Index: head/sys/cam/cam_ccb.h =================================================================== --- head/sys/cam/cam_ccb.h +++ head/sys/cam/cam_ccb.h @@ -207,7 +207,7 @@ /* Serial Management Protocol */ XPT_NVME_IO = 0x1c | XPT_FC_DEV_QUEUED, - /* Execiute the requestred NVMe I/O operation */ + /* Execute the requested NVMe I/O operation */ XPT_MMC_IO = 0x1d | XPT_FC_DEV_QUEUED, /* Placeholder for MMC / SD / SDIO I/O stuff */ @@ -216,6 +216,9 @@ | XPT_FC_XPT_ONLY, /* Scan Target */ + XPT_NVME_ADMIN = 0x1f | XPT_FC_DEV_QUEUED, + /* Execute the requested NVMe Admin operation */ + /* HBA engine commands 0x20->0x2F */ XPT_ENG_INQ = 0x20 | XPT_FC_XPT_ONLY, /* HBA engine feature inquiry */ @@ -819,7 +822,7 @@ }; /* - * NVMe I/O Request CCB used for the XPT_NVME_IO function code. + * NVMe I/O Request CCB used for the XPT_NVME_IO and XPT_NVME_ADMIN function codes. */ struct ccb_nvmeio { struct ccb_hdr ccb_h; @@ -1508,6 +1511,21 @@ u_int32_t timeout) { nvmeio->ccb_h.func_code = XPT_NVME_IO; + nvmeio->ccb_h.flags = flags; + nvmeio->ccb_h.retry_count = retries; + nvmeio->ccb_h.cbfcnp = cbfcnp; + nvmeio->ccb_h.timeout = timeout; + nvmeio->data_ptr = data_ptr; + nvmeio->dxfer_len = dxfer_len; +} + +static __inline void +cam_fill_nvmeadmin(struct ccb_nvmeio *nvmeio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int32_t flags, u_int8_t *data_ptr, u_int32_t dxfer_len, + u_int32_t timeout) +{ + nvmeio->ccb_h.func_code = XPT_NVME_ADMIN; nvmeio->ccb_h.flags = flags; nvmeio->ccb_h.retry_count = retries; nvmeio->ccb_h.cbfcnp = cbfcnp; Index: head/sys/cam/cam_periph.c =================================================================== --- head/sys/cam/cam_periph.c +++ head/sys/cam/cam_periph.c @@ -848,6 +848,17 @@ dirs[1] = CAM_DIR_IN; numbufs = 2; break; + case XPT_NVME_IO: + case XPT_NVME_ADMIN: + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) + return (0); + if ((ccb->ccb_h.flags & CAM_DATA_MASK) != CAM_DATA_VADDR) + return (EINVAL); + data_ptrs[0] = &ccb->nvmeio.data_ptr; + lengths[0] = ccb->nvmeio.dxfer_len; + dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK; + numbufs = 1; + break; case XPT_DEV_ADVINFO: if (ccb->cdai.bufsiz == 0) return (0); @@ -1013,6 +1024,11 @@ case XPT_DEV_ADVINFO: numbufs = min(mapinfo->num_bufs_used, 1); data_ptrs[0] = (uint8_t **)&ccb->cdai.buf; + break; + case XPT_NVME_IO: + case XPT_NVME_ADMIN: + data_ptrs[0] = &ccb->nvmeio.data_ptr; + numbufs = min(mapinfo->num_bufs_used, 1); break; default: /* allow ourselves to be swapped once again */ Index: head/sys/cam/cam_xpt.c =================================================================== --- head/sys/cam/cam_xpt.c +++ head/sys/cam/cam_xpt.c @@ -2689,9 +2689,9 @@ start_ccb->ataio.resid = 0; /* FALLTHROUGH */ case XPT_NVME_IO: - if (start_ccb->ccb_h.func_code == XPT_NVME_IO) - start_ccb->nvmeio.resid = 0; /* FALLTHROUGH */ + case XPT_NVME_ADMIN: + /* FALLTHROUGH */ case XPT_MMC_IO: /* XXX just like nmve_io? */ case XPT_RESET_DEV: @@ -5548,6 +5548,7 @@ { XPT_MMC_IO, "XPT_MMC_IO" }, { XPT_SMP_IO, "XPT_SMP_IO" }, { XPT_SCAN_TGT, "XPT_SCAN_TGT" }, + { XPT_NVME_ADMIN, "XPT_NVME_ADMIN" }, { XPT_ENG_INQ, "XPT_ENG_INQ" }, { XPT_ENG_EXEC, "XPT_ENG_EXEC" }, { XPT_EN_LUN, "XPT_EN_LUN" }, Index: head/sys/cam/scsi/scsi_pass.c =================================================================== --- head/sys/cam/scsi/scsi_pass.c +++ head/sys/cam/scsi/scsi_pass.c @@ -1146,6 +1146,11 @@ numbufs = min(io_req->num_bufs, 1); data_ptrs[0] = (uint8_t **)&ccb->cdai.buf; break; + case XPT_NVME_IO: + case XPT_NVME_ADMIN: + data_ptrs[0] = &ccb->nvmeio.data_ptr; + numbufs = min(io_req->num_bufs, 1); + break; default: /* allow ourselves to be swapped once again */ return; @@ -1384,6 +1389,25 @@ dirs[0] = CAM_DIR_IN; numbufs = 1; break; + case XPT_NVME_ADMIN: + case XPT_NVME_IO: + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) + return (0); + + io_req->data_flags = ccb->ccb_h.flags & CAM_DATA_MASK; + + /* + * We only support a single virtual address for NVMe + */ + if ((ccb->ccb_h.flags & CAM_DATA_MASK) != CAM_DATA_VADDR) + return (EINVAL); + + data_ptrs[0] = &ccb->nvmeio.data_ptr; + lengths[0] = ccb->nvmeio.dxfer_len; + dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK; + numbufs = 1; + maxmap = softc->maxio; + break; default: return(EINVAL); break; /* NOTREACHED */ @@ -1957,7 +1981,8 @@ */ if ((fc == XPT_SCSI_IO) || (fc == XPT_ATA_IO) || (fc == XPT_SMP_IO) || (fc == XPT_DEV_MATCH) - || (fc == XPT_DEV_ADVINFO)) { + || (fc == XPT_DEV_ADVINFO) + || (fc == XPT_NVME_ADMIN) || (fc == XPT_NVME_IO)) { error = passmemsetup(periph, io_req); if (error != 0) goto camioqueue_error; Index: head/sys/dev/nvme/nvme_sim.c =================================================================== --- head/sys/dev/nvme/nvme_sim.c +++ head/sys/dev/nvme/nvme_sim.c @@ -110,7 +110,10 @@ memcpy(&req->cmd, &ccb->nvmeio.cmd, sizeof(ccb->nvmeio.cmd)); - nvme_ctrlr_submit_io_request(ctrlr, req); + if (ccb->ccb_h.func_code == XPT_NVME_IO) + nvme_ctrlr_submit_io_request(ctrlr, req); + else + nvme_ctrlr_submit_admin_request(ctrlr, req); ccb->ccb_h.status |= CAM_SIM_QUEUED; } @@ -225,6 +228,7 @@ ccb->ccb_h.status = CAM_REQ_CMP; break; case XPT_NVME_IO: /* Execute the requested I/O operation */ + case XPT_NVME_ADMIN: /* or Admin operation */ nvme_sim_nvmeio(sim, ccb); return; /* no done */ default: Index: head/sys/kern/subr_bus_dma.c =================================================================== --- head/sys/kern/subr_bus_dma.c +++ head/sys/kern/subr_bus_dma.c @@ -218,6 +218,16 @@ sglist_cnt = 0; break; } + case XPT_NVME_IO: + case XPT_NVME_ADMIN: { + struct ccb_nvmeio *nvmeio; + + nvmeio = &ccb->nvmeio; + data_ptr = nvmeio->data_ptr; + dxfer_len = nvmeio->dxfer_len; + sglist_cnt = 0; + break; + } default: panic("_bus_dmamap_load_ccb: Unsupported func code %d", ccb_h->func_code);