summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authorsimokawa <simokawa@FreeBSD.org>2002-03-23 18:18:02 +0000
committersimokawa <simokawa@FreeBSD.org>2002-03-23 18:18:02 +0000
commit0edcbc8d2f47de488e51537e83b314cb1b9b8297 (patch)
tree0536198309f30eef9b02581e9fa018d57952d793 /sys/cam
parent8cb84dc7fa4d80169ef4aeb36a08c71ab46f538a (diff)
downloadFreeBSD-src-0edcbc8d2f47de488e51537e83b314cb1b9b8297.zip
FreeBSD-src-0edcbc8d2f47de488e51537e83b314cb1b9b8297.tar.gz
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
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/scsi/scsi_da.c76
1 files changed, 75 insertions, 1 deletions
diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c
index 2101587..e0b282d 100644
--- a/sys/cam/scsi/scsi_da.c
+++ b/sys/cam/scsi/scsi_da.c
@@ -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,
OpenPOWER on IntegriCloud