[Midnightbsd-cvs] src [8805] trunk/sys/cam: Add cam infrastructure to allow reporting when a drive long read capacity data changes.
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Sun Sep 25 23:30:23 EDT 2016
Revision: 8805
http://svnweb.midnightbsd.org/src/?rev=8805
Author: laffer1
Date: 2016-09-25 23:30:23 -0400 (Sun, 25 Sep 2016)
Log Message:
-----------
Add cam infrastructure to allow reporting when a drive long read capacity data changes.
Modified Paths:
--------------
trunk/sys/cam/cam_ccb.h
trunk/sys/cam/cam_xpt.c
trunk/sys/cam/cam_xpt_internal.h
trunk/sys/cam/scsi/scsi_all.h
trunk/sys/cam/scsi/scsi_da.c
trunk/sys/cam/scsi/scsi_xpt.c
Modified: trunk/sys/cam/cam_ccb.h
===================================================================
--- trunk/sys/cam/cam_ccb.h 2016-09-26 03:29:45 UTC (rev 8804)
+++ trunk/sys/cam/cam_ccb.h 2016-09-26 03:30:23 UTC (rev 8805)
@@ -1128,6 +1128,7 @@
#define CDAI_TYPE_SCSI_DEVID 1
#define CDAI_TYPE_SERIAL_NUM 2
#define CDAI_TYPE_PHYS_PATH 3
+#define CDAI_TYPE_RCAPLONG 4
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 */
Modified: trunk/sys/cam/cam_xpt.c
===================================================================
--- trunk/sys/cam/cam_xpt.c 2016-09-26 03:29:45 UTC (rev 8804)
+++ trunk/sys/cam/cam_xpt.c 2016-09-26 03:30:23 UTC (rev 8805)
@@ -4616,6 +4616,17 @@
cam_devq_resize(devq, devq->alloc_queue.array_size - 1);
camq_fini(&device->drvq);
cam_ccbq_fini(&device->ccbq);
+ /*
+ * Free allocated memory. free(9) does nothing if the
+ * supplied pointer is NULL, so it is safe to call without
+ * checking.
+ */
+ free(device->supported_vpds, M_CAMXPT);
+ free(device->device_id, M_CAMXPT);
+ free(device->physpath, M_CAMXPT);
+ free(device->rcap_buf, M_CAMXPT);
+ free(device->serial_num, M_CAMXPT);
+
xpt_release_target(device->target);
free(device, M_CAMDEV);
} else
Modified: trunk/sys/cam/cam_xpt_internal.h
===================================================================
--- trunk/sys/cam/cam_xpt_internal.h 2016-09-26 03:29:45 UTC (rev 8804)
+++ trunk/sys/cam/cam_xpt_internal.h 2016-09-26 03:30:23 UTC (rev 8805)
@@ -99,6 +99,8 @@
uint8_t *device_id;
uint8_t physpath_len;
uint8_t *physpath; /* physical path string form */
+ uint32_t rcap_len;
+ uint8_t *rcap_buf;
struct ata_params ident_data;
u_int8_t inq_flags; /*
* Current settings for inquiry flags.
Modified: trunk/sys/cam/scsi/scsi_all.h
===================================================================
--- trunk/sys/cam/scsi/scsi_all.h 2016-09-26 03:29:45 UTC (rev 8804)
+++ trunk/sys/cam/scsi/scsi_all.h 2016-09-26 03:30:23 UTC (rev 8805)
@@ -1444,14 +1444,24 @@
uint8_t length[4];
#define SRC16_PROT_EN 0x01
#define SRC16_P_TYPE 0x0e
+#define SRC16_PTYPE_1 0x00
+#define SRC16_PTYPE_2 0x02
+#define SRC16_PTYPE_3 0x04
uint8_t prot;
#define SRC16_LBPPBE 0x0f
#define SRC16_PI_EXPONENT 0xf0
#define SRC16_PI_EXPONENT_SHIFT 4
uint8_t prot_lbppbe;
-#define SRC16_LALBA 0x3fff
-#define SRC16_LBPRZ 0x4000
-#define SRC16_LBPME 0x8000
+#define SRC16_LALBA 0x3f
+#define SRC16_LBPRZ 0x40
+#define SRC16_LBPME 0x80
+/*
+ * Alternate versions of these macros that are intended for use on a 16-bit
+ * version of the lalba_lbp field instead of the array of 2 8 bit numbers.
+ */
+#define SRC16_LALBA_A 0x3fff
+#define SRC16_LBPRZ_A 0x4000
+#define SRC16_LBPME_A 0x8000
uint8_t lalba_lbp[2];
};
Modified: trunk/sys/cam/scsi/scsi_da.c
===================================================================
--- trunk/sys/cam/scsi/scsi_da.c 2016-09-26 03:29:45 UTC (rev 8804)
+++ trunk/sys/cam/scsi/scsi_da.c 2016-09-26 03:30:23 UTC (rev 8805)
@@ -159,6 +159,7 @@
struct callout sendordered_c;
uint64_t wwpn;
uint8_t unmap_buf[UNMAP_MAX_RANGES * 16 + 8];
+ struct scsi_read_capacity_data_long rcaplong;
};
struct da_quirk_entry {
@@ -868,7 +869,9 @@
static void daprevent(struct cam_periph *periph, int action);
static int dagetcapacity(struct cam_periph *periph);
static void dasetgeom(struct cam_periph *periph, uint32_t block_len,
- uint64_t maxsector, u_int lbppbe, u_int lalba);
+ uint64_t maxsector,
+ struct scsi_read_capacity_data_long *rcaplong,
+ size_t rcap_size);
static timeout_t dasendorderedtag;
static void dashutdown(void *arg, int howto);
@@ -2262,10 +2265,15 @@
announce_buf[0] = '\0';
cam_periph_invalidate(periph);
} else {
+ /*
+ * We pass rcaplong into dasetgeom(),
+ * because it will only use it if it is
+ * non-NULL.
+ */
dasetgeom(periph, block_size, maxsector,
- lbppbe, lalba & SRC16_LALBA);
- if ((lalba & SRC16_LBPME) &&
- softc->delete_method == DA_DELETE_NONE)
+ rcaplong, sizeof(*rcaplong));
+ if ((lalba & SRC16_LBPME_A)
+ && softc->delete_method == DA_DELETE_NONE)
softc->delete_method = DA_DELETE_UNMAP;
dp = &softc->params;
snprintf(announce_buf, sizeof(announce_buf),
@@ -2539,6 +2547,7 @@
lalba = 0;
error = 0;
rc16failed = 0;
+ rcaplong = NULL;
sense_flags = SF_RETRY_UA;
if (softc->flags & DA_FLAG_PACK_REMOVABLE)
sense_flags |= SF_NO_PRINT;
@@ -2556,39 +2565,46 @@
/* Try READ CAPACITY(16) first if we think it should work. */
if (softc->flags & DA_FLAG_CAN_RC16) {
scsi_read_capacity_16(&ccb->csio,
- /*retries*/ 4,
- /*cbfcnp*/ dadone,
- /*tag_action*/ MSG_SIMPLE_Q_TAG,
- /*lba*/ 0,
- /*reladr*/ 0,
- /*pmi*/ 0,
- rcaplong,
- /*sense_len*/ SSD_FULL_SIZE,
- /*timeout*/ 60000);
+ /*retries*/ 4,
+ /*cbfcnp*/ dadone,
+ /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*lba*/ 0,
+ /*reladr*/ 0,
+ /*pmi*/ 0,
+ /*rcap_buf*/ rcaplong,
+ /*sense_len*/ SSD_FULL_SIZE,
+ /*timeout*/ 60000);
ccb->ccb_h.ccb_bp = NULL;
error = cam_periph_runccb(ccb, daerror,
- /*cam_flags*/CAM_RETRY_SELTO,
- sense_flags,
- softc->disk->d_devstat);
+ /*cam_flags*/CAM_RETRY_SELTO,
+ sense_flags, softc->disk->d_devstat);
if (error == 0)
goto rc16ok;
/* If we got ILLEGAL REQUEST, do not prefer RC16 any more. */
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
- CAM_REQ_INVALID) {
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INVALID) {
softc->flags &= ~DA_FLAG_CAN_RC16;
} else if (((ccb->ccb_h.status & CAM_STATUS_MASK) ==
- CAM_SCSI_STATUS_ERROR) &&
- (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) &&
- (ccb->ccb_h.status & CAM_AUTOSNS_VALID) &&
- ((ccb->ccb_h.flags & CAM_SENSE_PHYS) == 0) &&
- ((ccb->ccb_h.flags & CAM_SENSE_PTR) == 0)) {
+ CAM_SCSI_STATUS_ERROR)
+ && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND)
+ && (ccb->ccb_h.status & CAM_AUTOSNS_VALID)
+ && ((ccb->ccb_h.flags & CAM_SENSE_PHYS) == 0)
+ && ((ccb->ccb_h.flags & CAM_SENSE_PTR) == 0)) {
int sense_key, error_code, asc, ascq;
- scsi_extract_sense(&ccb->csio.sense_data,
- &error_code, &sense_key, &asc, &ascq);
- if (sense_key == SSD_KEY_ILLEGAL_REQUEST)
+ scsi_extract_sense_len(&ccb->csio.sense_data,
+ ccb->csio.sense_len -
+ ccb->csio.sense_resid,
+ &error_code, &sense_key,
+ &asc, &ascq, /*show_errors*/1);
+ /*
+ * If we don't have enough sense to get the sense
+ * key, or if it's illegal request, turn off
+ * READ CAPACITY (16).
+ */
+ if ((sense_key == -1)
+ || (sense_key == SSD_KEY_ILLEGAL_REQUEST))
softc->flags &= ~DA_FLAG_CAN_RC16;
}
rc16failed = 1;
@@ -2652,9 +2668,9 @@
error = EINVAL;
} else {
dasetgeom(periph, block_len, maxsector,
- lbppbe, lalba & SRC16_LALBA);
- if ((lalba & SRC16_LBPME) &&
- softc->delete_method == DA_DELETE_NONE)
+ rcaplong, sizeof(*rcaplong));
+ if ((lalba & SRC16_LBPME)
+ && softc->delete_method == DA_DELETE_NONE)
softc->delete_method = DA_DELETE_UNMAP;
}
}
@@ -2668,11 +2684,12 @@
static void
dasetgeom(struct cam_periph *periph, uint32_t block_len, uint64_t maxsector,
- u_int lbppbe, u_int lalba)
+ struct scsi_read_capacity_data_long *rcaplong, size_t rcap_len)
{
struct ccb_calc_geometry ccg;
struct da_softc *softc;
struct disk_params *dp;
+ u_int lbppbe, lalba;
softc = (struct da_softc *)periph->softc;
@@ -2679,6 +2696,15 @@
dp = &softc->params;
dp->secsize = block_len;
dp->sectors = maxsector + 1;
+ if (rcaplong != NULL) {
+ lbppbe = rcaplong->prot_lbppbe & SRC16_LBPPBE;
+ lalba = scsi_2btoul(rcaplong->lalba_lbp);
+ lalba &= SRC16_LALBA_A;
+ } else {
+ lbppbe = 0;
+ lalba = 0;
+ }
+
if (lbppbe > 0) {
dp->stripesize = block_len << lbppbe;
dp->stripeoffset = (dp->stripesize - block_len * lalba) %
@@ -2723,6 +2749,38 @@
dp->secs_per_track = ccg.secs_per_track;
dp->cylinders = ccg.cylinders;
}
+
+ /*
+ * If the user supplied a read capacity buffer, and if it is
+ * different than the previous buffer, update the data in the EDT.
+ * If it's the same, we don't bother. This avoids sending an
+ * update every time someone opens this device.
+ */
+ if ((rcaplong != NULL)
+ && (bcmp(rcaplong, &softc->rcaplong,
+ min(sizeof(softc->rcaplong), rcap_len)) != 0)) {
+ struct ccb_dev_advinfo cdai;
+
+ xpt_setup_ccb(&cdai.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
+ cdai.ccb_h.func_code = XPT_DEV_ADVINFO;
+ cdai.buftype = CDAI_TYPE_RCAPLONG;
+ cdai.flags |= CDAI_FLAG_STORE;
+ cdai.bufsiz = rcap_len;
+ cdai.buf = (uint8_t *)rcaplong;
+ xpt_action((union ccb *)&cdai);
+ if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0)
+ cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE);
+ if (cdai.ccb_h.status != CAM_REQ_CMP) {
+ xpt_print(periph->path, "%s: failed to set read "
+ "capacity advinfo\n", __func__);
+ /* Use cam_error_print() to decode the status */
+ cam_error_print((union ccb *)&cdai, CAM_ESF_CAM_STATUS,
+ CAM_EPF_ALL);
+ } else {
+ bcopy(rcaplong, &softc->rcaplong,
+ min(sizeof(softc->rcaplong), rcap_len));
+ }
+ }
}
static void
Modified: trunk/sys/cam/scsi/scsi_xpt.c
===================================================================
--- trunk/sys/cam/scsi/scsi_xpt.c 2016-09-26 03:29:45 UTC (rev 8804)
+++ trunk/sys/cam/scsi/scsi_xpt.c 2016-09-26 03:30:23 UTC (rev 8805)
@@ -2473,8 +2473,10 @@
break;
case CDAI_TYPE_PHYS_PATH:
if (cdai->flags & CDAI_FLAG_STORE) {
- if (device->physpath != NULL)
+ if (device->physpath != NULL) {
free(device->physpath, M_CAMXPT);
+ device->physpath = NULL;
+ }
device->physpath_len = cdai->bufsiz;
/* Clear existing buffer if zero length */
if (cdai->bufsiz == 0)
@@ -2495,6 +2497,36 @@
memcpy(cdai->buf, device->physpath, amt);
}
break;
+ case CDAI_TYPE_RCAPLONG:
+ if (cdai->flags & CDAI_FLAG_STORE) {
+ if (device->rcap_buf != NULL) {
+ free(device->rcap_buf, M_CAMXPT);
+ device->rcap_buf = NULL;
+ }
+
+ device->rcap_len = cdai->bufsiz;
+ /* Clear existing buffer if zero length */
+ if (cdai->bufsiz == 0)
+ break;
+
+ device->rcap_buf = malloc(cdai->bufsiz, M_CAMXPT,
+ M_NOWAIT);
+ if (device->rcap_buf == NULL) {
+ start_ccb->ccb_h.status = CAM_REQ_ABORTED;
+ return;
+ }
+
+ memcpy(device->rcap_buf, cdai->buf, cdai->bufsiz);
+ } else {
+ cdai->provsiz = device->rcap_len;
+ if (device->rcap_len == 0)
+ break;
+ amt = device->rcap_len;
+ if (cdai->provsiz > cdai->bufsiz)
+ amt = cdai->bufsiz;
+ memcpy(cdai->buf, device->rcap_buf, amt);
+ }
+ break;
default:
return;
}
More information about the Midnightbsd-cvs
mailing list