diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index 43cb287..09f4367 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2009.12.19.142456" +#define Cdrskin_timestamP "2009.12.24.170601" diff --git a/configure.ac b/configure.ac index 7d104b7..1e090ba 100644 --- a/configure.ac +++ b/configure.ac @@ -217,13 +217,16 @@ dnl Check whether there is libcdio-devel and libcdio-runtime. dnl If not, erase this macro LIBCDIO_DEF="-DLibburn_use_libcdiO" dnl The empty yes case obviously causes -lacl to be linked - AC_CHECK_HEADER(cdio/cdio.h, AC_CHECK_LIB(cdio, cdio_open, , LIBCDIO_DEF= ), LIBCDIO_DEF= ) + AC_CHECK_HEADER(cdio/cdio.h, AC_CHECK_LIB(cdio, mmc_last_cmd_sense, , LIBCDIO_DEF= ), LIBCDIO_DEF= ) else LIBCDIO_DEF= fi if test x$LIBCDIO_DEF = x then - LIBCDIO_DEF= + if test x$enable_libcdio = xyes + then + echo "WARNING: could not enable use of libcdio as system adapter" + fi else echo "enabled EXPERIMENTAL use of libcdio as system adapter" CFLAGS="$CFLAGS $LIBCDIO_DEF" diff --git a/libburn/sg-libcdio.c b/libburn/sg-libcdio.c index ba767cb..3a2ebef 100644 --- a/libburn/sg-libcdio.c +++ b/libburn/sg-libcdio.c @@ -87,6 +87,14 @@ Send feedback to libburn-hackers@pykix.org . #include +/* The waiting time before eventually retrying a failed SCSI command. + Before each retry wait Libburn_sg_linux_retry_incR longer than with + the previous one. +*/ +#define Libburn_sg_libcdio_retry_usleeP 100000 +#define Libburn_sg_libcdio_retry_incR 100000 + + /** PORTING : ------ libburn portable headers and definitions ----- */ #include "transport.h" @@ -117,6 +125,18 @@ int burn_drive_is_banned(char *device_address); extern int burn_sg_log_scsi; +/* ------------------------------------------------------------------------ */ +/* PORTING: Private definitions. Port only if needed by public functions. */ +/* (Public functions are listed below) */ +/* ------------------------------------------------------------------------ */ + + +/* Storage object is in libburn/init.c + whether to strive for exclusive access to the drive +*/ +extern int burn_sg_open_o_excl; + + /* ------------------------------------------------------------------------ */ /* PORTING: Private functions. Port only if needed by public functions */ /* (Public functions are listed below) */ @@ -232,7 +252,8 @@ int sg_give_next_adr(burn_drive_enumerator_t *idx, int scsi_enumerate_drives(void) { burn_drive_enumerator_t idx; - int initialize = 1, ret; + int initialize = 1, ret, i_bus_no = -1; + int i_host_no = -1, i_channel_no = -1, i_target_no = -1, i_lun_no = -1; char buf[64]; while(1) { @@ -242,10 +263,10 @@ int scsi_enumerate_drives(void) break; if (burn_drive_is_banned(buf)) continue; - - /* >>> try to obtain bus,host,channel,target,lun */; - - enumerate_common(buf, -1, -1, -1, -1, -1); + sg_obtain_scsi_adr(buf, &i_bus_no, &i_host_no, + &i_channel_no, &i_target_no, &i_lun_no); + enumerate_common(buf, i_bus_no, i_host_no, i_channel_no, + i_target_no, i_lun_no); } sg_give_next_adr(&idx, buf, sizeof(buf), -1); return 1; @@ -272,12 +293,44 @@ int sg_drive_is_open(struct burn_drive * d) int sg_grab(struct burn_drive *d) { CdIo_t *p_cdio; + char *am, *version_text; + char msg[160]; + int cdio_ver = 82; - if(d->p_cdio != NULL) { + if (d->p_cdio != NULL) { d->released = 0; return 1; } - p_cdio = cdio_open(d->devname, DRIVER_DEVICE); + + sprintf(msg, "Using sg-libcdio-%d with libcdio version ", + LIBCDIO_VERSION_NUM ); + +/* >>> change this to #if LIBCDIO_VERSION_NUM < 83 */ +#ifdef LIBCDIO_HAS_VERSION_CALL + cdio_ver = cdio_version(&version_text); +#else +LIBBURN_MISCONFIGURATION = 0; +INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_cdio_version_dot_h_TOO_OLD__NEED_LIBCDIO_HAS_VERSION_CALL = 0; +LIBBURN_MISCONFIGURATION_ = 0; +#endif /* ! LIBCDIO_HAS_VERSION_CALL */ + + strncat(msg, version_text, 80); + libdax_msgs_submit(libdax_messenger, -1, 0x00000002, + LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, + msg , 0, 0); + if (cdio_ver < LIBCDIO_VERSION_NUM) { + sprintf(msg, + "libcdio TOO OLD: numeric version %d , need at least %d", + cdio_ver, LIBCDIO_VERSION_NUM); + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020003, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + msg, 0, 0); + return 0; + } + + p_cdio = cdio_open_am(d->devname, DRIVER_DEVICE, + burn_sg_open_o_excl ? "MMC_RDWR_EXCL" : "MMC_RDWR"); if (p_cdio == NULL) { libdax_msgs_submit(libdax_messenger, d->global_index, @@ -286,6 +339,16 @@ int sg_grab(struct burn_drive *d) "Could not grab drive", 0/*os_errno*/, 0); return 0; } + am = (char *) cdio_get_arg(p_cdio, "access-mode"); + if (strncmp(am, "MMC_RDWR", 8) != 0) { + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020003, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + "libcdio provides no MMC_RDWR access mode", 0, 0); + cdio_destroy(p_cdio); + return 0; + } + d->p_cdio = p_cdio; d->released = 0; return 1; @@ -320,13 +383,15 @@ int sg_release(struct burn_drive *d) */ int sg_issue_command(struct burn_drive *d, struct command *c) { - int i_status; + int sense_valid = 0, i, usleep_time, timeout_ms; + time_t start_time; + driver_return_code_t i_status; unsigned int dxfer_len; static FILE *fp = NULL; mmc_cdb_t cdb = {{0, }}; cdio_mmc_direction_t e_direction; CdIo_t *p_cdio; - char msg[160]; + unsigned char sense[18], *sense_pt = NULL; c->error = 0; if (d->p_cdio == NULL) { @@ -357,31 +422,35 @@ int sg_issue_command(struct burn_drive *d, struct command *c) memset(c->page->data, 0, BUFFER_SIZE); } else { dxfer_len = 0; + +/* >>> remove this condition when #if LIBCDIO_VERSION_NUM < 83 + is in effect above*/ #ifdef SCSI_MMC_HAS_DIR_NONE e_direction = SCSI_MMC_DATA_NONE; #else e_direction = SCSI_MMC_DATA_READ; #endif + } - /* >>> longer timeout , sg-linux has 200 s */ + /* retry-loop */ + start_time = time(NULL); + timeout_ms = 200000; + for(i = 0; ; i++) { - /* >>> retry-loop */ - - i_status = mmc_run_cmd(p_cdio, 10000, &cdb, e_direction, + i_status = mmc_run_cmd(p_cdio, timeout_ms, &cdb, e_direction, dxfer_len, c->page->data); - - if (i_status == 0) - return 1; + sense_valid = mmc_last_cmd_sense(p_cdio, &sense_pt); + if (sense_valid >= 18) + memcpy(sense, sense_pt, 18); + if (sense_pt != NULL) + free(sense_pt); - /* >>> One would need to get info about the nature of failure - SCSI SK,ASC,ASCQ would be nice. - One would need to distinguish between drive error and - transport error. - */; - -/* This is for failure of the transport mechanism itself: +/* Regrettably mmc_run_cmd() does not clearly distinguish between transport + failure and SCSI error reply. + This reaction here would be for transport failure: + if (i_status != 0 && i_status != DRIVER_OP_ERROR) { libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002010c, LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, @@ -390,27 +459,56 @@ int sg_issue_command(struct burn_drive *d, struct command *c) sg_close_drive(d); d->released = 1; d->busy = BURN_DRIVE_IDLE; + c->error = 1; + return -1; + } */ - /* >>> end retry-loop */ + if (!sense_valid) { + memset(sense, 0, 18); + if (i_status != 0) { /* set dummy sense */ + /*LOGICAL UNIT NOT READY,CAUSE NOT REPORTABLE*/ + sense[2] = 0x02; + sense[12] = 0x04; + } + } else + sense[2] &= 15; + + if (i_status != 0 || (sense[2] || sense[12] || sense[13])) { + if (!c->retry) { + c->error = 1; + goto ex; + } + switch (scsi_error(d, sense, 18)) { + case RETRY: + break; + case FAIL: + c->error = 1; + goto ex; + } + /* + Calming down retries and breaking up endless cycle + */ + usleep_time = Libburn_sg_libcdio_retry_usleeP + + i * Libburn_sg_libcdio_retry_incR; + if (time(NULL) + usleep_time / 1000000 - start_time > + timeout_ms / 1000 + 1) { + c->error = 1; + goto ex; + } + usleep(usleep_time); + } else + break; /* retry-loop */ + } /* end of retry-loop */ +ex:; + if (c->error) + scsi_notify_error(d, c, sense, 18, 0); - if (c->opcode[0] != 0x00) { - sprintf(msg, "SCSI command %2.2Xh failed", - (unsigned int) c->opcode[0]); - libdax_msgs_submit(libdax_messenger, - d->global_index, 0x0002010f, - LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, - msg, errno, 0); - } - - /* 2 04 00 LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE */ - c->sense[2] = 0x02; - c->sense[12] = 0x04; - c->sense[13] = 0x00; - - c->error = 1; - return -1; + if (burn_sg_log_scsi & 3) + /* >>> Need own duration time measurement. Then remove bit1 */ + scsi_log_err(c, fp, sense, 0, (c->error != 0) | 2); + return 1; } diff --git a/libburn/sg-linux.c b/libburn/sg-linux.c index fd13ab5..c99b726 100644 --- a/libburn/sg-linux.c +++ b/libburn/sg-linux.c @@ -1679,6 +1679,9 @@ int sg_release(struct burn_drive *d) } +#ifdef NIX +/* <<< now in spc.c as scsi_log_err */ + /** logs outcome of a sg command. flag&1 causes an error message */ static int sg_log_err(struct command *c, FILE *fp, sg_io_hdr_t *s, @@ -1698,10 +1701,13 @@ static int sg_log_err(struct command *c, FILE *fp, } if (fp == stderr || !(burn_sg_log_scsi & 2)) return 1; + sg_log_err(c, stderr, s, flag); return 1; } +#endif /* NIX */ + /** Sends a SCSI command to the drive, receives reply and evaluates wether the command succeeded or shall be retried or finally failed. @@ -1876,7 +1882,8 @@ ex:; msg, 0, 0); } if (burn_sg_log_scsi & 3) - sg_log_err(c, fp, &s, c->error != 0); + /* <<< sg_log_err(c, fp, &s, c->error != 0); */ + scsi_log_err(c, fp, s.sbp, s.duration, c->error != 0); return 1; } diff --git a/libburn/spc.c b/libburn/spc.c index 6cd8501..3e7b97f 100644 --- a/libburn/spc.c +++ b/libburn/spc.c @@ -1438,3 +1438,37 @@ int scsi_log_cmd(struct command *c, void *fp_in, int flag) return 1; } + +/* ts A91221 (former sg_log_err ts A91108) */ +/** Logs outcome of a sg command. + @param flag bit0 causes an error message + bit1 do not print duration +*/ +int scsi_log_err(struct command *c, void *fp_in, unsigned char sense[18], + int duration, int flag) +{ + char durtxt[20]; + FILE *fp = fp_in; + + if(fp != NULL && (fp == stderr || (burn_sg_log_scsi & 1))) { + if(flag & 1) { + durtxt[0] = 0; + if (!(flag & 2)) + sprintf(durtxt, " (%6d ms)\n",duration); + fprintf(fp, "+++ key=%X asc=%2.2Xh ascq=%2.2Xh%s\n", + sense[2], sense[12], sense[13], durtxt); + + } else { + scsi_show_cmd_reply(c, fp, 0); + if (!(flag & 2)) + fprintf(fp,"%6d ms\n", duration); + } + if (burn_sg_log_scsi & 4) + fflush(fp); + } + if (fp == stderr || !(burn_sg_log_scsi & 2)) + return 1; + scsi_log_err(c, stderr, sense, duration, flag); + return 1; +} + diff --git a/libburn/spc.h b/libburn/spc.h index ed1b5b4..3c22946 100644 --- a/libburn/spc.h +++ b/libburn/spc.h @@ -69,5 +69,10 @@ int scsi_show_cmd_reply(struct command *c, void *fp, int flag); /** Logs command (before execution) */ int scsi_log_cmd(struct command *c, void *fp, int flag); +/* ts A91221 (former sg_log_err ts A91108) */ +/** Logs outcome of a sg command. */ +int scsi_log_err(struct command *c, void *fp, unsigned char sense[18], + int duration, int flag); + #endif /*__SPC*/