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 <ch...@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;
        }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to