aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Percival <cperciva@FreeBSD.org>2020-09-28 00:53:45 +0000
committerColin Percival <cperciva@FreeBSD.org>2020-09-28 00:53:45 +0000
commit88afe3774d72804d7cb88f554ba3b5cda371b2ee (patch)
treefdf0ae082f1fe970965ef2f51f6e7544423d1918
parentc18eb742b0083583b0d9aabded1b3fe8d307f459 (diff)
downloadsrc-88afe3774d72804d7cb88f554ba3b5cda371b2ee.tar.gz
src-88afe3774d72804d7cb88f554ba3b5cda371b2ee.zip
MFS r366179: Make nvmecontrol work with nda like it does with nvd, and
associated bits. Approved by: re (delphij) Sponsored by: https://www.patreon.com/cperciva
Notes
Notes: svn path=/releng/12.2/; revision=366213
-rw-r--r--sys/cam/cam_ccb.h5
-rw-r--r--sys/cam/nvme/nvme_da.c93
-rw-r--r--sys/dev/nvme/nvme_sim.c2
3 files changed, 97 insertions, 3 deletions
diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h
index 7893b19290aa..3b04cbf0f8f1 100644
--- a/sys/cam/cam_ccb.h
+++ b/sys/cam/cam_ccb.h
@@ -630,6 +630,7 @@ struct ccb_pathinq_settings_sas {
u_int32_t bitrate; /* Mbps */
};
+#define NVME_DEV_NAME_LEN 52
struct ccb_pathinq_settings_nvme {
uint32_t nsid; /* Namespace ID for this path */
uint32_t domain;
@@ -637,7 +638,10 @@ struct ccb_pathinq_settings_nvme {
uint8_t slot;
uint8_t function;
uint8_t extra;
+ char dev_name[NVME_DEV_NAME_LEN]; /* nvme controller dev name for this device */
};
+_Static_assert(sizeof(struct ccb_pathinq_settings_nvme) == 64,
+ "ccb_pathinq_settings_nvme too big");
#define PATHINQ_SETTINGS_SIZE 128
@@ -1030,6 +1034,7 @@ struct ccb_trans_settings_nvme
uint8_t speed; /* PCIe generation for each lane */
uint8_t max_lanes; /* Number of PCIe lanes */
uint8_t max_speed; /* PCIe generation for each lane */
+
};
#include <cam/mmc/mmc_bus.h>
diff --git a/sys/cam/nvme/nvme_da.c b/sys/cam/nvme/nvme_da.c
index 059b940ea2df..50b5ae29fc0b 100644
--- a/sys/cam/nvme/nvme_da.c
+++ b/sys/cam/nvme/nvme_da.c
@@ -88,6 +88,7 @@ typedef enum {
NDA_CCB_BUFFER_IO = 0x01,
NDA_CCB_DUMP = 0x02,
NDA_CCB_TRIM = 0x03,
+ NDA_CCB_PASS = 0x04,
NDA_CCB_TYPE_MASK = 0x0F,
} nda_ccb_state;
@@ -136,6 +137,7 @@ struct nda_trim_request {
/* Need quirk table */
+static disk_ioctl_t ndaioctl;
static disk_strategy_t ndastrategy;
static dumper_t ndadump;
static periph_init_t ndainit;
@@ -354,6 +356,91 @@ ndaschedule(struct cam_periph *periph)
cam_iosched_schedule(softc->cam_iosched, periph);
}
+static int
+ndaioctl(struct disk *dp, u_long cmd, void *data, int fflag,
+ struct thread *td)
+{
+ struct cam_periph *periph;
+ struct nda_softc *softc;
+
+ periph = (struct cam_periph *)dp->d_drv1;
+ softc = (struct nda_softc *)periph->softc;
+
+ switch (cmd) {
+ case NVME_IO_TEST:
+ case NVME_BIO_TEST:
+ /*
+ * These don't map well to the underlying CCBs, so
+ * they are usupported via CAM.
+ */
+ return (ENOTTY);
+ case NVME_GET_NSID:
+ {
+ struct nvme_get_nsid *gnsid = (struct nvme_get_nsid *)data;
+ struct ccb_pathinq cpi;
+
+ xpt_path_inq(&cpi, periph->path);
+ strncpy(gnsid->cdev, cpi.xport_specific.nvme.dev_name,
+ sizeof(gnsid->cdev));
+ gnsid->nsid = cpi.xport_specific.nvme.nsid;
+ return (0);
+ }
+ case NVME_PASSTHROUGH_CMD:
+ {
+ struct nvme_pt_command *pt;
+ union ccb *ccb;
+ struct cam_periph_map_info mapinfo;
+ u_int maxmap = MAXPHYS; /* XXX is this right */
+ int error;
+
+ /*
+ * Create a NVME_IO CCB to do the passthrough command.
+ */
+ pt = (struct nvme_pt_command *)data;
+ ccb = xpt_alloc_ccb();
+ xpt_setup_ccb(&ccb->ccb_h, periph->path, CAM_PRIORITY_NORMAL);
+ ccb->ccb_state = NDA_CCB_PASS;
+ cam_fill_nvmeio(&ccb->nvmeio,
+ 0, /* Retries */
+ ndadone,
+ (pt->is_read ? CAM_DIR_IN : CAM_DIR_OUT) | CAM_DATA_VADDR,
+ pt->buf,
+ pt->len,
+ nda_default_timeout * 1000);
+ memcpy(&ccb->nvmeio.cmd, &pt->cmd, sizeof(pt->cmd));
+
+ /*
+ * Wire the user memory in this request for the I/O
+ */
+ memset(&mapinfo, 0, sizeof(mapinfo));
+ error = cam_periph_mapmem(ccb, &mapinfo, maxmap);
+ if (error)
+ return (error);
+
+ /*
+ * Lock the periph and run the command. XXX do we need
+ * to lock the periph?
+ */
+ cam_periph_lock(periph);
+ cam_periph_runccb(ccb, NULL, CAM_RETRY_SELTO, SF_RETRY_UA | SF_NO_PRINT,
+ NULL);
+ cam_periph_unlock(periph);
+
+ /*
+ * Tear down mapping and return status.
+ */
+ cam_periph_unmapmem(ccb, &mapinfo);
+ cam_periph_lock(periph);
+ error = (ccb->ccb_h.status == CAM_REQ_CMP) ? 0 : EIO;
+ xpt_release_ccb(ccb);
+ return (error);
+ }
+ default:
+ break;
+ }
+ return (ENOTTY);
+}
+
/*
* Actually translate the requested transfer into one the physical driver
* can understand. The transfer is described by a buf and will include
@@ -735,11 +822,8 @@ ndaregister(struct cam_periph *periph, void *arg)
/* ident_data parsing */
periph->softc = softc;
-
softc->quirks = NDA_Q_NONE;
-
xpt_path_inq(&cpi, periph->path);
-
TASK_INIT(&softc->sysctl_task, 0, ndasysctlinit, periph);
/*
@@ -763,6 +847,7 @@ ndaregister(struct cam_periph *periph, void *arg)
disk->d_open = ndaopen;
disk->d_close = ndaclose;
disk->d_strategy = ndastrategy;
+ disk->d_ioctl = ndaioctl;
disk->d_getattr = ndagetattr;
disk->d_dump = ndadump;
disk->d_gone = ndadiskgonecb;
@@ -1109,6 +1194,8 @@ ndadone(struct cam_periph *periph, union ccb *done_ccb)
case NDA_CCB_DUMP:
/* No-op. We're polling */
return;
+ case NDA_CCB_PASS:
+ return;
default:
break;
}
diff --git a/sys/dev/nvme/nvme_sim.c b/sys/dev/nvme/nvme_sim.c
index 88582e47972f..b66126b11bce 100644
--- a/sys/dev/nvme/nvme_sim.c
+++ b/sys/dev/nvme/nvme_sim.c
@@ -197,6 +197,8 @@ nvme_sim_action(struct cam_sim *sim, union ccb *ccb)
cpi->xport_specific.nvme.slot = pci_get_slot(dev);
cpi->xport_specific.nvme.function = pci_get_function(dev);
cpi->xport_specific.nvme.extra = 0;
+ strncpy(cpi->xport_specific.nvme.dev_name, device_get_nameunit(ctrlr->dev),
+ sizeof(cpi->xport_specific.nvme.dev_name));
cpi->ccb_h.status = CAM_REQ_CMP;
break;
}