From owner-svn-src-all@freebsd.org Tue Aug 22 13:08:23 2017 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id AC2A8DEA1F0; Tue, 22 Aug 2017 13:08:23 +0000 (UTC) (envelope-from ken@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 6BC7F1055; Tue, 22 Aug 2017 13:08:23 +0000 (UTC) (envelope-from ken@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v7MD8MVS001891; Tue, 22 Aug 2017 13:08:22 GMT (envelope-from ken@FreeBSD.org) Received: (from ken@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v7MD8MXs001890; Tue, 22 Aug 2017 13:08:22 GMT (envelope-from ken@FreeBSD.org) Message-Id: <201708221308.v7MD8MXs001890@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ken set sender to ken@FreeBSD.org using -f From: "Kenneth D. Merry" Date: Tue, 22 Aug 2017 13:08:22 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r322785 - head/usr.sbin/camdd X-SVN-Group: head X-SVN-Commit-Author: ken X-SVN-Commit-Paths: head/usr.sbin/camdd X-SVN-Commit-Revision: 322785 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 22 Aug 2017 13:08:23 -0000 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 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; }