mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-13 14:40:22 +00:00
Automatically detect devices that do not support READ(6)/WRITE(6)
and upgrade to using 10 byte cdbs. As far as I tested, this works efficiently for most of the SBP-II/Firewire devices but most of the umass devices still need ad-hoc work around because umass-sim doesn't return any SCSI errors. A sysctl nob is also added for the last resort. I hope we don't need DA_Q_NO_6_BYTE quirks anymore. Reviewed by: gibbs MFC after: 1 week
This commit is contained in:
parent
327e1e773f
commit
5cdf02dbe0
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=93038
@ -416,6 +416,7 @@ static void dashutdown(void *arg, int howto);
|
||||
|
||||
static int da_retry_count = DA_DEFAULT_RETRY;
|
||||
static int da_default_timeout = DA_DEFAULT_TIMEOUT;
|
||||
static int da_no_6_byte = 0;
|
||||
|
||||
SYSCTL_NODE(_kern_cam, OID_AUTO, da, CTLFLAG_RD, 0,
|
||||
"CAM Direct Access Disk driver");
|
||||
@ -423,6 +424,8 @@ SYSCTL_INT(_kern_cam_da, OID_AUTO, retry_count, CTLFLAG_RW,
|
||||
&da_retry_count, 0, "Normal I/O retry count");
|
||||
SYSCTL_INT(_kern_cam_da, OID_AUTO, default_timeout, CTLFLAG_RW,
|
||||
&da_default_timeout, 0, "Normal I/O timeout (in seconds)");
|
||||
SYSCTL_INT(_kern_cam_da, OID_AUTO, no_6_byte, CTLFLAG_RW,
|
||||
&da_no_6_byte, 0, "No 6 bytes commands");
|
||||
|
||||
/*
|
||||
* DA_ORDEREDTAG_INTERVAL determines how often, relative
|
||||
@ -1249,6 +1252,8 @@ dastart(struct cam_periph *periph, union ccb *start_ccb)
|
||||
} else {
|
||||
tag_code = MSG_SIMPLE_Q_TAG;
|
||||
}
|
||||
if (da_no_6_byte && softc->minimum_cmd_size == 6)
|
||||
softc->minimum_cmd_size = 10;
|
||||
scsi_read_write(&start_ccb->csio,
|
||||
/*retries*/da_retry_count,
|
||||
dadone,
|
||||
@ -1321,6 +1326,48 @@ dastart(struct cam_periph *periph, union ccb *start_ccb)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
cmd6workaround(union ccb *ccb)
|
||||
{
|
||||
struct scsi_rw_6 cmd6;
|
||||
struct scsi_rw_10 *cmd10;
|
||||
struct da_softc *softc;
|
||||
struct ccb_scsiio *csio;
|
||||
u_int8_t opcode;
|
||||
|
||||
csio = &ccb->csio;
|
||||
opcode = ((struct scsi_rw_6 *)csio->cdb_io.cdb_bytes)->opcode;
|
||||
|
||||
if (opcode != READ_6 && opcode != WRITE_6)
|
||||
return 0;
|
||||
|
||||
xpt_print_path(ccb->ccb_h.path);
|
||||
printf("READ(6)/WRITE(6) failed, "
|
||||
"minimum_cmd_size is increased to 10.\n");
|
||||
softc = (struct da_softc *)xpt_path_periph(ccb->ccb_h.path)->softc;
|
||||
softc->minimum_cmd_size = 10;
|
||||
|
||||
bcopy(&csio->cdb_io.cdb_bytes, &cmd6, sizeof(struct scsi_rw_6));
|
||||
cmd10 = (struct scsi_rw_10 *) &csio->cdb_io.cdb_bytes;
|
||||
cmd10->opcode = (cmd6.opcode == READ_6) ? READ_10 : WRITE_10;
|
||||
cmd10->byte2 = 0;
|
||||
scsi_ulto4b(scsi_3btoul(cmd6.addr), cmd10->addr);
|
||||
cmd10->reserved = 0;
|
||||
scsi_ulto2b(cmd6.length, cmd10->length);
|
||||
cmd10->control = cmd6.control;
|
||||
csio->cdb_len = sizeof(*cmd10);
|
||||
|
||||
/* requeue */
|
||||
ccb->ccb_h.status = CAM_REQUEUE_REQ;
|
||||
xpt_action(ccb);
|
||||
if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
|
||||
cam_release_devq(ccb->ccb_h.path,
|
||||
/*relsim_flags*/0,
|
||||
/*reduction*/0,
|
||||
/*timeout*/0,
|
||||
/*getcount_only*/0);
|
||||
return (ERESTART);
|
||||
}
|
||||
|
||||
static void
|
||||
dadone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
@ -1393,6 +1440,11 @@ dadone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
bp->bio_error = 0;
|
||||
if (bp->bio_resid != 0) {
|
||||
/* Short transfer ??? */
|
||||
#if 0
|
||||
if (cmd6workaround(done_ccb)
|
||||
== ERESTART)
|
||||
return;
|
||||
#endif
|
||||
bp->bio_flags |= BIO_ERROR;
|
||||
}
|
||||
}
|
||||
@ -1406,8 +1458,14 @@ dadone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
|
||||
panic("REQ_CMP with QFRZN");
|
||||
bp->bio_resid = csio->resid;
|
||||
if (csio->resid > 0)
|
||||
if (csio->resid > 0) {
|
||||
/* Short transfer ??? */
|
||||
#if 0 /* XXX most of the broken umass devices need this ad-hoc work around */
|
||||
if (cmd6workaround(done_ccb) == ERESTART)
|
||||
return;
|
||||
#endif
|
||||
bp->bio_flags |= BIO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1574,10 +1632,26 @@ daerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
|
||||
{
|
||||
struct da_softc *softc;
|
||||
struct cam_periph *periph;
|
||||
int error, sense_key, error_code, asc, ascq;
|
||||
|
||||
periph = xpt_path_periph(ccb->ccb_h.path);
|
||||
softc = (struct da_softc *)periph->softc;
|
||||
|
||||
/*
|
||||
* Automatically detect devices that do not support
|
||||
* READ(6)/WRITE(6) and upgrade to using 10 byte cdbs.
|
||||
*/
|
||||
error = 0;
|
||||
if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR
|
||||
&& ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) {
|
||||
scsi_extract_sense(&ccb->csio.sense_data,
|
||||
&error_code, &sense_key, &asc, &ascq);
|
||||
if (sense_key == SSD_KEY_ILLEGAL_REQUEST)
|
||||
error = cmd6workaround(ccb);
|
||||
}
|
||||
if (error == ERESTART)
|
||||
return ERESTART;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Until we have a better way of doing pack validation,
|
||||
|
Loading…
Reference in New Issue
Block a user