Improved reaction on Linux SG_IO transport problems

This commit is contained in:
Thomas Schmitt 2013-11-14 10:17:48 +00:00
parent 0cd21eed54
commit 404f239207
5 changed files with 207 additions and 23 deletions

View File

@ -1 +1 @@
#define Cdrskin_timestamP "2013.11.11.160915" #define Cdrskin_timestamP "2013.11.14.101636"

View File

@ -520,7 +520,7 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
0x0002014a (SORRY,HIGH) = Cannot read desired amount of data 0x0002014a (SORRY,HIGH) = Cannot read desired amount of data
0x0002014b (SORRY,HIGH) = Drive is already registered resp. scanned 0x0002014b (SORRY,HIGH) = Drive is already registered resp. scanned
0x0002014c (FATAL,HIGH) = Emulated drive caught in SCSI function 0x0002014c (FATAL,HIGH) = Emulated drive caught in SCSI function
0x0002014d (SORRY,HIGH) = Asynchromous SCSI error 0x0002014d (SORRY,HIGH) = Asynchronous SCSI error
0x0002014f (SORRY,HIGH) = Timeout with asynchronous SCSI command 0x0002014f (SORRY,HIGH) = Timeout with asynchronous SCSI command
0x00020150 (DEBUG,LOW) = Reporting asynchronous waiting time 0x00020150 (DEBUG,LOW) = Reporting asynchronous waiting time
0x00020151 (FAILURE,HIGH) = Read attempt on write-only drive 0x00020151 (FAILURE,HIGH) = Read attempt on write-only drive
@ -606,6 +606,10 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
0x000201a2 (FAILURE,HIGH) = Error while writing to disk file 0x000201a2 (FAILURE,HIGH) = Error while writing to disk file
0x000201a3 (UPDATE,HIGH) = Progress message of burn_drive_extract_audio() 0x000201a3 (UPDATE,HIGH) = Progress message of burn_drive_extract_audio()
0x000201a4 (FAILURE,HIGH) = Failure to read audio sectors 0x000201a4 (FAILURE,HIGH) = Failure to read audio sectors
0x000201a5 (FAILURE,HIGH) = Asynchronous SCSI error
0x000201a6 (FATAL,HIGH) = Lost connection to drive
0x000201a7 (FAILURE,HIGH) = SCSI command yielded host problem
0x000201a8 (FAILURE,HIGH) = SCSI command yielded driver problem
libdax_audioxtr: libdax_audioxtr:

View File

@ -1884,6 +1884,167 @@ int sg_release(struct burn_drive *d)
return 0; return 0;
} }
/* @return -1= transport failed, give up drive
0= transport failed, do not retry
1= transport succeeded
2- transport failed, please retry
*/
static int evaluate_transport_success(struct burn_drive *d, struct command *c,
FILE *fp,
unsigned short host_status,
unsigned short driver_status)
{
int ret, do_retry= 0, give_up_drive= 0;
char *msg = NULL, *host_problem, *driver_problem, *driver_sugg;
BURN_ALLOC_MEM(msg, char, 161);
if ((host_status == Libburn_sg_host_oK &&
driver_status == Libburn_sg_driver_oK) || c->error)
{ret = 1; goto ex;} /* No transport problems */
/* See http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/x291.html */
switch(host_status) {
case 0x00:
host_problem =
"SG_ERR_DID_OK (No error)";
break; case 0x01:
host_problem =
"SG_ERR_DID_NO_CONNECT (Could not connect before timeout period)";
give_up_drive= 1;
break; case 0x02:
host_problem =
"SG_ERR_DID_BUS_BUSY (Bus stayed busy through time out period)";
break; case 0x03:
host_problem =
"SG_ERR_DID_TIME_OUT (Timed out for miscellaneous reasons)";
break; case 0x04:
host_problem =
"SG_ERR_DID_BAD_TARGET (Bad target, device not responding ?)";
give_up_drive= 1;
break; case 0x05:
host_problem =
"SG_ERR_DID_ABORT (Told to abort)";
break; case 0x06:
host_problem =
"SG_ERR_DID_PARITY (Parity error)";
break; case 0x07:
host_problem =
"SG_ERR_DID_ERROR (Internal error detected in the host adapter)";
give_up_drive= 1;
break; case 0x08:
host_problem =
"SG_ERR_DID_RESET (The SCSI bus or the device have been reset)";
give_up_drive= 1;
break; case 0x09:
host_problem =
"SG_ERR_DID_BAD_INTR (Got an unexpected interrupt)";
break; case 0x0a:
host_problem =
"SG_ERR_DID_PASSTHROUGH (Force command past mid-layer)";
break; case 0x0b:
host_problem =
"SG_ERR_DID_SOFT_ERROR (The low level driver wants a retry)";
do_retry = 1;
default:
host_problem =
"? (unknown host_status code)";
}
if (host_status != Libburn_sg_host_oK) {
sprintf(msg, "SCSI command %2.2Xh yielded host problem: ",
(unsigned int) c->opcode[0]);
sprintf(msg+strlen(msg), "0x%x %s",
(unsigned int) host_status, host_problem);
libdax_msgs_submit(libdax_messenger, d->global_index,
0x000201a7,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
sprintf(msg, "--- SG_IO: host_status= 0x%x %s",
(unsigned int) host_status, host_problem);
scsi_log_message(d, fp, msg, 0);
}
switch (driver_status & 0x0f) {
case 0:
driver_problem = "SG_ERR_DRIVER_OK";
break; case 1:
driver_problem = "SG_ERR_DRIVER_BUSY";
break; case 2:
driver_problem = "SG_ERR_DRIVER_SOFT";
break; case 3:
driver_problem = "SG_ERR_DRIVER_MEDIA";
break; case 4:
driver_problem = "SG_ERR_DRIVER_ERROR";
break; case 5:
driver_problem = "SG_ERR_DRIVER_INVALID";
break; case 6:
driver_problem = "SG_ERR_DRIVER_TIMEOUT";
break; case 7:
driver_problem = "SG_ERR_DRIVER_HARD";
break; case 8:
driver_problem = "SG_ERR_DRIVER_SENSE";
default:
driver_problem = "(unknown driver_status code)";
}
switch (driver_status & 0xf0) {
case 0:
driver_sugg = "(no suggestion)";
break; case 0x10:
driver_sugg = "SG_ERR_SUGGEST_RETRY";
do_retry = 1;
break; case 0x20:
driver_sugg = "SG_ERR_SUGGEST_ABORT";
give_up_drive= 1;
break; case 0x30:
driver_sugg = "SG_ERR_SUGGEST_REMAP";
give_up_drive= 1;
break; case 0x40:
driver_sugg = "SG_ERR_SUGGEST_DIE";
give_up_drive= 1;
break; case 0x80:
driver_sugg = "SG_ERR_SUGGEST_SENSE";
default:
driver_sugg = "(unknown driver_status suggestion)";
}
if (driver_status != Libburn_sg_driver_oK) {
sprintf(msg, "SCSI command %2.2Xh yielded driver problem: ",
(unsigned int) c->opcode[0]);
sprintf(msg+strlen(msg), "driver_status= 0x%x %s / %s",
(unsigned int) driver_status,
driver_problem, driver_sugg);
libdax_msgs_submit(libdax_messenger, d->global_index,
0x000201a8,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
sprintf(msg, "--- SG_IO: driver_status= 0x%x %s / %s",
(unsigned int) driver_status,
driver_problem, driver_sugg);
scsi_log_message(d, fp, msg, 0);
}
if (! do_retry)
c->error = 1;
ret = give_up_drive ? -1 : do_retry ? 2 : 0;
ex:;
BURN_FREE_MEM(msg);
return ret;
}
static void react_on_drive_loss(struct burn_drive *d, struct command *c,
FILE *fp)
{
sg_close_drive(d);
d->released = 1;
d->busy = BURN_DRIVE_IDLE;
d->cancel = 1;
c->error = 1;
libdax_msgs_submit(libdax_messenger,
d->global_index, 0x000201a6,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Lost connection to drive", 0, 0);
scsi_log_message(d, fp, "--- SG_IO: Gave up connection to drive", 0);
}
/** Sends a SCSI command to the drive, receives reply and evaluates wether /** Sends a SCSI command to the drive, receives reply and evaluates wether
the command succeeded or shall be retried or finally failed. the command succeeded or shall be retried or finally failed.
@ -1923,8 +2084,6 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
"\n-----------------------------------------\n"); "\n-----------------------------------------\n");
} }
} }
if (burn_sg_log_scsi & 3)
scsi_log_cmd(c,fp,0);
/* ts A61010 : with no fd there is no chance to send an ioctl */ /* ts A61010 : with no fd there is no chance to send an ioctl */
if (d->fd < 0) { if (d->fd < 0) {
@ -1932,8 +2091,11 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
{ret = 0; goto ex;} {ret = 0; goto ex;}
} }
c->error = 0; c->error = 0;
memset(&s, 0, sizeof(sg_io_hdr_t)); memset(&s, 0, sizeof(sg_io_hdr_t));
if (burn_sg_log_scsi & 3)
scsi_log_cmd(c,fp,0);
s.interface_id = 'S'; s.interface_id = 'S';
@ -2012,32 +2174,31 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Failed to transfer command to drive", "Failed to transfer command to drive",
errno, 0); errno, 0);
sg_close_drive(d); sprintf(msg, "--- SG_IO: return= -1 , ");
d->released = 1; sprintf(msg + strlen(msg), "errno= %d , ", errno);
d->busy = BURN_DRIVE_IDLE; sprintf(msg + strlen(msg),
c->error = 1; "host_status= 0x%x , driver_status= 0x%x",
(unsigned int) s.host_status,
(unsigned int) s.driver_status);
scsi_log_message(d, fp, msg, 0);
react_on_drive_loss(d, c, fp);
{ret = -1; goto ex;} {ret = -1; goto ex;}
} }
done = scsi_eval_cmd_outcome(d, c, fp, s.sbp, s.sb_len_wr, done = scsi_eval_cmd_outcome(d, c, fp, s.sbp, s.sb_len_wr,
start_time, s.timeout, i, 0); start_time, s.timeout, i, 0);
if (d->cancel) if (d->cancel)
done = 1; break;
ret = evaluate_transport_success(d, c, fp,
s.host_status, s.driver_status);
if (ret == -1)
react_on_drive_loss(d, c, fp);
if (ret <= 0)
{ret = -1; goto ex;}
if (ret != 2 || d->cancel)
break;
/* loop for retry */;
} }
if (s.host_status != Libburn_sg_host_oK ||
(s.driver_status != Libburn_sg_driver_oK && !c->error)) {
sprintf(msg,
"SCSI command %2.2Xh indicates host or driver error:",
(unsigned int) c->opcode[0]);
sprintf(msg+strlen(msg),
" host_status= %xh , driver_status= %xh",
(unsigned int) s.host_status,
(unsigned int) s.driver_status);
libdax_msgs_submit(libdax_messenger, d->global_index,
0x0002013b,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
}
ret = 1; ret = 1;
ex:; ex:;
BURN_FREE_MEM(msg); BURN_FREE_MEM(msg);

View File

@ -1747,6 +1747,22 @@ int scsi_log_err(struct burn_drive *d, struct command *c,
return ret; return ret;
} }
/* ts B31112 */
int scsi_log_message(struct burn_drive *d, void *fp_in, char * msg, int flag)
{
int ret;
FILE *fp = fp_in;
if (fp != NULL && (fp == stderr || (burn_sg_log_scsi & 1))) {
fprintf(fp, "%s\n", msg);
if (burn_sg_log_scsi & 4)
fflush(fp);
}
if (fp == stderr || !(burn_sg_log_scsi & 2))
return 1;
ret = scsi_log_message(d, stderr, msg, flag);
return ret;
}
/* ts B00808 */ /* ts B00808 */
/* /*

View File

@ -98,6 +98,9 @@ int scsi_log_err(struct burn_drive *d, struct command *c,
void *fp, unsigned char sense[18], void *fp, unsigned char sense[18],
int sense_len, int flag); int sense_len, int flag);
/* ts B31112 */
int scsi_log_message(struct burn_drive *d, void *fp, char * msg, int flag);
/* ts B00728 */ /* ts B00728 */
int spc_decode_sense(unsigned char *sense, int senselen, int spc_decode_sense(unsigned char *sense, int senselen,
int *key, int *asc, int *ascq); int *key, int *asc, int *ascq);