Index: sys/cam/cam_ccb.h =================================================================== --- sys/cam/cam_ccb.h +++ sys/cam/cam_ccb.h @@ -206,7 +206,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_MMCSD_IO = 0x1d | XPT_FC_DEV_QUEUED, /* Placeholder for MMC / SD / SDIO I/O stuff */ @@ -215,6 +215,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 */ @@ -805,7 +808,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; @@ -1443,6 +1446,21 @@ 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; + nvmeio->ccb_h.timeout = timeout; + nvmeio->data_ptr = data_ptr; + nvmeio->dxfer_len = dxfer_len; +} __END_DECLS #endif /* _CAM_CAM_CCB_H */ Index: sys/cam/cam_periph.c =================================================================== --- sys/cam/cam_periph.c +++ sys/cam/cam_periph.c @@ -819,6 +819,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); Index: sys/cam/cam_xpt.c =================================================================== --- sys/cam/cam_xpt.c +++ sys/cam/cam_xpt.c @@ -2575,6 +2575,10 @@ if (start_ccb->ccb_h.func_code == XPT_NVME_IO) start_ccb->nvmeio.resid = 0; /* FALLTHROUGH */ + case XPT_NVME_ADMIN: + if (start_ccb->ccb_h.func_code == XPT_NVME_ADMIN) + start_ccb->nvmeio.resid = 0; + /* FALLTHROUGH */ case XPT_RESET_DEV: case XPT_ENG_EXEC: case XPT_SMP_IO: @@ -5428,6 +5432,7 @@ { XPT_MMCSD_IO, "XPT_MMCSD_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: sys/cam/scsi/scsi_pass.c =================================================================== --- sys/cam/scsi/scsi_pass.c +++ sys/cam/scsi/scsi_pass.c @@ -2202,6 +2202,7 @@ */ fc = ccb->ccb_h.func_code; if ((fc == XPT_SCSI_IO) || (fc == XPT_ATA_IO) || (fc == XPT_SMP_IO) + || (fc == XPT_NVME_IO) || (fc == XPT_NVME_ADMIN) || (fc == XPT_DEV_MATCH) || (fc == XPT_DEV_ADVINFO)) { bzero(&mapinfo, sizeof(mapinfo)); Index: sys/dev/nvme/nvme_sim.c =================================================================== --- sys/dev/nvme/nvme_sim.c +++ 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: