summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/cam/cam_ccb.h1
-rw-r--r--sys/cam/cam_xpt.c1
-rw-r--r--sys/cam/cam_xpt_internal.h2
-rw-r--r--sys/cam/scsi/scsi_xpt.c89
-rw-r--r--sys/sys/param.h2
5 files changed, 94 insertions, 1 deletions
diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h
index c2f6c46..9b882ca 100644
--- a/sys/cam/cam_ccb.h
+++ b/sys/cam/cam_ccb.h
@@ -1152,6 +1152,7 @@ struct ccb_dev_advinfo {
#define CDAI_TYPE_SERIAL_NUM 2
#define CDAI_TYPE_PHYS_PATH 3
#define CDAI_TYPE_RCAPLONG 4
+#define CDAI_TYPE_EXT_INQ 5
off_t bufsiz; /* IN: Size of external buffer */
#define CAM_SCSI_DEVID_MAXLEN 65536 /* length in buffer is an uint16_t */
off_t provsiz; /* OUT: Size required/used */
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index c8a7256..b48654a 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -4793,6 +4793,7 @@ xpt_release_device(struct cam_ed *device)
*/
free(device->supported_vpds, M_CAMXPT);
free(device->device_id, M_CAMXPT);
+ free(device->ext_inq, M_CAMXPT);
free(device->physpath, M_CAMXPT);
free(device->rcap_buf, M_CAMXPT);
free(device->serial_num, M_CAMXPT);
diff --git a/sys/cam/cam_xpt_internal.h b/sys/cam/cam_xpt_internal.h
index f8c6498..23d6d34 100644
--- a/sys/cam/cam_xpt_internal.h
+++ b/sys/cam/cam_xpt_internal.h
@@ -83,6 +83,8 @@ struct cam_ed {
uint8_t supported_vpds_len;
uint32_t device_id_len;
uint8_t *device_id;
+ uint32_t ext_inq_len;
+ uint8_t *ext_inq;
uint8_t physpath_len;
uint8_t *physpath; /* physical path string form */
uint32_t rcap_len;
diff --git a/sys/cam/scsi/scsi_xpt.c b/sys/cam/scsi/scsi_xpt.c
index df82871..57bcfb2 100644
--- a/sys/cam/scsi/scsi_xpt.c
+++ b/sys/cam/scsi/scsi_xpt.c
@@ -142,6 +142,7 @@ typedef enum {
PROBE_MODE_SENSE,
PROBE_SUPPORTED_VPD_LIST,
PROBE_DEVICE_ID,
+ PROBE_EXTENDED_INQUIRY,
PROBE_SERIAL_NUM,
PROBE_TUR_FOR_NEGOTIATION,
PROBE_INQUIRY_BASIC_DV1,
@@ -159,6 +160,7 @@ static char *probe_action_text[] = {
"PROBE_MODE_SENSE",
"PROBE_SUPPORTED_VPD_LIST",
"PROBE_DEVICE_ID",
+ "PROBE_EXTENDED_INQUIRY",
"PROBE_SERIAL_NUM",
"PROBE_TUR_FOR_NEGOTIATION",
"PROBE_INQUIRY_BASIC_DV1",
@@ -926,6 +928,34 @@ done:
}
goto done;
}
+ case PROBE_EXTENDED_INQUIRY:
+ {
+ struct scsi_vpd_extended_inquiry_data *ext_inq;
+
+ ext_inq = NULL;
+ if (scsi_vpd_supported_page(periph, SVPD_EXTENDED_INQUIRY_DATA))
+ ext_inq = malloc(sizeof(*ext_inq), M_CAMXPT,
+ M_NOWAIT | M_ZERO);
+
+ if (ext_inq != NULL) {
+ scsi_inquiry(csio,
+ /*retries*/4,
+ probedone,
+ MSG_SIMPLE_Q_TAG,
+ (uint8_t *)ext_inq,
+ sizeof(*ext_inq),
+ /*evpd*/TRUE,
+ SVPD_EXTENDED_INQUIRY_DATA,
+ SSD_MIN_SIZE,
+ /*timeout*/60 * 1000);
+ break;
+ }
+ /*
+ * We'll have to do without, let our probedone
+ * routine finish up for us.
+ */
+ goto done;
+ }
case PROBE_SERIAL_NUM:
{
struct scsi_vpd_unit_serial_number *serial_buf;
@@ -1457,6 +1487,50 @@ out:
if (devid && length == 0)
free(devid, M_CAMXPT);
xpt_release_ccb(done_ccb);
+ PROBE_SET_ACTION(softc, PROBE_EXTENDED_INQUIRY);
+ xpt_schedule(periph, priority);
+ goto out;
+ }
+ case PROBE_EXTENDED_INQUIRY: {
+ struct scsi_vpd_extended_inquiry_data *ext_inq;
+ struct ccb_scsiio *csio;
+ int32_t length = 0;
+
+ csio = &done_ccb->csio;
+ ext_inq = (struct scsi_vpd_extended_inquiry_data *)
+ csio->data_ptr;
+ if (path->device->ext_inq != NULL) {
+ path->device->ext_inq_len = 0;
+ free(path->device->ext_inq, M_CAMXPT);
+ path->device->ext_inq = NULL;
+ }
+
+ if (ext_inq == NULL) {
+ /* Don't process the command as it was never sent */
+ } else if (CCB_COMPLETED_OK(csio->ccb_h)) {
+ length = scsi_2btoul(ext_inq->page_length) +
+ __offsetof(struct scsi_vpd_extended_inquiry_data,
+ flags1);
+ length = min(length, sizeof(*ext_inq));
+ length -= csio->resid;
+ if (length > 0) {
+ path->device->ext_inq_len = length;
+ path->device->ext_inq = (uint8_t *)ext_inq;
+ }
+ } else if (cam_periph_error(done_ccb, 0,
+ SF_RETRY_UA,
+ &softc->saved_ccb) == ERESTART) {
+ return;
+ } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
+ /* Don't wedge the queue */
+ xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
+ /*run_queue*/TRUE);
+ }
+
+ /* Free the device id space if we don't use it */
+ if (ext_inq && length <= 0)
+ free(ext_inq, M_CAMXPT);
+ xpt_release_ccb(done_ccb);
PROBE_SET_ACTION(softc, PROBE_SERIAL_NUM);
xpt_schedule(periph, priority);
goto out;
@@ -2486,6 +2560,21 @@ scsi_dev_advinfo(union ccb *start_ccb)
memcpy(cdai->buf, device->rcap_buf, amt);
}
break;
+ case CDAI_TYPE_EXT_INQ:
+ /*
+ * We fetch extended inquiry data during probe, if
+ * available. We don't allow changing it.
+ */
+ if (cdai->flags & CDAI_FLAG_STORE)
+ return;
+ cdai->provsiz = device->ext_inq_len;
+ if (device->ext_inq_len == 0)
+ break;
+ amt = device->ext_inq_len;
+ if (cdai->provsiz > cdai->bufsiz)
+ amt = cdai->bufsiz;
+ memcpy(cdai->buf, device->ext_inq, amt);
+ break;
default:
return;
}
diff --git a/sys/sys/param.h b/sys/sys/param.h
index 9df21bf..d837048 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -58,7 +58,7 @@
* in the range 5 to 9.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 1001507 /* Master, propagated to newvers */
+#define __FreeBSD_version 1001508 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
OpenPOWER on IntegriCloud