summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sbin/camcontrol/camcontrol.c3
-rw-r--r--sys/cam/cam_ccb.h1
-rw-r--r--sys/cam/cam_xpt.c11
-rw-r--r--sys/cam/cam_xpt_internal.h2
-rw-r--r--sys/cam/scsi/scsi_all.c8
-rw-r--r--sys/cam/scsi/scsi_all.h22
-rw-r--r--sys/cam/scsi/scsi_da.c125
-rw-r--r--sys/cam/scsi/scsi_xpt.c34
-rw-r--r--sys/sys/param.h2
-rw-r--r--usr.sbin/mptutil/mpt_cam.c2
10 files changed, 164 insertions, 46 deletions
diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c
index 6116db7..0bbb511 100644
--- a/sbin/camcontrol/camcontrol.c
+++ b/sbin/camcontrol/camcontrol.c
@@ -4232,7 +4232,8 @@ scsireadcapacity(struct cam_device *device, int argc, char **argv,
/*lba*/ 0,
/*reladdr*/ 0,
/*pmi*/ 0,
- &rcaplong,
+ /*rcap_buf*/ (uint8_t *)&rcaplong,
+ /*rcap_buf_len*/ sizeof(rcaplong),
/*sense_len*/ SSD_FULL_SIZE,
/*timeout*/ timeout ? timeout : 5000);
diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h
index 0d51482..6eb3b50 100644
--- a/sys/cam/cam_ccb.h
+++ b/sys/cam/cam_ccb.h
@@ -1118,6 +1118,7 @@ struct ccb_dev_advinfo {
#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 */
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index 7b639a9..0ee1cc4 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -4588,6 +4588,17 @@ xpt_release_device(struct cam_ed *device)
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_CAMXPT);
} else
diff --git a/sys/cam/cam_xpt_internal.h b/sys/cam/cam_xpt_internal.h
index b6e8f66..8c62c4e 100644
--- a/sys/cam/cam_xpt_internal.h
+++ b/sys/cam/cam_xpt_internal.h
@@ -99,6 +99,8 @@ struct cam_ed {
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.
diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c
index 93e5658..2622609 100644
--- a/sys/cam/scsi/scsi_all.c
+++ b/sys/cam/scsi/scsi_all.c
@@ -5325,8 +5325,8 @@ void
scsi_read_capacity_16(struct ccb_scsiio *csio, uint32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
uint8_t tag_action, uint64_t lba, int reladr, int pmi,
- struct scsi_read_capacity_data_long *rcap_buf,
- uint8_t sense_len, uint32_t timeout)
+ uint8_t *rcap_buf, int rcap_buf_len, uint8_t sense_len,
+ uint32_t timeout)
{
struct scsi_read_capacity_16 *scsi_cmd;
@@ -5337,7 +5337,7 @@ scsi_read_capacity_16(struct ccb_scsiio *csio, uint32_t retries,
/*flags*/CAM_DIR_IN,
tag_action,
/*data_ptr*/(u_int8_t *)rcap_buf,
- /*dxfer_len*/sizeof(*rcap_buf),
+ /*dxfer_len*/rcap_buf_len,
sense_len,
sizeof(*scsi_cmd),
timeout);
@@ -5346,7 +5346,7 @@ scsi_read_capacity_16(struct ccb_scsiio *csio, uint32_t retries,
scsi_cmd->opcode = SERVICE_ACTION_IN;
scsi_cmd->service_action = SRC16_SERVICE_ACTION;
scsi_u64to8b(lba, scsi_cmd->addr);
- scsi_ulto4b(sizeof(*rcap_buf), scsi_cmd->alloc_len);
+ scsi_ulto4b(rcap_buf_len, scsi_cmd->alloc_len);
if (pmi)
reladr |= SRC16_PMI;
if (reladr)
diff --git a/sys/cam/scsi/scsi_all.h b/sys/cam/scsi/scsi_all.h
index bc56418..ebee01c 100644
--- a/sys/cam/scsi/scsi_all.h
+++ b/sys/cam/scsi/scsi_all.h
@@ -1437,15 +1437,26 @@ struct scsi_read_capacity_data_long
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];
+ uint8_t reserved[16];
};
struct scsi_report_luns
@@ -2293,9 +2304,8 @@ void scsi_read_capacity_16(struct ccb_scsiio *csio, uint32_t retries,
void (*cbfcnp)(struct cam_periph *,
union ccb *), uint8_t tag_action,
uint64_t lba, int reladr, int pmi,
- struct scsi_read_capacity_data_long
- *rcap_buf, uint8_t sense_len,
- uint32_t timeout);
+ uint8_t *rcap_buf, int rcap_buf_len,
+ uint8_t sense_len, uint32_t timeout);
void scsi_report_luns(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *,
diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c
index 756093c..b3bf5ff 100644
--- a/sys/cam/scsi/scsi_da.c
+++ b/sys/cam/scsi/scsi_da.c
@@ -160,6 +160,7 @@ struct da_softc {
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 {
@@ -830,7 +831,9 @@ static int daerror(union ccb *ccb, u_int32_t cam_flags,
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);
@@ -1948,7 +1951,8 @@ out:
/*lba*/ 0,
/*reladr*/ 0,
/*pmi*/ 0,
- rcaplong,
+ /*rcap_buf*/ (uint8_t *)rcaplong,
+ /*rcap_buf_len*/ sizeof(*rcaplong),
/*sense_len*/ SSD_FULL_SIZE,
/*timeout*/ 60000);
start_ccb->ccb_h.ccb_bp = NULL;
@@ -2227,10 +2231,15 @@ dadone(struct cam_periph *periph, union ccb *done_ccb)
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),
@@ -2504,6 +2513,7 @@ dagetcapacity(struct cam_periph *periph)
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;
@@ -2521,39 +2531,47 @@ dagetcapacity(struct cam_periph *periph)
/* 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*/ (uint8_t *)rcaplong,
+ /*rcap_buf_len*/ sizeof(*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;
@@ -2590,7 +2608,8 @@ dagetcapacity(struct cam_periph *periph)
/*lba*/ 0,
/*reladr*/ 0,
/*pmi*/ 0,
- rcaplong,
+ /*rcap_buf*/ (uint8_t *)rcaplong,
+ /*rcap_buf_len*/ sizeof(*rcaplong),
/*sense_len*/ SSD_FULL_SIZE,
/*timeout*/ 60000);
ccb->ccb_h.ccb_bp = NULL;
@@ -2617,9 +2636,9 @@ done:
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;
}
}
@@ -2633,17 +2652,27 @@ done:
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;
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) %
@@ -2688,6 +2717,38 @@ dasetgeom(struct cam_periph *periph, uint32_t block_len, uint64_t maxsector,
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
diff --git a/sys/cam/scsi/scsi_xpt.c b/sys/cam/scsi/scsi_xpt.c
index b177fca..7ff4f7e 100644
--- a/sys/cam/scsi/scsi_xpt.c
+++ b/sys/cam/scsi/scsi_xpt.c
@@ -2468,8 +2468,10 @@ scsi_dev_advinfo(union ccb *start_ccb)
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)
@@ -2490,6 +2492,36 @@ scsi_dev_advinfo(union ccb *start_ccb)
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;
}
diff --git a/sys/sys/param.h b/sys/sys/param.h
index 921ba46..35bca55 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 1000005 /* Master, propagated to newvers */
+#define __FreeBSD_version 1000006 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
diff --git a/usr.sbin/mptutil/mpt_cam.c b/usr.sbin/mptutil/mpt_cam.c
index 3adbed8..6a8ff07 100644
--- a/usr.sbin/mptutil/mpt_cam.c
+++ b/usr.sbin/mptutil/mpt_cam.c
@@ -277,7 +277,7 @@ fetch_scsi_capacity(struct cam_device *dev, struct mpt_standalone_disk *disk)
sizeof(struct ccb_hdr));
scsi_read_capacity_16(&ccb->csio, 1, NULL, MSG_SIMPLE_Q_TAG, 0, 0, 0,
- &rcaplong, SSD_FULL_SIZE, 5000);
+ (uint8_t *)&rcaplong, sizeof(rcaplong), SSD_FULL_SIZE, 5000);
/* Disable freezing the device queue */
ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
OpenPOWER on IntegriCloud