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 1758f079322SWarner Losh /* 1768f079322SWarner Losh * For devices that are reported as children of the AHCI 1778f079322SWarner Losh * controller, which has no access to the config space for this 1788f079322SWarner Losh * controller, report the AHCI controller's data. 1798f079322SWarner Losh */ 1808f079322SWarner Losh if (ctrlr->quirks & QUIRK_AHCI) 1818f079322SWarner Losh dev = device_get_parent(dev); 1823a31c31cSWarner Losh cpi->version_num = 1; 1833a31c31cSWarner Losh cpi->hba_inquiry = 0; 1843a31c31cSWarner Losh cpi->target_sprt = 0; 185f439e3a4SAlexander Motin cpi->hba_misc = PIM_UNMAPPED | PIM_NOSCAN; 1863a31c31cSWarner Losh cpi->hba_eng_cnt = 0; 1873a31c31cSWarner Losh cpi->max_target = 0; 1883a31c31cSWarner Losh cpi->max_lun = ctrlr->cdata.nn; 189f439e3a4SAlexander Motin cpi->maxio = ctrlr->max_xfer_size; 1903a31c31cSWarner Losh cpi->initiator_id = 0; 1913a31c31cSWarner Losh cpi->bus_id = cam_sim_bus(sim); 1924e3b2744SWarner Losh cpi->base_transfer_speed = nvme_link_kBps(ctrlr); 1934195c7deSAlan Somers strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 1944195c7deSAlan Somers strlcpy(cpi->hba_vid, "NVMe", HBA_IDLEN); 1954195c7deSAlan Somers strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 1963a31c31cSWarner Losh cpi->unit_number = cam_sim_unit(sim); 1973a31c31cSWarner Losh cpi->transport = XPORT_NVME; /* XXX XPORT_PCIE ? */ 1984e3b2744SWarner Losh cpi->transport_version = nvme_mmio_read_4(ctrlr, vs); 1993a31c31cSWarner Losh cpi->protocol = PROTO_NVME; 2004e3b2744SWarner Losh cpi->protocol_version = nvme_mmio_read_4(ctrlr, vs); 201f439e3a4SAlexander Motin cpi->xport_specific.nvme.nsid = xpt_path_lun_id(ccb->ccb_h.path); 2024484c8f5SWarner Losh cpi->xport_specific.nvme.domain = pci_get_domain(dev); 2034484c8f5SWarner Losh cpi->xport_specific.nvme.bus = pci_get_bus(dev); 2044484c8f5SWarner Losh cpi->xport_specific.nvme.slot = pci_get_slot(dev); 2054484c8f5SWarner Losh cpi->xport_specific.nvme.function = pci_get_function(dev); 2064484c8f5SWarner Losh cpi->xport_specific.nvme.extra = 0; 20797dc595dSAlexander Motin strncpy(cpi->xport_specific.nvme.dev_name, device_get_nameunit(dev), 208027d0612SWarner Losh sizeof(cpi->xport_specific.nvme.dev_name)); 20997dc595dSAlexander Motin cpi->hba_vendor = pci_get_vendor(dev); 21097dc595dSAlexander Motin cpi->hba_device = pci_get_device(dev); 21197dc595dSAlexander Motin cpi->hba_subvendor = pci_get_subvendor(dev); 21297dc595dSAlexander Motin cpi->hba_subdevice = pci_get_subdevice(dev); 2133a31c31cSWarner Losh cpi->ccb_h.status = CAM_REQ_CMP; 2143a31c31cSWarner Losh break; 2153a31c31cSWarner Losh } 2163a31c31cSWarner Losh case XPT_GET_TRAN_SETTINGS: /* Get transport settings */ 2173a31c31cSWarner Losh { 2183a31c31cSWarner Losh struct ccb_trans_settings *cts; 2193a31c31cSWarner Losh struct ccb_trans_settings_nvme *nvmep; 2203a31c31cSWarner Losh struct ccb_trans_settings_nvme *nvmex; 2214e3b2744SWarner Losh device_t dev; 222b1f14710SChuck Tuffli uint32_t status, caps, flags; 2233a31c31cSWarner Losh 2244e3b2744SWarner Losh dev = ctrlr->dev; 2253a31c31cSWarner Losh cts = &ccb->cts; 2263a31c31cSWarner Losh nvmex = &cts->xport_specific.nvme; 2273a31c31cSWarner Losh nvmep = &cts->proto_specific.nvme; 2283a31c31cSWarner Losh 2298f079322SWarner Losh nvmex->spec = nvme_mmio_read_4(ctrlr, vs); 2308f079322SWarner Losh nvmex->valid = CTS_NVME_VALID_SPEC; 2318f079322SWarner Losh if ((ctrlr->quirks & QUIRK_AHCI) == 0) { 2328f079322SWarner Losh /* AHCI redirect makes it impossible to query */ 233eab9d0a8SWarner Losh status = pcie_read_config(dev, PCIER_LINK_STA, 2); 234eab9d0a8SWarner Losh caps = pcie_read_config(dev, PCIER_LINK_CAP, 2); 235b1f14710SChuck Tuffli flags = pcie_read_config(dev, PCIER_FLAGS, 2); 236b1f14710SChuck Tuffli if ((flags & PCIEM_FLAGS_TYPE) == PCIEM_TYPE_ENDPOINT) { 237b1f14710SChuck Tuffli nvmex->valid |= CTS_NVME_VALID_LINK; 238eab9d0a8SWarner Losh nvmex->speed = status & PCIEM_LINK_STA_SPEED; 239eab9d0a8SWarner Losh nvmex->lanes = (status & PCIEM_LINK_STA_WIDTH) >> 4; 240eab9d0a8SWarner Losh nvmex->max_speed = caps & PCIEM_LINK_CAP_MAX_SPEED; 241eab9d0a8SWarner Losh nvmex->max_lanes = (caps & PCIEM_LINK_CAP_MAX_WIDTH) >> 4; 242b1f14710SChuck Tuffli } 2438f079322SWarner Losh } 2443a31c31cSWarner Losh 2454e3b2744SWarner Losh /* XXX these should be something else maybe ? */ 246*9c2203a6SJohn Baldwin nvmep->valid = CTS_NVME_VALID_SPEC; 2474e3b2744SWarner Losh nvmep->spec = nvmex->spec; 2484e3b2744SWarner Losh 2493a31c31cSWarner Losh cts->transport = XPORT_NVME; 250*9c2203a6SJohn Baldwin cts->transport_version = nvmex->spec; 2513a31c31cSWarner Losh cts->protocol = PROTO_NVME; 252*9c2203a6SJohn Baldwin cts->protocol_version = nvmex->spec; 2533a31c31cSWarner Losh cts->ccb_h.status = CAM_REQ_CMP; 2543a31c31cSWarner Losh break; 2553a31c31cSWarner Losh } 2563a31c31cSWarner Losh case XPT_TERM_IO: /* Terminate the I/O process */ 2573a31c31cSWarner Losh /* 2583a31c31cSWarner Losh * every driver handles this, but nothing generates it. Assume 2593a31c31cSWarner Losh * it's OK to just say 'that worked'. 2603a31c31cSWarner Losh */ 2613a31c31cSWarner Losh /*FALLTHROUGH*/ 2623a31c31cSWarner Losh case XPT_RESET_DEV: /* Bus Device Reset the specified device */ 2633a31c31cSWarner Losh case XPT_RESET_BUS: /* Reset the specified bus */ 2643a31c31cSWarner Losh /* 2653a31c31cSWarner Losh * NVMe doesn't really support physically resetting the bus. It's part 2663a31c31cSWarner Losh * of the bus scanning dance, so return sucess to tell the process to 2673a31c31cSWarner Losh * proceed. 2683a31c31cSWarner Losh */ 2693a31c31cSWarner Losh ccb->ccb_h.status = CAM_REQ_CMP; 2703a31c31cSWarner Losh break; 2713a31c31cSWarner Losh case XPT_NVME_IO: /* Execute the requested I/O operation */ 272df424515SWarner Losh case XPT_NVME_ADMIN: /* or Admin operation */ 2734b977e6dSWarner Losh if (ctrlr->is_failed) { 2744b977e6dSWarner Losh ccb->ccb_h.status = CAM_DEV_NOT_THERE; 2754b977e6dSWarner Losh break; 2764b977e6dSWarner Losh } 2773a31c31cSWarner Losh nvme_sim_nvmeio(sim, ccb); 2783a31c31cSWarner Losh return; /* no done */ 2793a31c31cSWarner Losh default: 2803a31c31cSWarner Losh ccb->ccb_h.status = CAM_REQ_INVALID; 2813a31c31cSWarner Losh break; 2823a31c31cSWarner Losh } 2833a31c31cSWarner Losh xpt_done(ccb); 2843a31c31cSWarner Losh } 2853a31c31cSWarner Losh 2863a31c31cSWarner Losh static void 2873a31c31cSWarner Losh nvme_sim_poll(struct cam_sim *sim) 2883a31c31cSWarner Losh { 2893a31c31cSWarner Losh 29029431e54SWarner Losh nvme_ctrlr_poll(sim2ctrlr(sim)); 2913a31c31cSWarner Losh } 2923a31c31cSWarner Losh 2933a31c31cSWarner Losh static void * 2943a31c31cSWarner Losh nvme_sim_new_controller(struct nvme_controller *ctrlr) 2953a31c31cSWarner Losh { 296f439e3a4SAlexander Motin struct nvme_sim_softc *sc; 2973a31c31cSWarner Losh struct cam_devq *devq; 2983a31c31cSWarner Losh int max_trans; 2993a31c31cSWarner Losh 300c02565f9SWarner Losh max_trans = ctrlr->max_hw_pend_io; 3013a31c31cSWarner Losh devq = cam_simq_alloc(max_trans); 3023a31c31cSWarner Losh if (devq == NULL) 303f439e3a4SAlexander Motin return (NULL); 3043a31c31cSWarner Losh 3053a31c31cSWarner Losh sc = malloc(sizeof(*sc), M_NVME, M_ZERO | M_WAITOK); 3063a31c31cSWarner Losh sc->s_ctrlr = ctrlr; 3073a31c31cSWarner Losh 3083a31c31cSWarner Losh sc->s_sim = cam_sim_alloc(nvme_sim_action, nvme_sim_poll, 309f439e3a4SAlexander Motin "nvme", sc, device_get_unit(ctrlr->dev), 310511662d0SAlexander Motin NULL, max_trans, max_trans, devq); 3113a31c31cSWarner Losh if (sc->s_sim == NULL) { 3123a31c31cSWarner Losh printf("Failed to allocate a sim\n"); 3133a31c31cSWarner Losh cam_simq_free(devq); 314f439e3a4SAlexander Motin goto err1; 315f439e3a4SAlexander Motin } 316f439e3a4SAlexander Motin if (xpt_bus_register(sc->s_sim, ctrlr->dev, 0) != CAM_SUCCESS) { 317f439e3a4SAlexander Motin printf("Failed to create a bus\n"); 318f439e3a4SAlexander Motin goto err2; 319f439e3a4SAlexander Motin } 320f439e3a4SAlexander Motin if (xpt_create_path(&sc->s_path, /*periph*/NULL, cam_sim_path(sc->s_sim), 321f439e3a4SAlexander Motin CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 322f439e3a4SAlexander Motin printf("Failed to create a path\n"); 323f439e3a4SAlexander Motin goto err3; 324f439e3a4SAlexander Motin } 325f439e3a4SAlexander Motin 326f439e3a4SAlexander Motin return (sc); 327f439e3a4SAlexander Motin 328f439e3a4SAlexander Motin err3: 329f439e3a4SAlexander Motin xpt_bus_deregister(cam_sim_path(sc->s_sim)); 330f439e3a4SAlexander Motin err2: 331f439e3a4SAlexander Motin cam_sim_free(sc->s_sim, /*free_devq*/TRUE); 332f439e3a4SAlexander Motin err1: 3333a31c31cSWarner Losh free(sc, M_NVME); 334f439e3a4SAlexander Motin return (NULL); 3353a31c31cSWarner Losh } 3363a31c31cSWarner Losh 3373a31c31cSWarner Losh static void * 338950475caSWarner Losh nvme_sim_ns_change(struct nvme_namespace *ns, void *sc_arg) 3393a31c31cSWarner Losh { 3403a31c31cSWarner Losh struct nvme_sim_softc *sc = sc_arg; 341f439e3a4SAlexander Motin union ccb *ccb; 3423a31c31cSWarner Losh 343f439e3a4SAlexander Motin ccb = xpt_alloc_ccb_nowait(); 344f439e3a4SAlexander Motin if (ccb == NULL) { 345f439e3a4SAlexander Motin printf("unable to alloc CCB for rescan\n"); 346f439e3a4SAlexander Motin return (NULL); 3473a31c31cSWarner Losh } 348f439e3a4SAlexander Motin 3499cde7894SWarner Losh /* 3509cde7894SWarner Losh * We map the NVMe namespace idea onto the CAM unit LUN. For 3519cde7894SWarner Losh * each new namespace, we create a new CAM path for it. We then 3529cde7894SWarner Losh * rescan the path to get it to enumerate. 3539cde7894SWarner Losh */ 354f439e3a4SAlexander Motin if (xpt_create_path(&ccb->ccb_h.path, /*periph*/NULL, 355f439e3a4SAlexander Motin cam_sim_path(sc->s_sim), 0, ns->id) != CAM_REQ_CMP) { 356f439e3a4SAlexander Motin printf("unable to create path for rescan\n"); 357f439e3a4SAlexander Motin xpt_free_ccb(ccb); 358f439e3a4SAlexander Motin return (NULL); 359f439e3a4SAlexander Motin } 360f439e3a4SAlexander Motin xpt_rescan(ccb); 361f439e3a4SAlexander Motin 362950475caSWarner Losh return (sc_arg); 3633a31c31cSWarner Losh } 3643a31c31cSWarner Losh 3653a31c31cSWarner Losh static void 3663a31c31cSWarner Losh nvme_sim_controller_fail(void *ctrlr_arg) 3673a31c31cSWarner Losh { 368f439e3a4SAlexander Motin struct nvme_sim_softc *sc = ctrlr_arg; 369f439e3a4SAlexander Motin 370f439e3a4SAlexander Motin xpt_async(AC_LOST_DEVICE, sc->s_path, NULL); 371f439e3a4SAlexander Motin xpt_free_path(sc->s_path); 372f439e3a4SAlexander Motin xpt_bus_deregister(cam_sim_path(sc->s_sim)); 373f439e3a4SAlexander Motin cam_sim_free(sc->s_sim, /*free_devq*/TRUE); 374f439e3a4SAlexander Motin free(sc, M_NVME); 3753a31c31cSWarner Losh } 3763a31c31cSWarner Losh 3773a31c31cSWarner Losh struct nvme_consumer *consumer_cookie; 3783a31c31cSWarner Losh 3793a31c31cSWarner Losh static void 3803a31c31cSWarner Losh nvme_sim_init(void) 3813a31c31cSWarner Losh { 3828a5d94f9SWarner Losh if (nvme_use_nvd) 3838a5d94f9SWarner Losh return; 3843a31c31cSWarner Losh 385950475caSWarner Losh consumer_cookie = nvme_register_consumer(nvme_sim_ns_change, 3863a31c31cSWarner Losh nvme_sim_new_controller, NULL, nvme_sim_controller_fail); 3873a31c31cSWarner Losh } 3883a31c31cSWarner Losh 3893a31c31cSWarner Losh SYSINIT(nvme_sim_register, SI_SUB_DRIVERS, SI_ORDER_ANY, 3903a31c31cSWarner Losh nvme_sim_init, NULL); 3913a31c31cSWarner Losh 3923a31c31cSWarner Losh static void 3933a31c31cSWarner Losh nvme_sim_uninit(void) 3943a31c31cSWarner Losh { 3958a5d94f9SWarner Losh if (nvme_use_nvd) 3968a5d94f9SWarner Losh return; 3973a31c31cSWarner Losh /* XXX Cleanup */ 3983a31c31cSWarner Losh 3993a31c31cSWarner Losh nvme_unregister_consumer(consumer_cookie); 4003a31c31cSWarner Losh } 4013a31c31cSWarner Losh 4023a31c31cSWarner Losh SYSUNINIT(nvme_sim_unregister, SI_SUB_DRIVERS, SI_ORDER_ANY, 4033a31c31cSWarner Losh nvme_sim_uninit, NULL); 404