svn commit: r322785 - head/usr.sbin/camdd
Kenneth D. Merry
ken at FreeBSD.org
Tue Aug 22 13:08:23 UTC 2017
Author: ken
Date: Tue Aug 22 13:08:22 2017
New Revision: 322785
URL: https://svnweb.freebsd.org/changeset/base/322785
Log:
Restructure camdd(8) slightly to make it easier to add support for
additional protocols.
Submitted by: Chuck Tuffli <chuck at tuffli.net>
MFC after: 1 week
Differential Revision: D11230
Modified:
head/usr.sbin/camdd/camdd.c
Modified: head/usr.sbin/camdd/camdd.c
==============================================================================
--- head/usr.sbin/camdd/camdd.c Tue Aug 22 11:11:49 2017 (r322784)
+++ head/usr.sbin/camdd/camdd.c Tue Aug 22 13:08:22 2017 (r322785)
@@ -260,6 +260,7 @@ struct camdd_buf {
struct camdd_dev_pass {
int scsi_dev_type;
+ int protocol;
struct cam_device *dev;
uint64_t max_sector;
uint32_t block_len;
@@ -477,6 +478,9 @@ uint32_t camdd_buf_get_len(struct camdd_buf *buf);
void camdd_buf_add_child(struct camdd_buf *buf, struct camdd_buf *child_buf);
int camdd_probe_tape(int fd, char *filename, uint64_t *max_iosize,
uint64_t *max_blk, uint64_t *min_blk, uint64_t *blk_gran);
+int camdd_probe_pass_scsi(struct cam_device *cam_dev, union ccb *ccb,
+ camdd_argmask arglist, int probe_retry_count,
+ int probe_timeout, uint64_t *maxsector, uint32_t *block_len);
struct camdd_dev *camdd_probe_file(int fd, struct camdd_io_opts *io_opts,
int retry_count, int timeout);
struct camdd_dev *camdd_probe_pass(struct cam_device *cam_dev,
@@ -485,7 +489,8 @@ struct camdd_dev *camdd_probe_pass(struct cam_device *
int probe_timeout, int io_retry_count,
int io_timeout);
void *camdd_file_worker(void *arg);
-camdd_buf_status camdd_ccb_status(union ccb *ccb);
+camdd_buf_status camdd_ccb_status(union ccb *ccb, int protocol);
+int camdd_get_cgd(struct cam_device *device, struct ccb_getdev *cgd);
int camdd_queue_peer_buf(struct camdd_dev *dev, struct camdd_buf *buf);
int camdd_complete_peer_buf(struct camdd_dev *dev, struct camdd_buf *peer_buf);
void camdd_peer_done(struct camdd_buf *buf);
@@ -1248,56 +1253,59 @@ bailout_error:
}
/*
- * Need to implement this. Do a basic probe:
- * - Check the inquiry data, make sure we're talking to a device that we
- * can reasonably expect to talk to -- direct, RBC, CD, WORM.
- * - Send a test unit ready, make sure the device is available.
- * - Get the capacity and block size.
+ * Get a get device CCB for the specified device.
*/
-struct camdd_dev *
-camdd_probe_pass(struct cam_device *cam_dev, struct camdd_io_opts *io_opts,
- camdd_argmask arglist, int probe_retry_count,
- int probe_timeout, int io_retry_count, int io_timeout)
+int
+camdd_get_cgd(struct cam_device *device, struct ccb_getdev *cgd)
{
- union ccb *ccb;
- uint64_t maxsector;
- uint32_t cpi_maxio, max_iosize, pass_numblocks;
- uint32_t block_len;
- struct scsi_read_capacity_data rcap;
- struct scsi_read_capacity_data_long rcaplong;
- struct camdd_dev *dev;
- struct camdd_dev_pass *pass_dev;
- struct kevent ke;
- int scsi_dev_type;
+ union ccb *ccb;
+ int retval = 0;
- dev = NULL;
+ ccb = cam_getccb(device);
+
+ if (ccb == NULL) {
+ warnx("%s: couldn't allocate CCB", __func__);
+ return -1;
+ }
- scsi_dev_type = SID_TYPE(&cam_dev->inq_data);
- maxsector = 0;
- block_len = 0;
+ CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->cgd);
- /*
- * For devices that support READ CAPACITY, we'll attempt to get the
- * capacity. Otherwise, we really don't support tape or other
- * devices via SCSI passthrough, so just return an error in that case.
- */
- switch (scsi_dev_type) {
- case T_DIRECT:
- case T_WORM:
- case T_CDROM:
- case T_OPTICAL:
- case T_RBC:
- case T_ZBC_HM:
- break;
- default:
- errx(1, "Unsupported SCSI device type %d", scsi_dev_type);
- break; /*NOTREACHED*/
+ ccb->ccb_h.func_code = XPT_GDEV_TYPE;
+
+ if (cam_send_ccb(device, ccb) < 0) {
+ warn("%s: error sending Get Device Information CCB", __func__);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ retval = -1;
+ goto bailout;
}
- ccb = cam_getccb(cam_dev);
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ retval = -1;
+ goto bailout;
+ }
+ bcopy(&ccb->cgd, cgd, sizeof(struct ccb_getdev));
+
+bailout:
+ cam_freeccb(ccb);
+
+ return retval;
+}
+
+int
+camdd_probe_pass_scsi(struct cam_device *cam_dev, union ccb *ccb,
+ camdd_argmask arglist, int probe_retry_count,
+ int probe_timeout, uint64_t *maxsector, uint32_t *block_len)
+{
+ struct scsi_read_capacity_data rcap;
+ struct scsi_read_capacity_data_long rcaplong;
+ int retval = -1;
+
if (ccb == NULL) {
- warnx("%s: error allocating ccb", __func__);
+ warnx("%s: error passed ccb is NULL", __func__);
goto bailout;
}
@@ -1331,16 +1339,18 @@ camdd_probe_pass(struct cam_device *cam_dev, struct ca
goto bailout;
}
- maxsector = scsi_4btoul(rcap.addr);
- block_len = scsi_4btoul(rcap.length);
+ *maxsector = scsi_4btoul(rcap.addr);
+ *block_len = scsi_4btoul(rcap.length);
/*
* A last block of 2^32-1 means that the true capacity is over 2TB,
* and we need to issue the long READ CAPACITY to get the real
* capacity. Otherwise, we're all set.
*/
- if (maxsector != 0xffffffff)
- goto rcap_done;
+ if (*maxsector != 0xffffffff) {
+ retval = 0;
+ goto bailout;
+ }
scsi_read_capacity_16(&ccb->csio,
/*retries*/ probe_retry_count,
@@ -1372,10 +1382,83 @@ camdd_probe_pass(struct cam_device *cam_dev, struct ca
goto bailout;
}
- maxsector = scsi_8btou64(rcaplong.addr);
- block_len = scsi_4btoul(rcaplong.length);
+ *maxsector = scsi_8btou64(rcaplong.addr);
+ *block_len = scsi_4btoul(rcaplong.length);
-rcap_done:
+ retval = 0;
+
+bailout:
+ return retval;
+}
+
+/*
+ * Need to implement this. Do a basic probe:
+ * - Check the inquiry data, make sure we're talking to a device that we
+ * can reasonably expect to talk to -- direct, RBC, CD, WORM.
+ * - Send a test unit ready, make sure the device is available.
+ * - Get the capacity and block size.
+ */
+struct camdd_dev *
+camdd_probe_pass(struct cam_device *cam_dev, struct camdd_io_opts *io_opts,
+ camdd_argmask arglist, int probe_retry_count,
+ int probe_timeout, int io_retry_count, int io_timeout)
+{
+ union ccb *ccb;
+ uint64_t maxsector = 0;
+ uint32_t cpi_maxio, max_iosize, pass_numblocks;
+ uint32_t block_len = 0;
+ struct camdd_dev *dev = NULL;
+ struct camdd_dev_pass *pass_dev;
+ struct kevent ke;
+ struct ccb_getdev cgd;
+ int retval;
+ int scsi_dev_type;
+
+ if ((retval = camdd_get_cgd(cam_dev, &cgd)) != 0) {
+ warnx("%s: error retrieving CGD", __func__);
+ return NULL;
+ }
+
+ ccb = cam_getccb(cam_dev);
+
+ if (ccb == NULL) {
+ warnx("%s: error allocating ccb", __func__);
+ goto bailout;
+ }
+
+ switch (cgd.protocol) {
+ case PROTO_SCSI:
+ scsi_dev_type = SID_TYPE(&cam_dev->inq_data);
+
+ /*
+ * For devices that support READ CAPACITY, we'll attempt to get the
+ * capacity. Otherwise, we really don't support tape or other
+ * devices via SCSI passthrough, so just return an error in that case.
+ */
+ switch (scsi_dev_type) {
+ case T_DIRECT:
+ case T_WORM:
+ case T_CDROM:
+ case T_OPTICAL:
+ case T_RBC:
+ case T_ZBC_HM:
+ break;
+ default:
+ errx(1, "Unsupported SCSI device type %d", scsi_dev_type);
+ break; /*NOTREACHED*/
+ }
+
+ if ((retval = camdd_probe_pass_scsi(cam_dev, ccb, probe_retry_count,
+ arglist, probe_timeout, &maxsector,
+ &block_len))) {
+ goto bailout;
+ }
+ break;
+ default:
+ errx(1, "Unsupported PROTO type %d", cgd.protocol);
+ break; /*NOTREACHED*/
+ }
+
if (block_len == 0) {
warnx("Sector size for %s%u is 0, cannot continue",
cam_dev->device_name, cam_dev->dev_unit_num);
@@ -1405,6 +1488,7 @@ rcap_done:
pass_dev = &dev->dev_spec.pass;
pass_dev->scsi_dev_type = scsi_dev_type;
+ pass_dev->protocol = cgd.protocol;
pass_dev->dev = cam_dev;
pass_dev->max_sector = maxsector;
pass_dev->block_len = block_len;
@@ -1715,43 +1799,50 @@ bailout:
* Simplistic translation of CCB status to our local status.
*/
camdd_buf_status
-camdd_ccb_status(union ccb *ccb)
+camdd_ccb_status(union ccb *ccb, int protocol)
{
camdd_buf_status status = CAMDD_STATUS_NONE;
cam_status ccb_status;
ccb_status = ccb->ccb_h.status & CAM_STATUS_MASK;
- switch (ccb_status) {
- case CAM_REQ_CMP: {
- if (ccb->csio.resid == 0) {
- status = CAMDD_STATUS_OK;
- } else if (ccb->csio.dxfer_len > ccb->csio.resid) {
- status = CAMDD_STATUS_SHORT_IO;
- } else {
- status = CAMDD_STATUS_EOF;
+ switch (protocol) {
+ case PROTO_SCSI:
+ switch (ccb_status) {
+ case CAM_REQ_CMP: {
+ if (ccb->csio.resid == 0) {
+ status = CAMDD_STATUS_OK;
+ } else if (ccb->csio.dxfer_len > ccb->csio.resid) {
+ status = CAMDD_STATUS_SHORT_IO;
+ } else {
+ status = CAMDD_STATUS_EOF;
+ }
+ break;
}
- break;
- }
- case CAM_SCSI_STATUS_ERROR: {
- switch (ccb->csio.scsi_status) {
- case SCSI_STATUS_OK:
- case SCSI_STATUS_COND_MET:
- case SCSI_STATUS_INTERMED:
- case SCSI_STATUS_INTERMED_COND_MET:
- status = CAMDD_STATUS_OK;
+ case CAM_SCSI_STATUS_ERROR: {
+ switch (ccb->csio.scsi_status) {
+ case SCSI_STATUS_OK:
+ case SCSI_STATUS_COND_MET:
+ case SCSI_STATUS_INTERMED:
+ case SCSI_STATUS_INTERMED_COND_MET:
+ status = CAMDD_STATUS_OK;
+ break;
+ case SCSI_STATUS_CMD_TERMINATED:
+ case SCSI_STATUS_CHECK_COND:
+ case SCSI_STATUS_QUEUE_FULL:
+ case SCSI_STATUS_BUSY:
+ case SCSI_STATUS_RESERV_CONFLICT:
+ default:
+ status = CAMDD_STATUS_ERROR;
+ break;
+ }
break;
- case SCSI_STATUS_CMD_TERMINATED:
- case SCSI_STATUS_CHECK_COND:
- case SCSI_STATUS_QUEUE_FULL:
- case SCSI_STATUS_BUSY:
- case SCSI_STATUS_RESERV_CONFLICT:
+ }
default:
status = CAMDD_STATUS_ERROR;
break;
}
break;
- }
default:
status = CAMDD_STATUS_ERROR;
break;
@@ -2149,11 +2240,18 @@ camdd_pass_fetch(struct camdd_dev *dev)
CAM_EPF_ALL, stderr);
}
- data->resid = ccb.csio.resid;
- dev->bytes_transferred += (ccb.csio.dxfer_len - ccb.csio.resid);
+ switch (pass_dev->protocol) {
+ case PROTO_SCSI:
+ data->resid = ccb.csio.resid;
+ dev->bytes_transferred += (ccb.csio.dxfer_len - ccb.csio.resid);
+ break;
+ default:
+ return -1;
+ break;
+ }
if (buf->status == CAMDD_STATUS_NONE)
- buf->status = camdd_ccb_status(&ccb);
+ buf->status = camdd_ccb_status(&ccb, pass_dev->protocol);
if (buf->status == CAMDD_STATUS_ERROR)
error_count++;
else if (buf->status == CAMDD_STATUS_EOF) {
@@ -2433,9 +2531,6 @@ camdd_pass_run(struct camdd_dev *dev)
data = &buf->buf_type_spec.data;
- ccb = &data->ccb;
- CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
-
/*
* In almost every case the number of blocks should be the device
* block size. The exception may be at the end of an I/O stream
@@ -2446,22 +2541,37 @@ camdd_pass_run(struct camdd_dev *dev)
else
num_blocks = data->fill_len / pass_dev->block_len;
- scsi_read_write(&ccb->csio,
- /*retries*/ dev->retry_count,
- /*cbfcnp*/ NULL,
- /*tag_action*/ MSG_SIMPLE_Q_TAG,
- /*readop*/ (dev->write_dev == 0) ? SCSI_RW_READ :
- SCSI_RW_WRITE,
- /*byte2*/ 0,
- /*minimum_cmd_size*/ dev->min_cmd_size,
- /*lba*/ buf->lba,
- /*block_count*/ num_blocks,
- /*data_ptr*/ (data->sg_count != 0) ?
- (uint8_t *)data->segs : data->buf,
- /*dxfer_len*/ (num_blocks * pass_dev->block_len),
- /*sense_len*/ SSD_FULL_SIZE,
- /*timeout*/ dev->io_timeout);
+ ccb = &data->ccb;
+ switch (pass_dev->protocol) {
+ case PROTO_SCSI:
+ CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
+
+ scsi_read_write(&ccb->csio,
+ /*retries*/ dev->retry_count,
+ /*cbfcnp*/ NULL,
+ /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*readop*/ (dev->write_dev == 0) ? SCSI_RW_READ :
+ SCSI_RW_WRITE,
+ /*byte2*/ 0,
+ /*minimum_cmd_size*/ dev->min_cmd_size,
+ /*lba*/ buf->lba,
+ /*block_count*/ num_blocks,
+ /*data_ptr*/ (data->sg_count != 0) ?
+ (uint8_t *)data->segs : data->buf,
+ /*dxfer_len*/ (num_blocks * pass_dev->block_len),
+ /*sense_len*/ SSD_FULL_SIZE,
+ /*timeout*/ dev->io_timeout);
+
+ if (data->sg_count != 0) {
+ ccb->csio.sglist_cnt = data->sg_count;
+ }
+ break;
+ default:
+ retval = -1;
+ goto bailout;
+ }
+
/* Disable freezing the device queue */
ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
@@ -2469,7 +2579,6 @@ camdd_pass_run(struct camdd_dev *dev)
ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
if (data->sg_count != 0) {
- ccb->csio.sglist_cnt = data->sg_count;
ccb->ccb_h.flags |= CAM_DATA_SG;
}
More information about the svn-src-all
mailing list