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