Making use of libcdio function mmc_get_cmd_scsi_sense()

This commit is contained in:
Thomas Schmitt 2009-12-24 17:04:40 +00:00
parent 11a2094f97
commit 2947dc02de
6 changed files with 191 additions and 44 deletions

View File

@ -1 +1 @@
#define Cdrskin_timestamP "2009.12.19.142456" #define Cdrskin_timestamP "2009.12.24.170601"

View File

@ -217,13 +217,16 @@ dnl Check whether there is libcdio-devel and libcdio-runtime.
dnl If not, erase this macro dnl If not, erase this macro
LIBCDIO_DEF="-DLibburn_use_libcdiO" LIBCDIO_DEF="-DLibburn_use_libcdiO"
dnl The empty yes case obviously causes -lacl to be linked 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 else
LIBCDIO_DEF= LIBCDIO_DEF=
fi fi
if test x$LIBCDIO_DEF = x if test x$LIBCDIO_DEF = x
then then
LIBCDIO_DEF= if test x$enable_libcdio = xyes
then
echo "WARNING: could not enable use of libcdio as system adapter"
fi
else else
echo "enabled EXPERIMENTAL use of libcdio as system adapter" echo "enabled EXPERIMENTAL use of libcdio as system adapter"
CFLAGS="$CFLAGS $LIBCDIO_DEF" CFLAGS="$CFLAGS $LIBCDIO_DEF"

View File

@ -87,6 +87,14 @@ Send feedback to libburn-hackers@pykix.org .
#include <cdio/mmc.h> #include <cdio/mmc.h>
/* 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 ----- */ /** PORTING : ------ libburn portable headers and definitions ----- */
#include "transport.h" #include "transport.h"
@ -117,6 +125,18 @@ int burn_drive_is_banned(char *device_address);
extern int burn_sg_log_scsi; 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 */ /* PORTING: Private functions. Port only if needed by public functions */
/* (Public functions are listed below) */ /* (Public functions are listed below) */
@ -232,7 +252,8 @@ int sg_give_next_adr(burn_drive_enumerator_t *idx,
int scsi_enumerate_drives(void) int scsi_enumerate_drives(void)
{ {
burn_drive_enumerator_t idx; 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]; char buf[64];
while(1) { while(1) {
@ -242,10 +263,10 @@ int scsi_enumerate_drives(void)
break; break;
if (burn_drive_is_banned(buf)) if (burn_drive_is_banned(buf))
continue; continue;
sg_obtain_scsi_adr(buf, &i_bus_no, &i_host_no,
/* >>> try to obtain bus,host,channel,target,lun */; &i_channel_no, &i_target_no, &i_lun_no);
enumerate_common(buf, i_bus_no, i_host_no, i_channel_no,
enumerate_common(buf, -1, -1, -1, -1, -1); i_target_no, i_lun_no);
} }
sg_give_next_adr(&idx, buf, sizeof(buf), -1); sg_give_next_adr(&idx, buf, sizeof(buf), -1);
return 1; return 1;
@ -272,12 +293,44 @@ int sg_drive_is_open(struct burn_drive * d)
int sg_grab(struct burn_drive *d) int sg_grab(struct burn_drive *d)
{ {
CdIo_t *p_cdio; 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; d->released = 0;
return 1; 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) { if (p_cdio == NULL) {
libdax_msgs_submit(libdax_messenger, d->global_index, 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); "Could not grab drive", 0/*os_errno*/, 0);
return 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->p_cdio = p_cdio;
d->released = 0; d->released = 0;
return 1; 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 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; unsigned int dxfer_len;
static FILE *fp = NULL; static FILE *fp = NULL;
mmc_cdb_t cdb = {{0, }}; mmc_cdb_t cdb = {{0, }};
cdio_mmc_direction_t e_direction; cdio_mmc_direction_t e_direction;
CdIo_t *p_cdio; CdIo_t *p_cdio;
char msg[160]; unsigned char sense[18], *sense_pt = NULL;
c->error = 0; c->error = 0;
if (d->p_cdio == NULL) { 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); memset(c->page->data, 0, BUFFER_SIZE);
} else { } else {
dxfer_len = 0; dxfer_len = 0;
/* >>> remove this condition when #if LIBCDIO_VERSION_NUM < 83
is in effect above*/
#ifdef SCSI_MMC_HAS_DIR_NONE #ifdef SCSI_MMC_HAS_DIR_NONE
e_direction = SCSI_MMC_DATA_NONE; e_direction = SCSI_MMC_DATA_NONE;
#else #else
e_direction = SCSI_MMC_DATA_READ; e_direction = SCSI_MMC_DATA_READ;
#endif #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, timeout_ms, &cdb, e_direction,
i_status = mmc_run_cmd(p_cdio, 10000, &cdb, e_direction,
dxfer_len, c->page->data); dxfer_len, c->page->data);
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);
if (i_status == 0) /* Regrettably mmc_run_cmd() does not clearly distinguish between transport
return 1; failure and SCSI error reply.
This reaction here would be for transport failure:
/* >>> 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:
if (i_status != 0 && i_status != DRIVER_OP_ERROR) {
libdax_msgs_submit(libdax_messenger, libdax_msgs_submit(libdax_messenger,
d->global_index, 0x0002010c, d->global_index, 0x0002010c,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, 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); sg_close_drive(d);
d->released = 1; d->released = 1;
d->busy = BURN_DRIVE_IDLE; d->busy = BURN_DRIVE_IDLE;
*/
/* >>> end retry-loop */
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; c->error = 1;
return -1; return -1;
}
*/
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 (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;
} }

View File

@ -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 */ /** logs outcome of a sg command. flag&1 causes an error message */
static int sg_log_err(struct command *c, FILE *fp, static int sg_log_err(struct command *c, FILE *fp,
sg_io_hdr_t *s, 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)) if (fp == stderr || !(burn_sg_log_scsi & 2))
return 1; return 1;
sg_log_err(c, stderr, s, flag); sg_log_err(c, stderr, s, flag);
return 1; return 1;
} }
#endif /* NIX */
/** 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.
@ -1876,7 +1882,8 @@ ex:;
msg, 0, 0); msg, 0, 0);
} }
if (burn_sg_log_scsi & 3) 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; return 1;
} }

View File

@ -1438,3 +1438,37 @@ int scsi_log_cmd(struct command *c, void *fp_in, int flag)
return 1; 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;
}

View File

@ -69,5 +69,10 @@ int scsi_show_cmd_reply(struct command *c, void *fp, int flag);
/** Logs command (before execution) */ /** Logs command (before execution) */
int scsi_log_cmd(struct command *c, void *fp, int flag); 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*/ #endif /*__SPC*/