From c1f406319342c3ba22d38a2f4b52a39457a7d7e8 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Tue, 14 Sep 2010 12:50:06 +0000 Subject: [PATCH] Centralized interpretation of SCSI command outcome --- cdrskin/cdrskin_timestamp.h | 2 +- libburn/sg-freebsd.c | 33 +++++++++++++-- libburn/sg-libcdio.c | 32 ++++++++++++--- libburn/sg-linux.c | 34 +++++++++++++++- libburn/sg-solaris.c | 37 ++++++++++++++++- libburn/spc.c | 80 +++++++++++++++++++++++++------------ libburn/spc.h | 18 +++++++++ 7 files changed, 198 insertions(+), 38 deletions(-) diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index f87d341..ef42ad9 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2010.08.21.095456" +#define Cdrskin_timestamP "2010.09.14.124934" diff --git a/libburn/sg-freebsd.c b/libburn/sg-freebsd.c index dc217ed..66d054e 100644 --- a/libburn/sg-freebsd.c +++ b/libburn/sg-freebsd.c @@ -759,13 +759,17 @@ int sg_release(struct burn_drive *d) int sg_issue_command(struct burn_drive *d, struct command *c) { - int done = 0, err, sense_len = 0, ret, ignore_error, no_retry = 0; - int cam_pass_err_recover = 0, key, asc, ascq; + int done = 0, err, sense_len = 0, ret, ignore_error, no_retry = 0, i; + int cam_pass_err_recover = 0, key, asc, ascq, timeout_ms; union ccb *ccb; char buf[161]; static FILE *fp = NULL; + time_t start_time; - snprintf(buf, sizeof (buf), "sg_issue_command d->cam=%p d->released=%d", +#define Libburn_use_scsi_eval_cmd_outcomE yes + + snprintf(buf, sizeof (buf), + "sg_issue_command d->cam=%p d->released=%d", (void*)d->cam, d->released); mmc_function_spy(NULL, buf); @@ -854,7 +858,9 @@ int sg_issue_command(struct burn_drive *d, struct command *c) ccb->csio.dxfer_len = 0; } - do { + start_time = time(NULL); + timeout_ms = 200000; + for (i = 0; !done; i++) { memset(c->sense, 0, sizeof(c->sense)); err = cam_send_ccb(d->cam, ccb); @@ -954,6 +960,17 @@ int sg_issue_command(struct burn_drive *d, struct command *c) c->sense[13] = 0x00; no_retry = 1; } + + +#ifdef Libburn_use_scsi_eval_cmd_outcomE + + done = scsi_eval_cmd_outcome(d, c, fp, c->sense, + sense_len, 0, start_time, + timeout_ms, i, + 2 | !!ignore_error); + +#else /* Libburn_use_scsi_eval_cmd_outcomE */ + if (no_retry || ignore_error || !c->retry) { c->error = 1; {ret = 1; goto ex;} @@ -983,12 +1000,18 @@ int sg_issue_command(struct burn_drive *d, struct command *c) 0, 1 | 2); {ret = 1; goto ex;} } + +#endif /* ! Libburn_use_scsi_eval_cmd_outcomE */ + } else { done = 1; } } while (!done); ret = 1; ex:; + +#ifndef Libburn_use_scsi_eval_cmd_outcomE + if (c->error) scsi_notify_error(d, c, c->sense, 18, 0); @@ -997,6 +1020,8 @@ ex:; scsi_log_err(c, fp, c->sense, sense_len > 0 ? sense_len : 18, 0, (c->error != 0) | 2); +#endif /* ! Libburn_use_scsi_eval_cmd_outcomE */ + cam_freeccb(ccb); return ret; } diff --git a/libburn/sg-libcdio.c b/libburn/sg-libcdio.c index aef211f..2928a7d 100644 --- a/libburn/sg-libcdio.c +++ b/libburn/sg-libcdio.c @@ -586,6 +586,9 @@ int sg_release(struct burn_drive *d) } +#define Libburn_use_scsi_eval_cmd_outcomE yes + + /** Sends a SCSI command to the drive, receives reply and evaluates wether the command succeeded or shall be retried or finally failed. Returned SCSI errors shall not lead to a return value indicating failure. @@ -597,8 +600,8 @@ int sg_release(struct burn_drive *d) */ int sg_issue_command(struct burn_drive *d, struct command *c) { - int sense_valid = 0, i, usleep_time, timeout_ms, no_retry = 0; - int key = 0, asc = 0, ascq = 0; + int sense_valid = 0, i, timeout_ms, no_retry = 0; + int key = 0, asc = 0, ascq = 0, done = 0; time_t start_time; driver_return_code_t i_status; unsigned int dxfer_len; @@ -608,6 +611,10 @@ int sg_issue_command(struct burn_drive *d, struct command *c) CdIo_t *p_cdio; unsigned char *sense_pt = NULL; +#ifndef Libburn_use_scsi_eval_cmd_outcomE + int usleep_time; +#endif + c->error = 0; if (d->p_cdio == NULL) { return 0; @@ -643,7 +650,7 @@ int sg_issue_command(struct burn_drive *d, struct command *c) /* retry-loop */ start_time = time(NULL); timeout_ms = 200000; - for(i = 0; ; i++) { + for(i = 0; !done; i++) { i_status = mmc_run_cmd(p_cdio, timeout_ms, &cdb, e_direction, dxfer_len, c->page->data); @@ -688,6 +695,14 @@ int sg_issue_command(struct burn_drive *d, struct command *c) } } if (i_status != 0 || (key || asc || ascq)) { + +#ifdef Libburn_use_scsi_eval_cmd_outcomE + + done = scsi_eval_cmd_outcome(d, c, fp, c->sense, 18, + 0, start_time, timeout_ms, i, 2); + +#else /* Libburn_use_scsi_eval_cmd_outcomE */ + if (no_retry || !c->retry) { c->error = 1; goto ex; @@ -724,17 +739,24 @@ int sg_issue_command(struct burn_drive *d, struct command *c) goto ex; } usleep(usleep_time); +#endif /* ! Libburn_use_scsi_eval_cmd_outcomE */ + } else - break; /* retry-loop */ + done = 1; + } /* end of retry-loop */ +#ifndef Libburn_use_scsi_eval_cmd_outcomE + ex:; if (c->error) scsi_notify_error(d, c, c->sense, 18, 0); - if (burn_sg_log_scsi & 3) /* >>> Need own duration time measurement. Then remove bit1 */ scsi_log_err(c, fp, c->sense, 18, 0, (c->error != 0) | 2); + +#endif /* ! Libburn_use_scsi_eval_cmd_outcomE */ + return 1; } diff --git a/libburn/sg-linux.c b/libburn/sg-linux.c index 6e6d4aa..3365ac4 100644 --- a/libburn/sg-linux.c +++ b/libburn/sg-linux.c @@ -1782,13 +1782,19 @@ int sg_release(struct burn_drive *d) */ int sg_issue_command(struct burn_drive *d, struct command *c) { - int done = 0, no_c_page = 0, usleep_time, i; + int done = 0, no_c_page = 0, i; int err; time_t start_time; sg_io_hdr_t s; /* ts A61030 */ static FILE *fp= NULL; +#define Libburn_use_scsi_eval_cmd_outcomE yes +#ifndef Libburn_use_scsi_eval_cmd_outcomE + int usleep_time; +#endif + + /* <<< ts A60821 debug: for tracing calls which might use open drive fds */ char buf[161]; @@ -1910,6 +1916,14 @@ if(0){ /* <<< */ #endif /* NIX */ + +#ifdef Libburn_use_scsi_eval_cmd_outcomE + + done = scsi_eval_cmd_outcome(d, c, fp, s.sbp, s.sb_len_wr, + s.duration, start_time, s.timeout, i, 0); + +#else /* Libburn_use_scsi_eval_cmd_outcomE */ + if (s.sb_len_wr) { if (!c->retry) { c->error = 1; @@ -1951,14 +1965,28 @@ if(0){ } else { done = 1; } + +#endif /* ! Libburn_use_scsi_eval_cmd_outcomE */ + } /* ts A61106 */ + +#ifdef Libburn_use_scsi_eval_cmd_outcomE + + if (s.host_status != Libburn_sg_host_oK || + (s.driver_status != Libburn_sg_driver_oK && !c->error)) { + +#else /* Libburn_use_scsi_eval_cmd_outcomE */ + ex:; if (c->error) { scsi_notify_error(d, c, s.sbp, s.sb_len_wr, 0); } else if (s.host_status != Libburn_sg_host_oK || s.driver_status != Libburn_sg_driver_oK) { + +#endif /* ! Libburn_use_scsi_eval_cmd_outcomE */ + char msg[161]; sprintf(msg, @@ -1973,9 +2001,13 @@ ex:; LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg, 0, 0); } + +#ifndef Libburn_use_scsi_eval_cmd_outcomE if (burn_sg_log_scsi & 3) scsi_log_err(c, fp, s.sbp, s.sb_len_wr, s.duration, c->error != 0); +#endif + return 1; } diff --git a/libburn/sg-solaris.c b/libburn/sg-solaris.c index 1867ca3..5d9ce67 100644 --- a/libburn/sg-solaris.c +++ b/libburn/sg-solaris.c @@ -565,12 +565,17 @@ int sg_release(struct burn_drive *d) */ int sg_issue_command(struct burn_drive *d, struct command *c) { - int i, usleep_time, timeout_ms, no_retry = 0, ret, key, asc, ascq; + int i, timeout_ms, ret, key, asc, ascq, done = 0; time_t start_time; struct uscsi_cmd cgc; char msg[80]; static FILE *fp = NULL; +#define Libburn_use_scsi_eval_cmd_outcomE yes +#ifndef Libburn_use_scsi_eval_cmd_outcomE + int usleep_time, no_retry = 0; +#endif + c->error = 0; memset(c->sense, 0, sizeof(c->sense)); if (d->fd == -1) @@ -616,7 +621,7 @@ int sg_issue_command(struct burn_drive *d, struct command *c) /* retry-loop */ start_time = time(NULL); timeout_ms = 200000; - for(i = 0; ; i++) { + for(i = 0; !done; i++) { ret = ioctl(d->fd, USCSICMD, &cgc); @@ -639,6 +644,25 @@ int sg_issue_command(struct burn_drive *d, struct command *c) return -1; } +#ifdef Libburn_use_scsi_eval_cmd_outcomE + + + /* >>> Should replace "18" by realistic sense length. + What's about following older remark ? + */ + /* >>> valid sense: cgc.uscsi_rqlen - cgc.uscsi_rqresid */; + + spc_decode_sense(c->sense, 0, &key, &asc, &ascq); + if (key || asc || ascq) { + done = scsi_eval_cmd_outcome(d, c, fp, c->sense, 18, 0, + start_time, timeout_ms, i, 2); + } else + done = 1; + + +#else /* Libburn_use_scsi_eval_cmd_outcomE */ + + /* >>> valid sense: cgc.uscsi_rqlen - cgc.uscsi_rqresid */; spc_decode_sense(c->sense, 0, &key, &asc, &ascq); @@ -681,15 +705,24 @@ int sg_issue_command(struct burn_drive *d, struct command *c) usleep(usleep_time); } else break; /* retry-loop */ + +#endif /* ! Libburn_use_scsi_eval_cmd_outcomE */ + } /* end of retry-loop */ +#ifndef Libburn_use_scsi_eval_cmd_outcomE + ex:; + if (c->error) scsi_notify_error(d, c, c->sense, 18, 0); if (burn_sg_log_scsi & 3) /* >>> Need own duration time measurement. Then remove bit1 */ scsi_log_err(c, fp, c->sense, 18, 0, (c->error != 0) | 2); + +#endif /* ! Libburn_use_scsi_eval_cmd_outcomE */ + return 1; } diff --git a/libburn/spc.c b/libburn/spc.c index 3d306de..0e85eca 100644 --- a/libburn/spc.c +++ b/libburn/spc.c @@ -1408,28 +1408,10 @@ int scsi_notify_error(struct burn_drive *d, struct command *c, sprintf(msg, "SCSI error condition on command %2.2Xh %s: ", c->opcode[0], scsi_command_name((unsigned int) c->opcode[0], 0)); - -#ifdef NIX - if (key>=0) - sprintf(msg+strlen(msg), " key=%Xh", key); - if (asc>=0) - sprintf(msg+strlen(msg), " asc=%2.2Xh", asc); - if (ascq>=0) - sprintf(msg+strlen(msg), " ascq=%2.2Xh", ascq); - ret = libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002010f, - LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg,0,0); - if (ret < 0) - return ret; - ret = libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002010f, - LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, - scsi_msg,0,0); -#else strcat(msg, scsi_msg); ret = libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002010f, LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg,0,0); -#endif /* NIX */ - return ret; } @@ -1530,13 +1512,6 @@ int scsi_log_err(struct command *c, void *fp_in, unsigned char sense[18], if (fp != NULL && (fp == stderr || (burn_sg_log_scsi & 1))) { if (flag & 1) { - durtxt[0] = 0; - if (!(flag & 2)) - sprintf(durtxt, " (%6d ms)", duration); - spc_decode_sense(sense, 0, &key, &asc, &ascq); - fprintf(fp, "+++ key=%X asc=%2.2Xh ascq=%2.2Xh%s\n", - (unsigned int) key, (unsigned int) asc, - (unsigned int) ascq, durtxt); l = 18; if ((sense[0] & 0x7f) == 0x72 || (sense[0] & 0x7f) == 0x73) @@ -1547,6 +1522,13 @@ int scsi_log_err(struct command *c, void *fp_in, unsigned char sense[18], for (i = 0 ; i < l; i++) fprintf(fp, " %2.2X", sense[i]); fprintf(fp, "\n"); + durtxt[0] = 0; + if (!(flag & 2)) + sprintf(durtxt, " (%6d ms)", duration); + spc_decode_sense(sense, 0, &key, &asc, &ascq); + fprintf(fp, "+++ key=%X asc=%2.2Xh ascq=%2.2Xh%s\n", + (unsigned int) key, (unsigned int) asc, + (unsigned int) ascq, durtxt); } else { scsi_show_cmd_reply(c, fp, 0); if (!(flag & 2)) @@ -1561,3 +1543,51 @@ int scsi_log_err(struct command *c, void *fp_in, unsigned char sense[18], return 1; } + +/* ts B00808 */ +/* + @param flag bit0 = do not retry + bit1 = do not print duration + @return 0 = not yet done , 1 = done , -1 = error +*/ +int scsi_eval_cmd_outcome(struct burn_drive *d, struct command *c, void *fp, + unsigned char *sense, int sense_len, + int duration, time_t start_time, int timeout_ms, + int loop_count, int flag) +{ + enum response outcome; + int done = -1, usleep_time; + + if (sense_len <= 0) + return 1; + + if (burn_sg_log_scsi & 3) + scsi_log_err(c, fp, sense, sense_len, duration, + 1 | (flag & 2)); + outcome = scsi_error(d, sense, sense_len); + if (outcome == RETRY && c->retry && !(flag & 1)) { + /* Calming down retries and breaking up endless cycle + */ + usleep_time = Libburn_scsi_retry_usleeP + + loop_count * Libburn_scsi_retry_incR; + if (time(NULL) + usleep_time / 1000000 - start_time > + timeout_ms / 1000 + 1) { + done = 1; + goto ex; + } + usleep(usleep_time); + if (burn_sg_log_scsi & 3) + scsi_log_cmd(c, fp, 0); + return 0; + } else if (outcome == RETRY) { + done = 1; + } else if (outcome == GO_ON) { + return 1; + } else if (outcome == FAIL) { + done = 1; + } +ex:; + c->error = 1; + scsi_notify_error(d, c, sense, sense_len, 0); + return done; +} diff --git a/libburn/spc.h b/libburn/spc.h index bf07ed1..423b7fb 100644 --- a/libburn/spc.h +++ b/libburn/spc.h @@ -84,5 +84,23 @@ int scsi_log_err(struct command *c, void *fp, unsigned char sense[18], int spc_decode_sense(unsigned char *sense, int senselen, int *key, int *asc, int *ascq); +/* ts B00808 */ +/** Evaluates outcome of a single SCSI command, eventually logs sense data, + and issues DEBUG error message in case the command is evaluated as done. + @param flag bit1 = do not print duration + @return 0 = not yet done , 1 = done , -1 = error +*/ +int scsi_eval_cmd_outcome(struct burn_drive *d, struct command *c, void *fp_in, + unsigned char *sense, int sense_len, + int duration, time_t start_time, int timeout_ms, + int loop_count, int flag); + +/* The waiting time before eventually retrying a failed SCSI command. + Before each retry wait Libburn_scsi_retry_incR longer than with + the previous one. +*/ +#define Libburn_scsi_retry_usleeP 100000 +#define Libburn_scsi_retry_incR 100000 + #endif /*__SPC*/