Index: sys/cam/cam_ccb.h =================================================================== --- sys/cam/cam_ccb.h +++ sys/cam/cam_ccb.h @@ -630,6 +630,7 @@ 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 @@ 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 @@ 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 Index: sys/cam/nvme/nvme_da.c =================================================================== --- sys/cam/nvme/nvme_da.c +++ sys/cam/nvme/nvme_da.c @@ -95,6 +95,7 @@ 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; @@ -144,6 +145,7 @@ /* Need quirk table */ +static disk_ioctl_t ndaioctl; static disk_strategy_t ndastrategy; static dumper_t ndadump; static periph_init_t ndainit; @@ -366,6 +368,91 @@ 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 @@ -782,11 +869,8 @@ /* 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); /* @@ -810,6 +894,7 @@ 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; @@ -1163,6 +1248,8 @@ case NDA_CCB_DUMP: /* No-op. We're polling */ return; + case NDA_CCB_PASS: + return; default: break; } Index: sys/dev/nvme/nvme_sim.c =================================================================== --- sys/dev/nvme/nvme_sim.c +++ sys/dev/nvme/nvme_sim.c @@ -203,6 +203,8 @@ 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; }