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 dd85e37ac8
commit eb34561262
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
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"

View File

@ -87,6 +87,14 @@ Send feedback to libburn-hackers@pykix.org .
#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 ----- */
#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) {
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);
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)
return 1;
/* >>> 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,28 +459,57 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
sg_close_drive(d);
d->released = 1;
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;
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;
}
/** Tries to obtain SCSI address parameters.

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 */
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;
}

View File

@ -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;
}

View File

@ -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*/