Date: Sat, 8 Jun 2019 17:17:17 +0000 (UTC) From: Chuck Tuffli <chuck@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r348806 - head/usr.sbin/camdd Message-ID: <201906081717.x58HHHST031098@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: chuck Date: Sat Jun 8 17:17:17 2019 New Revision: 348806 URL: https://svnweb.freebsd.org/changeset/base/348806 Log: Add NVMe support to camdd(8) Reviewed by: ken Approved by: ken (mentor) MFC after: 1 week Differential Review: https://reviews.freebsd.org/D12141 Modified: head/usr.sbin/camdd/camdd.c Modified: head/usr.sbin/camdd/camdd.c ============================================================================== --- head/usr.sbin/camdd/camdd.c Sat Jun 8 16:26:56 2019 (r348805) +++ head/usr.sbin/camdd/camdd.c Sat Jun 8 17:17:17 2019 (r348806) @@ -80,6 +80,7 @@ __FBSDID("$FreeBSD$"); #include <cam/scsi/scsi_pass.h> #include <cam/scsi/scsi_message.h> #include <cam/scsi/smp_all.h> +#include <cam/nvme/nvme_all.h> #include <camlib.h> #include <mtlib.h> #include <zlib.h> @@ -463,6 +464,9 @@ int camdd_probe_tape(int fd, char *filename, uint64_t 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); +int camdd_probe_pass_nvme(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, @@ -470,6 +474,11 @@ struct camdd_dev *camdd_probe_pass(struct cam_device * camdd_argmask arglist, int probe_retry_count, int probe_timeout, int io_retry_count, int io_timeout); +void nvme_read_write(struct ccb_nvmeio *nvmeio, uint32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + uint32_t nsid, int readop, uint64_t lba, + uint32_t block_count, uint8_t *data_ptr, uint32_t dxfer_len, + uint32_t timeout); void *camdd_file_worker(void *arg); camdd_buf_status camdd_ccb_status(union ccb *ccb, int protocol); int camdd_get_cgd(struct cam_device *device, struct ccb_getdev *cgd); @@ -1379,6 +1388,72 @@ bailout: return retval; } +int +camdd_probe_pass_nvme(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 nvme_command *nc = NULL; + struct nvme_namespace_data nsdata; + uint32_t nsid = cam_dev->target_lun & UINT32_MAX; + uint8_t format = 0, lbads = 0; + int retval = -1; + + if (ccb == NULL) { + warnx("%s: error passed ccb is NULL", __func__); + goto bailout; + } + + CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->nvmeio); + + /* Send Identify Namespace to get block size and capacity */ + nc = &ccb->nvmeio.cmd; + nc->opc = NVME_OPC_IDENTIFY; + + nc->nsid = nsid; + nc->cdw10 = 0; /* Identify Namespace is CNS = 0 */ + + cam_fill_nvmeadmin(&ccb->nvmeio, + /*retries*/ probe_retry_count, + /*cbfcnp*/ NULL, + CAM_DIR_IN, + (uint8_t *)&nsdata, + sizeof(nsdata), + probe_timeout); + + /* Disable freezing the device queue */ + ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; + + if (arglist & CAMDD_ARG_ERR_RECOVER) + ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; + + if (cam_send_ccb(cam_dev, ccb) < 0) { + warn("error sending Identify Namespace command"); + + cam_error_print(cam_dev, ccb, CAM_ESF_ALL, + CAM_EPF_ALL, stderr); + + goto bailout; + } + + if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + cam_error_print(cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); + goto bailout; + } + + *maxsector = nsdata.nsze; + /* The LBA Data Size (LBADS) is reported as a power of 2 */ + format = nsdata.flbas & NVME_NS_DATA_FLBAS_FORMAT_MASK; + lbads = (nsdata.lbaf[format] >> NVME_NS_DATA_LBAF_LBADS_SHIFT) & + NVME_NS_DATA_LBAF_LBADS_MASK; + *block_len = 1 << lbads; + + 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 @@ -1442,6 +1517,13 @@ camdd_probe_pass(struct cam_device *cam_dev, struct ca goto bailout; } break; + case PROTO_NVME: + if ((retval = camdd_probe_pass_nvme(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*/ @@ -1576,6 +1658,34 @@ bailout_error: return (NULL); } +void +nvme_read_write(struct ccb_nvmeio *nvmeio, uint32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + uint32_t nsid, int readop, uint64_t lba, + uint32_t block_count, uint8_t *data_ptr, uint32_t dxfer_len, + uint32_t timeout) +{ + struct nvme_command *nc = &nvmeio->cmd; + + nc->opc = readop ? NVME_OPC_READ : NVME_OPC_WRITE; + + nc->nsid = nsid; + + nc->cdw10 = lba & UINT32_MAX; + nc->cdw11 = lba >> 32; + + /* NLB (bits 15:0) is a zero based value */ + nc->cdw12 = (block_count - 1) & UINT16_MAX; + + cam_fill_nvmeio(nvmeio, + retries, + cbfcnp, + readop ? CAM_DIR_IN : CAM_DIR_OUT, + data_ptr, + dxfer_len, + timeout); +} + void * camdd_worker(void *arg) { @@ -1831,6 +1941,16 @@ camdd_ccb_status(union ccb *ccb, int protocol) break; } break; + case PROTO_NVME: + switch (ccb_status) { + case CAM_REQ_CMP: + status = CAMDD_STATUS_OK; + break; + default: + status = CAMDD_STATUS_ERROR; + break; + } + break; default: status = CAMDD_STATUS_ERROR; break; @@ -2233,6 +2353,10 @@ camdd_pass_fetch(struct camdd_dev *dev) data->resid = ccb.csio.resid; dev->bytes_transferred += (ccb.csio.dxfer_len - ccb.csio.resid); break; + case PROTO_NVME: + data->resid = 0; + dev->bytes_transferred += ccb.nvmeio.dxfer_len; + break; default: return -1; break; @@ -2554,6 +2678,23 @@ camdd_pass_run(struct camdd_dev *dev) if (data->sg_count != 0) { ccb->csio.sglist_cnt = data->sg_count; } + break; + case PROTO_NVME: + CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->nvmeio); + + nvme_read_write(&ccb->nvmeio, + /*retries*/ dev->retry_count, + /*cbfcnp*/ NULL, + /*nsid*/ pass_dev->dev->target_lun & UINT32_MAX, + /*readop*/ dev->write_dev == 0, + /*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), + /*timeout*/ dev->io_timeout); + + ccb->nvmeio.sglist_cnt = data->sg_count; break; default: retval = -1;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201906081717.x58HHHST031098>