13a31c31cSWarner Losh /*- 252467047SWarner Losh * Copyright (c) 2016 Netflix, Inc. 33a31c31cSWarner Losh * 43a31c31cSWarner Losh * Redistribution and use in source and binary forms, with or without 53a31c31cSWarner Losh * modification, are permitted provided that the following conditions 63a31c31cSWarner Losh * are met: 73a31c31cSWarner Losh * 1. Redistributions of source code must retain the above copyright 83a31c31cSWarner Losh * notice, this list of conditions and the following disclaimer, 93a31c31cSWarner Losh * without modification, immediately at the beginning of the file. 103a31c31cSWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 113a31c31cSWarner Losh * notice, this list of conditions and the following disclaimer in the 123a31c31cSWarner Losh * documentation and/or other materials provided with the distribution. 133a31c31cSWarner Losh * 143a31c31cSWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 153a31c31cSWarner Losh * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 163a31c31cSWarner Losh * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 173a31c31cSWarner Losh * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 183a31c31cSWarner Losh * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 193a31c31cSWarner Losh * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 203a31c31cSWarner Losh * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 213a31c31cSWarner Losh * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 223a31c31cSWarner Losh * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 233a31c31cSWarner Losh * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 243a31c31cSWarner Losh */ 253a31c31cSWarner Losh 263a31c31cSWarner Losh #include <sys/cdefs.h> 273a31c31cSWarner Losh __FBSDID("$FreeBSD$"); 283a31c31cSWarner Losh 293a31c31cSWarner Losh #include <sys/param.h> 303a31c31cSWarner Losh #include <sys/systm.h> 313a31c31cSWarner Losh #include <sys/buf.h> 323a31c31cSWarner Losh #include <sys/bus.h> 333a31c31cSWarner Losh #include <sys/conf.h> 343a31c31cSWarner Losh #include <sys/ioccom.h> 353a31c31cSWarner Losh #include <sys/malloc.h> 363a31c31cSWarner Losh #include <sys/proc.h> 373a31c31cSWarner Losh #include <sys/smp.h> 383a31c31cSWarner Losh 393a31c31cSWarner Losh #include <cam/cam.h> 403a31c31cSWarner Losh #include <cam/cam_ccb.h> 413a31c31cSWarner Losh #include <cam/cam_sim.h> 423a31c31cSWarner Losh #include <cam/cam_xpt_sim.h> 433a31c31cSWarner Losh #include <cam/cam_debug.h> 443a31c31cSWarner Losh 454e3b2744SWarner Losh #include <dev/pci/pcivar.h> 464e3b2744SWarner Losh #include <dev/pci/pcireg.h> 474e3b2744SWarner Losh 483a31c31cSWarner Losh #include "nvme_private.h" 493a31c31cSWarner Losh 503a31c31cSWarner Losh #define ccb_accb_ptr spriv_ptr0 513a31c31cSWarner Losh #define ccb_ctrlr_ptr spriv_ptr1 523a31c31cSWarner Losh static void nvme_sim_action(struct cam_sim *sim, union ccb *ccb); 533a31c31cSWarner Losh static void nvme_sim_poll(struct cam_sim *sim); 543a31c31cSWarner Losh 553a31c31cSWarner Losh #define sim2softc(sim) ((struct nvme_sim_softc *)cam_sim_softc(sim)) 563a31c31cSWarner Losh #define sim2ctrlr(sim) (sim2softc(sim)->s_ctrlr) 573a31c31cSWarner Losh 583a31c31cSWarner Losh struct nvme_sim_softc 593a31c31cSWarner Losh { 603a31c31cSWarner Losh struct nvme_controller *s_ctrlr; 613a31c31cSWarner Losh struct cam_sim *s_sim; 623a31c31cSWarner Losh struct cam_path *s_path; 633a31c31cSWarner Losh }; 643a31c31cSWarner Losh 653a31c31cSWarner Losh static void 663a31c31cSWarner Losh nvme_sim_nvmeio_done(void *ccb_arg, const struct nvme_completion *cpl) 673a31c31cSWarner Losh { 683a31c31cSWarner Losh union ccb *ccb = (union ccb *)ccb_arg; 693a31c31cSWarner Losh 703a31c31cSWarner Losh /* 713a31c31cSWarner Losh * Let the periph know the completion, and let it sort out what 723a31c31cSWarner Losh * it means. Make our best guess, though for the status code. 733a31c31cSWarner Losh */ 743a31c31cSWarner Losh memcpy(&ccb->nvmeio.cpl, cpl, sizeof(*cpl)); 757e5f6f25SWarner Losh ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 76cfb43eb1SWarner Losh if (nvme_completion_is_error(cpl)) { 773a31c31cSWarner Losh ccb->ccb_h.status = CAM_REQ_CMP_ERR; 783a31c31cSWarner Losh xpt_done(ccb); 79cfb43eb1SWarner Losh } else { 80cfb43eb1SWarner Losh ccb->ccb_h.status = CAM_REQ_CMP; 81cfb43eb1SWarner Losh xpt_done_direct(ccb); 82cfb43eb1SWarner Losh } 833a31c31cSWarner Losh } 843a31c31cSWarner Losh 853a31c31cSWarner Losh static void 863a31c31cSWarner Losh nvme_sim_nvmeio(struct cam_sim *sim, union ccb *ccb) 873a31c31cSWarner Losh { 883a31c31cSWarner Losh struct ccb_nvmeio *nvmeio = &ccb->nvmeio; 893a31c31cSWarner Losh struct nvme_request *req; 903a31c31cSWarner Losh void *payload; 913a31c31cSWarner Losh uint32_t size; 923a31c31cSWarner Losh struct nvme_controller *ctrlr; 933a31c31cSWarner Losh 943a31c31cSWarner Losh ctrlr = sim2ctrlr(sim); 953a31c31cSWarner Losh payload = nvmeio->data_ptr; 963a31c31cSWarner Losh size = nvmeio->dxfer_len; 973a31c31cSWarner Losh /* SG LIST ??? */ 983a31c31cSWarner Losh if ((nvmeio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_BIO) 993a31c31cSWarner Losh req = nvme_allocate_request_bio((struct bio *)payload, 1003a31c31cSWarner Losh nvme_sim_nvmeio_done, ccb); 10151977281SWarner Losh else if ((nvmeio->ccb_h.flags & CAM_DATA_SG) == CAM_DATA_SG) 10251977281SWarner Losh req = nvme_allocate_request_ccb(ccb, nvme_sim_nvmeio_done, ccb); 1033a31c31cSWarner Losh else if (payload == NULL) 1043a31c31cSWarner Losh req = nvme_allocate_request_null(nvme_sim_nvmeio_done, ccb); 1053a31c31cSWarner Losh else 1063a31c31cSWarner Losh req = nvme_allocate_request_vaddr(payload, size, 1073a31c31cSWarner Losh nvme_sim_nvmeio_done, ccb); 1083a31c31cSWarner Losh 1093a31c31cSWarner Losh if (req == NULL) { 1103a31c31cSWarner Losh nvmeio->ccb_h.status = CAM_RESRC_UNAVAIL; 1113a31c31cSWarner Losh xpt_done(ccb); 1123a31c31cSWarner Losh return; 1133a31c31cSWarner Losh } 1147e5f6f25SWarner Losh ccb->ccb_h.status |= CAM_SIM_QUEUED; 1153a31c31cSWarner Losh 1163a31c31cSWarner Losh memcpy(&req->cmd, &ccb->nvmeio.cmd, sizeof(ccb->nvmeio.cmd)); 1173a31c31cSWarner Losh 118df424515SWarner Losh if (ccb->ccb_h.func_code == XPT_NVME_IO) 1193a31c31cSWarner Losh nvme_ctrlr_submit_io_request(ctrlr, req); 120df424515SWarner Losh else 121df424515SWarner Losh nvme_ctrlr_submit_admin_request(ctrlr, req); 1223a31c31cSWarner Losh } 1233a31c31cSWarner Losh 1244e3b2744SWarner Losh static uint32_t 1254e3b2744SWarner Losh nvme_link_kBps(struct nvme_controller *ctrlr) 1264e3b2744SWarner Losh { 1274e3b2744SWarner Losh uint32_t speed, lanes, link[] = { 1, 250000, 500000, 985000, 1970000 }; 128eab9d0a8SWarner Losh uint32_t status; 1294e3b2744SWarner Losh 130eab9d0a8SWarner Losh status = pcie_read_config(ctrlr->dev, PCIER_LINK_STA, 2); 131eab9d0a8SWarner Losh speed = status & PCIEM_LINK_STA_SPEED; 132eab9d0a8SWarner Losh lanes = (status & PCIEM_LINK_STA_WIDTH) >> 4; 1334e3b2744SWarner Losh /* 1344e3b2744SWarner Losh * Failsafe on link speed indicator. If it is insane report the number of 1354e3b2744SWarner Losh * lanes as the speed. Not 100% accurate, but may be diagnostic. 1364e3b2744SWarner Losh */ 1374e3b2744SWarner Losh if (speed >= nitems(link)) 1384e3b2744SWarner Losh speed = 0; 1394e3b2744SWarner Losh return link[speed] * lanes; 1404e3b2744SWarner Losh } 1414e3b2744SWarner Losh 1423a31c31cSWarner Losh static void 1433a31c31cSWarner Losh nvme_sim_action(struct cam_sim *sim, union ccb *ccb) 1443a31c31cSWarner Losh { 1453a31c31cSWarner Losh struct nvme_controller *ctrlr; 1463a31c31cSWarner Losh 1473a31c31cSWarner Losh CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, 1483a31c31cSWarner Losh ("nvme_sim_action: func= %#x\n", 1493a31c31cSWarner Losh ccb->ccb_h.func_code)); 1503a31c31cSWarner Losh 1513a31c31cSWarner Losh ctrlr = sim2ctrlr(sim); 1523a31c31cSWarner Losh 1533a31c31cSWarner Losh switch (ccb->ccb_h.func_code) { 1543a31c31cSWarner Losh case XPT_CALC_GEOMETRY: /* Calculate Geometry Totally nuts ? XXX */ 1553a31c31cSWarner Losh /* 1563a31c31cSWarner Losh * Only meaningful for old-school SCSI disks since only the SCSI 1573a31c31cSWarner Losh * da driver generates them. Reject all these that slip through. 1583a31c31cSWarner Losh */ 1593a31c31cSWarner Losh /*FALLTHROUGH*/ 1603a31c31cSWarner Losh case XPT_ABORT: /* Abort the specified CCB */ 1613a31c31cSWarner Losh ccb->ccb_h.status = CAM_REQ_INVALID; 1623a31c31cSWarner Losh break; 1633a31c31cSWarner Losh case XPT_SET_TRAN_SETTINGS: 1643a31c31cSWarner Losh /* 1653a31c31cSWarner Losh * NVMe doesn't really have different transfer settings, but 1663a31c31cSWarner Losh * other parts of CAM think failure here is a big deal. 1673a31c31cSWarner Losh */ 1683a31c31cSWarner Losh ccb->ccb_h.status = CAM_REQ_CMP; 1693a31c31cSWarner Losh break; 1703a31c31cSWarner Losh case XPT_PATH_INQ: /* Path routing inquiry */ 1713a31c31cSWarner Losh { 1723a31c31cSWarner Losh struct ccb_pathinq *cpi = &ccb->cpi; 1734484c8f5SWarner Losh device_t dev = ctrlr->dev; 1743a31c31cSWarner Losh 1753a31c31cSWarner Losh cpi->version_num = 1; 1763a31c31cSWarner Losh cpi->hba_inquiry = 0; 1773a31c31cSWarner Losh cpi->target_sprt = 0; 178f439e3a4SAlexander Motin cpi->hba_misc = PIM_UNMAPPED | PIM_NOSCAN; 1793a31c31cSWarner Losh cpi->hba_eng_cnt = 0; 1803a31c31cSWarner Losh cpi->max_target = 0; 1813a31c31cSWarner Losh cpi->max_lun = ctrlr->cdata.nn; 182f439e3a4SAlexander Motin cpi->maxio = ctrlr->max_xfer_size; 1833a31c31cSWarner Losh cpi->initiator_id = 0; 1843a31c31cSWarner Losh cpi->bus_id = cam_sim_bus(sim); 1854e3b2744SWarner Losh cpi->base_transfer_speed = nvme_link_kBps(ctrlr); 1864195c7deSAlan Somers strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 1874195c7deSAlan Somers strlcpy(cpi->hba_vid, "NVMe", HBA_IDLEN); 1884195c7deSAlan Somers strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 1893a31c31cSWarner Losh cpi->unit_number = cam_sim_unit(sim); 1903a31c31cSWarner Losh cpi->transport = XPORT_NVME; /* XXX XPORT_PCIE ? */ 1914e3b2744SWarner Losh cpi->transport_version = nvme_mmio_read_4(ctrlr, vs); 1923a31c31cSWarner Losh cpi->protocol = PROTO_NVME; 1934e3b2744SWarner Losh cpi->protocol_version = nvme_mmio_read_4(ctrlr, vs); 194f439e3a4SAlexander Motin cpi->xport_specific.nvme.nsid = xpt_path_lun_id(ccb->ccb_h.path); 1954484c8f5SWarner Losh cpi->xport_specific.nvme.domain = pci_get_domain(dev); 1964484c8f5SWarner Losh cpi->xport_specific.nvme.bus = pci_get_bus(dev); 1974484c8f5SWarner Losh cpi->xport_specific.nvme.slot = pci_get_slot(dev); 1984484c8f5SWarner Losh cpi->xport_specific.nvme.function = pci_get_function(dev); 1994484c8f5SWarner Losh cpi->xport_specific.nvme.extra = 0; 200027d0612SWarner Losh strncpy(cpi->xport_specific.nvme.dev_name, device_get_nameunit(ctrlr->dev), 201027d0612SWarner Losh sizeof(cpi->xport_specific.nvme.dev_name)); 2023a31c31cSWarner Losh cpi->ccb_h.status = CAM_REQ_CMP; 2033a31c31cSWarner Losh break; 2043a31c31cSWarner Losh } 2053a31c31cSWarner Losh case XPT_GET_TRAN_SETTINGS: /* Get transport settings */ 2063a31c31cSWarner Losh { 2073a31c31cSWarner Losh struct ccb_trans_settings *cts; 2083a31c31cSWarner Losh struct ccb_trans_settings_nvme *nvmep; 2093a31c31cSWarner Losh struct ccb_trans_settings_nvme *nvmex; 2104e3b2744SWarner Losh device_t dev; 211b1f14710SChuck Tuffli uint32_t status, caps, flags; 2123a31c31cSWarner Losh 2134e3b2744SWarner Losh dev = ctrlr->dev; 2143a31c31cSWarner Losh cts = &ccb->cts; 2153a31c31cSWarner Losh nvmex = &cts->xport_specific.nvme; 2163a31c31cSWarner Losh nvmep = &cts->proto_specific.nvme; 2173a31c31cSWarner Losh 218eab9d0a8SWarner Losh status = pcie_read_config(dev, PCIER_LINK_STA, 2); 219eab9d0a8SWarner Losh caps = pcie_read_config(dev, PCIER_LINK_CAP, 2); 220b1f14710SChuck Tuffli flags = pcie_read_config(dev, PCIER_FLAGS, 2); 2214e3b2744SWarner Losh nvmex->spec = nvme_mmio_read_4(ctrlr, vs); 222b1f14710SChuck Tuffli nvmex->valid = CTS_NVME_VALID_SPEC; 223b1f14710SChuck Tuffli if ((flags & PCIEM_FLAGS_TYPE) == PCIEM_TYPE_ENDPOINT) { 224b1f14710SChuck Tuffli nvmex->valid |= CTS_NVME_VALID_LINK; 225eab9d0a8SWarner Losh nvmex->speed = status & PCIEM_LINK_STA_SPEED; 226eab9d0a8SWarner Losh nvmex->lanes = (status & PCIEM_LINK_STA_WIDTH) >> 4; 227eab9d0a8SWarner Losh nvmex->max_speed = caps & PCIEM_LINK_CAP_MAX_SPEED; 228eab9d0a8SWarner Losh nvmex->max_lanes = (caps & PCIEM_LINK_CAP_MAX_WIDTH) >> 4; 229b1f14710SChuck Tuffli } 2303a31c31cSWarner Losh 2314e3b2744SWarner Losh /* XXX these should be something else maybe ? */ 2324e3b2744SWarner Losh nvmep->valid = 1; 2334e3b2744SWarner Losh nvmep->spec = nvmex->spec; 2344e3b2744SWarner Losh 2353a31c31cSWarner Losh cts->transport = XPORT_NVME; 2363a31c31cSWarner Losh cts->protocol = PROTO_NVME; 2373a31c31cSWarner Losh cts->ccb_h.status = CAM_REQ_CMP; 2383a31c31cSWarner Losh break; 2393a31c31cSWarner Losh } 2403a31c31cSWarner Losh case XPT_TERM_IO: /* Terminate the I/O process */ 2413a31c31cSWarner Losh /* 2423a31c31cSWarner Losh * every driver handles this, but nothing generates it. Assume 2433a31c31cSWarner Losh * it's OK to just say 'that worked'. 2443a31c31cSWarner Losh */ 2453a31c31cSWarner Losh /*FALLTHROUGH*/ 2463a31c31cSWarner Losh case XPT_RESET_DEV: /* Bus Device Reset the specified device */ 2473a31c31cSWarner Losh case XPT_RESET_BUS: /* Reset the specified bus */ 2483a31c31cSWarner Losh /* 2493a31c31cSWarner Losh * NVMe doesn't really support physically resetting the bus. It's part 2503a31c31cSWarner Losh * of the bus scanning dance, so return sucess to tell the process to 2513a31c31cSWarner Losh * proceed. 2523a31c31cSWarner Losh */ 2533a31c31cSWarner Losh ccb->ccb_h.status = CAM_REQ_CMP; 2543a31c31cSWarner Losh break; 2553a31c31cSWarner Losh case XPT_NVME_IO: /* Execute the requested I/O operation */ 256df424515SWarner Losh case XPT_NVME_ADMIN: /* or Admin operation */ 2573a31c31cSWarner Losh nvme_sim_nvmeio(sim, ccb); 2583a31c31cSWarner Losh return; /* no done */ 2593a31c31cSWarner Losh default: 2603a31c31cSWarner Losh ccb->ccb_h.status = CAM_REQ_INVALID; 2613a31c31cSWarner Losh break; 2623a31c31cSWarner Losh } 2633a31c31cSWarner Losh xpt_done(ccb); 2643a31c31cSWarner Losh } 2653a31c31cSWarner Losh 2663a31c31cSWarner Losh static void 2673a31c31cSWarner Losh nvme_sim_poll(struct cam_sim *sim) 2683a31c31cSWarner Losh { 2693a31c31cSWarner Losh 27029431e54SWarner Losh nvme_ctrlr_poll(sim2ctrlr(sim)); 2713a31c31cSWarner Losh } 2723a31c31cSWarner Losh 2733a31c31cSWarner Losh static void * 2743a31c31cSWarner Losh nvme_sim_new_controller(struct nvme_controller *ctrlr) 2753a31c31cSWarner Losh { 276f439e3a4SAlexander Motin struct nvme_sim_softc *sc; 2773a31c31cSWarner Losh struct cam_devq *devq; 2783a31c31cSWarner Losh int max_trans; 2793a31c31cSWarner Losh 280c02565f9SWarner Losh max_trans = ctrlr->max_hw_pend_io; 2813a31c31cSWarner Losh devq = cam_simq_alloc(max_trans); 2823a31c31cSWarner Losh if (devq == NULL) 283f439e3a4SAlexander Motin return (NULL); 2843a31c31cSWarner Losh 2853a31c31cSWarner Losh sc = malloc(sizeof(*sc), M_NVME, M_ZERO | M_WAITOK); 2863a31c31cSWarner Losh sc->s_ctrlr = ctrlr; 2873a31c31cSWarner Losh 2883a31c31cSWarner Losh sc->s_sim = cam_sim_alloc(nvme_sim_action, nvme_sim_poll, 289f439e3a4SAlexander Motin "nvme", sc, device_get_unit(ctrlr->dev), 290511662d0SAlexander Motin NULL, max_trans, max_trans, devq); 2913a31c31cSWarner Losh if (sc->s_sim == NULL) { 2923a31c31cSWarner Losh printf("Failed to allocate a sim\n"); 2933a31c31cSWarner Losh cam_simq_free(devq); 294f439e3a4SAlexander Motin goto err1; 295f439e3a4SAlexander Motin } 296f439e3a4SAlexander Motin if (xpt_bus_register(sc->s_sim, ctrlr->dev, 0) != CAM_SUCCESS) { 297f439e3a4SAlexander Motin printf("Failed to create a bus\n"); 298f439e3a4SAlexander Motin goto err2; 299f439e3a4SAlexander Motin } 300f439e3a4SAlexander Motin if (xpt_create_path(&sc->s_path, /*periph*/NULL, cam_sim_path(sc->s_sim), 301f439e3a4SAlexander Motin CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 302f439e3a4SAlexander Motin printf("Failed to create a path\n"); 303f439e3a4SAlexander Motin goto err3; 304f439e3a4SAlexander Motin } 305f439e3a4SAlexander Motin 306f439e3a4SAlexander Motin return (sc); 307f439e3a4SAlexander Motin 308f439e3a4SAlexander Motin err3: 309f439e3a4SAlexander Motin xpt_bus_deregister(cam_sim_path(sc->s_sim)); 310f439e3a4SAlexander Motin err2: 311f439e3a4SAlexander Motin cam_sim_free(sc->s_sim, /*free_devq*/TRUE); 312f439e3a4SAlexander Motin err1: 3133a31c31cSWarner Losh free(sc, M_NVME); 314f439e3a4SAlexander Motin return (NULL); 3153a31c31cSWarner Losh } 3163a31c31cSWarner Losh 3173a31c31cSWarner Losh static void * 3183a31c31cSWarner Losh nvme_sim_new_ns(struct nvme_namespace *ns, void *sc_arg) 3193a31c31cSWarner Losh { 3203a31c31cSWarner Losh struct nvme_sim_softc *sc = sc_arg; 321f439e3a4SAlexander Motin union ccb *ccb; 3223a31c31cSWarner Losh 323f439e3a4SAlexander Motin ccb = xpt_alloc_ccb_nowait(); 324f439e3a4SAlexander Motin if (ccb == NULL) { 325f439e3a4SAlexander Motin printf("unable to alloc CCB for rescan\n"); 326f439e3a4SAlexander Motin return (NULL); 3273a31c31cSWarner Losh } 328f439e3a4SAlexander Motin 329*9cde7894SWarner Losh /* 330*9cde7894SWarner Losh * We map the NVMe namespace idea onto the CAM unit LUN. For 331*9cde7894SWarner Losh * each new namespace, we create a new CAM path for it. We then 332*9cde7894SWarner Losh * rescan the path to get it to enumerate. 333*9cde7894SWarner Losh */ 334f439e3a4SAlexander Motin if (xpt_create_path(&ccb->ccb_h.path, /*periph*/NULL, 335f439e3a4SAlexander Motin cam_sim_path(sc->s_sim), 0, ns->id) != CAM_REQ_CMP) { 336f439e3a4SAlexander Motin printf("unable to create path for rescan\n"); 337f439e3a4SAlexander Motin xpt_free_ccb(ccb); 338f439e3a4SAlexander Motin return (NULL); 339f439e3a4SAlexander Motin } 340f439e3a4SAlexander Motin xpt_rescan(ccb); 341f439e3a4SAlexander Motin 342f439e3a4SAlexander Motin return (ns); 3433a31c31cSWarner Losh } 3443a31c31cSWarner Losh 3453a31c31cSWarner Losh static void 3463a31c31cSWarner Losh nvme_sim_controller_fail(void *ctrlr_arg) 3473a31c31cSWarner Losh { 348f439e3a4SAlexander Motin struct nvme_sim_softc *sc = ctrlr_arg; 349f439e3a4SAlexander Motin 350f439e3a4SAlexander Motin xpt_async(AC_LOST_DEVICE, sc->s_path, NULL); 351f439e3a4SAlexander Motin xpt_free_path(sc->s_path); 352f439e3a4SAlexander Motin xpt_bus_deregister(cam_sim_path(sc->s_sim)); 353f439e3a4SAlexander Motin cam_sim_free(sc->s_sim, /*free_devq*/TRUE); 354f439e3a4SAlexander Motin free(sc, M_NVME); 3553a31c31cSWarner Losh } 3563a31c31cSWarner Losh 3573a31c31cSWarner Losh struct nvme_consumer *consumer_cookie; 3583a31c31cSWarner Losh 3593a31c31cSWarner Losh static void 3603a31c31cSWarner Losh nvme_sim_init(void) 3613a31c31cSWarner Losh { 3628a5d94f9SWarner Losh if (nvme_use_nvd) 3638a5d94f9SWarner Losh return; 3643a31c31cSWarner Losh 3653a31c31cSWarner Losh consumer_cookie = nvme_register_consumer(nvme_sim_new_ns, 3663a31c31cSWarner Losh nvme_sim_new_controller, NULL, nvme_sim_controller_fail); 3673a31c31cSWarner Losh } 3683a31c31cSWarner Losh 3693a31c31cSWarner Losh SYSINIT(nvme_sim_register, SI_SUB_DRIVERS, SI_ORDER_ANY, 3703a31c31cSWarner Losh nvme_sim_init, NULL); 3713a31c31cSWarner Losh 3723a31c31cSWarner Losh static void 3733a31c31cSWarner Losh nvme_sim_uninit(void) 3743a31c31cSWarner Losh { 3758a5d94f9SWarner Losh if (nvme_use_nvd) 3768a5d94f9SWarner Losh return; 3773a31c31cSWarner Losh /* XXX Cleanup */ 3783a31c31cSWarner Losh 3793a31c31cSWarner Losh nvme_unregister_consumer(consumer_cookie); 3803a31c31cSWarner Losh } 3813a31c31cSWarner Losh 3823a31c31cSWarner Losh SYSUNINIT(nvme_sim_unregister, SI_SUB_DRIVERS, SI_ORDER_ANY, 3833a31c31cSWarner Losh nvme_sim_uninit, NULL); 384