1baabaca3SWarner Losh /*- 2891c6986SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3f24882ecSPedro F. Giffuni * 4baabaca3SWarner Losh * Copyright (c) 2015 Netflix, Inc. 5baabaca3SWarner Losh * 6baabaca3SWarner Losh * Redistribution and use in source and binary forms, with or without 7baabaca3SWarner Losh * modification, are permitted provided that the following conditions 8baabaca3SWarner Losh * are met: 9baabaca3SWarner Losh * 1. Redistributions of source code must retain the above copyright 10891c6986SWarner Losh * notice, this list of conditions and the following disclaimer. 11baabaca3SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 12baabaca3SWarner Losh * notice, this list of conditions and the following disclaimer in the 13baabaca3SWarner Losh * documentation and/or other materials provided with the distribution. 14baabaca3SWarner Losh * 15891c6986SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16891c6986SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17891c6986SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18891c6986SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19891c6986SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20891c6986SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21891c6986SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22891c6986SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23891c6986SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24891c6986SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25891c6986SWarner Losh * SUCH DAMAGE. 26baabaca3SWarner Losh * 27baabaca3SWarner Losh * derived from ata_xpt.c: Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org> 28baabaca3SWarner Losh */ 29baabaca3SWarner Losh 30baabaca3SWarner Losh #include <sys/param.h> 31baabaca3SWarner Losh #include <sys/bus.h> 32baabaca3SWarner Losh #include <sys/endian.h> 33baabaca3SWarner Losh #include <sys/systm.h> 34baabaca3SWarner Losh #include <sys/types.h> 35baabaca3SWarner Losh #include <sys/malloc.h> 36baabaca3SWarner Losh #include <sys/kernel.h> 37baabaca3SWarner Losh #include <sys/time.h> 38baabaca3SWarner Losh #include <sys/conf.h> 39baabaca3SWarner Losh #include <sys/fcntl.h> 40baabaca3SWarner Losh #include <sys/sbuf.h> 41baabaca3SWarner Losh 42baabaca3SWarner Losh #include <sys/lock.h> 43baabaca3SWarner Losh #include <sys/mutex.h> 44baabaca3SWarner Losh #include <sys/sysctl.h> 45baabaca3SWarner Losh 46baabaca3SWarner Losh #include <cam/cam.h> 47baabaca3SWarner Losh #include <cam/cam_ccb.h> 48baabaca3SWarner Losh #include <cam/cam_queue.h> 49baabaca3SWarner Losh #include <cam/cam_periph.h> 50baabaca3SWarner Losh #include <cam/cam_sim.h> 51baabaca3SWarner Losh #include <cam/cam_xpt.h> 52baabaca3SWarner Losh #include <cam/cam_xpt_sim.h> 53baabaca3SWarner Losh #include <cam/cam_xpt_periph.h> 54baabaca3SWarner Losh #include <cam/cam_xpt_internal.h> 55baabaca3SWarner Losh #include <cam/cam_debug.h> 56baabaca3SWarner Losh 57baabaca3SWarner Losh #include <cam/scsi/scsi_all.h> 58baabaca3SWarner Losh #include <cam/scsi/scsi_message.h> 59baabaca3SWarner Losh #include <cam/nvme/nvme_all.h> 60baabaca3SWarner Losh #include <machine/stdarg.h> /* for xpt_print below */ 61baabaca3SWarner Losh 62baabaca3SWarner Losh struct nvme_quirk_entry { 63baabaca3SWarner Losh u_int quirks; 64baabaca3SWarner Losh #define CAM_QUIRK_MAXTAGS 1 65baabaca3SWarner Losh u_int mintags; 66baabaca3SWarner Losh u_int maxtags; 67baabaca3SWarner Losh }; 68baabaca3SWarner Losh 69baabaca3SWarner Losh /* Not even sure why we need this */ 70baabaca3SWarner Losh static periph_init_t nvme_probe_periph_init; 71baabaca3SWarner Losh 72baabaca3SWarner Losh static struct periph_driver nvme_probe_driver = 73baabaca3SWarner Losh { 74baabaca3SWarner Losh nvme_probe_periph_init, "nvme_probe", 75baabaca3SWarner Losh TAILQ_HEAD_INITIALIZER(nvme_probe_driver.units), /* generation */ 0, 76baabaca3SWarner Losh CAM_PERIPH_DRV_EARLY 77baabaca3SWarner Losh }; 78baabaca3SWarner Losh 79baabaca3SWarner Losh PERIPHDRIVER_DECLARE(nvme_probe, nvme_probe_driver); 80baabaca3SWarner Losh 81baabaca3SWarner Losh typedef enum { 82f439e3a4SAlexander Motin NVME_PROBE_IDENTIFY_CD, 83f439e3a4SAlexander Motin NVME_PROBE_IDENTIFY_NS, 84baabaca3SWarner Losh NVME_PROBE_DONE, 85f439e3a4SAlexander Motin NVME_PROBE_INVALID 86baabaca3SWarner Losh } nvme_probe_action; 87baabaca3SWarner Losh 88baabaca3SWarner Losh static char *nvme_probe_action_text[] = { 89f439e3a4SAlexander Motin "NVME_PROBE_IDENTIFY_CD", 90f439e3a4SAlexander Motin "NVME_PROBE_IDENTIFY_NS", 91baabaca3SWarner Losh "NVME_PROBE_DONE", 92f439e3a4SAlexander Motin "NVME_PROBE_INVALID" 93baabaca3SWarner Losh }; 94baabaca3SWarner Losh 95baabaca3SWarner Losh #define NVME_PROBE_SET_ACTION(softc, newaction) \ 96baabaca3SWarner Losh do { \ 97baabaca3SWarner Losh char **text; \ 98baabaca3SWarner Losh text = nvme_probe_action_text; \ 99baabaca3SWarner Losh CAM_DEBUG((softc)->periph->path, CAM_DEBUG_PROBE, \ 100baabaca3SWarner Losh ("Probe %s to %s\n", text[(softc)->action], \ 101baabaca3SWarner Losh text[(newaction)])); \ 102baabaca3SWarner Losh (softc)->action = (newaction); \ 103baabaca3SWarner Losh } while(0) 104baabaca3SWarner Losh 105baabaca3SWarner Losh typedef enum { 106baabaca3SWarner Losh NVME_PROBE_NO_ANNOUNCE = 0x04 107baabaca3SWarner Losh } nvme_probe_flags; 108baabaca3SWarner Losh 109baabaca3SWarner Losh typedef struct { 110baabaca3SWarner Losh TAILQ_HEAD(, ccb_hdr) request_ccbs; 111f439e3a4SAlexander Motin union { 112f439e3a4SAlexander Motin struct nvme_controller_data cd; 113f439e3a4SAlexander Motin struct nvme_namespace_data ns; 114f439e3a4SAlexander Motin }; 115baabaca3SWarner Losh nvme_probe_action action; 116baabaca3SWarner Losh nvme_probe_flags flags; 117baabaca3SWarner Losh int restart; 118baabaca3SWarner Losh struct cam_periph *periph; 119baabaca3SWarner Losh } nvme_probe_softc; 120baabaca3SWarner Losh 121baabaca3SWarner Losh static struct nvme_quirk_entry nvme_quirk_table[] = 122baabaca3SWarner Losh { 123baabaca3SWarner Losh { 124baabaca3SWarner Losh // { 125baabaca3SWarner Losh // T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 126baabaca3SWarner Losh // /*vendor*/"*", /*product*/"*", /*revision*/"*" 127baabaca3SWarner Losh // }, 128baabaca3SWarner Losh .quirks = 0, .mintags = 0, .maxtags = 0 129baabaca3SWarner Losh }, 130baabaca3SWarner Losh }; 131baabaca3SWarner Losh 132baabaca3SWarner Losh static const int nvme_quirk_table_size = 133baabaca3SWarner Losh sizeof(nvme_quirk_table) / sizeof(*nvme_quirk_table); 134baabaca3SWarner Losh 135baabaca3SWarner Losh static cam_status nvme_probe_register(struct cam_periph *periph, 136baabaca3SWarner Losh void *arg); 137baabaca3SWarner Losh static void nvme_probe_schedule(struct cam_periph *nvme_probe_periph); 138baabaca3SWarner Losh static void nvme_probe_start(struct cam_periph *periph, union ccb *start_ccb); 139f439e3a4SAlexander Motin static void nvme_probe_done(struct cam_periph *periph, union ccb *done_ccb); 140baabaca3SWarner Losh static void nvme_probe_cleanup(struct cam_periph *periph); 141f24c011bSWarner Losh //static void nvme_find_quirk(struct cam_ed *device); 142baabaca3SWarner Losh static void nvme_scan_lun(struct cam_periph *periph, 143baabaca3SWarner Losh struct cam_path *path, cam_flags flags, 144baabaca3SWarner Losh union ccb *ccb); 145baabaca3SWarner Losh static struct cam_ed * 146baabaca3SWarner Losh nvme_alloc_device(struct cam_eb *bus, struct cam_et *target, 147baabaca3SWarner Losh lun_id_t lun_id); 148baabaca3SWarner Losh static void nvme_device_transport(struct cam_path *path); 1497f85b11cSWarner Losh static void nvme_dev_async(uint32_t async_code, 150baabaca3SWarner Losh struct cam_eb *bus, 151baabaca3SWarner Losh struct cam_et *target, 152baabaca3SWarner Losh struct cam_ed *device, 153baabaca3SWarner Losh void *async_arg); 154baabaca3SWarner Losh static void nvme_action(union ccb *start_ccb); 1557eb53897SJohn Baldwin static void nvme_announce_periph_sbuf(struct cam_periph *periph, 1567eb53897SJohn Baldwin struct sbuf *sb); 1577eb53897SJohn Baldwin static void nvme_proto_announce_sbuf(struct cam_ed *device, 1587eb53897SJohn Baldwin struct sbuf *sb); 1597eb53897SJohn Baldwin static void nvme_proto_denounce_sbuf(struct cam_ed *device, 1607eb53897SJohn Baldwin struct sbuf *sb); 16108f13879SWarner Losh static void nvme_proto_debug_out(union ccb *ccb); 162baabaca3SWarner Losh 163ded2b706SWarner Losh static struct xpt_xport_ops nvme_xport_ops = { 164baabaca3SWarner Losh .alloc_device = nvme_alloc_device, 165baabaca3SWarner Losh .action = nvme_action, 166baabaca3SWarner Losh .async = nvme_dev_async, 1677eb53897SJohn Baldwin .announce_sbuf = nvme_announce_periph_sbuf, 168baabaca3SWarner Losh }; 169ded2b706SWarner Losh #define NVME_XPT_XPORT(x, X) \ 170ded2b706SWarner Losh static struct xpt_xport nvme_xport_ ## x = { \ 171ded2b706SWarner Losh .xport = XPORT_ ## X, \ 172ded2b706SWarner Losh .name = #x, \ 173ded2b706SWarner Losh .ops = &nvme_xport_ops, \ 174ded2b706SWarner Losh }; \ 175ded2b706SWarner Losh CAM_XPT_XPORT(nvme_xport_ ## x); 176baabaca3SWarner Losh 177ded2b706SWarner Losh NVME_XPT_XPORT(nvme, NVME); 178*07c6a62bSJohn Baldwin NVME_XPT_XPORT(nvmf, NVMF); 179e0ce51cbSWarner Losh 180ded2b706SWarner Losh #undef NVME_XPT_XPORT 181baabaca3SWarner Losh 18208f13879SWarner Losh static struct xpt_proto_ops nvme_proto_ops = { 1837eb53897SJohn Baldwin .announce_sbuf = nvme_proto_announce_sbuf, 1847eb53897SJohn Baldwin .denounce_sbuf = nvme_proto_denounce_sbuf, 18508f13879SWarner Losh .debug_out = nvme_proto_debug_out, 18608f13879SWarner Losh }; 18708f13879SWarner Losh static struct xpt_proto nvme_proto = { 18808f13879SWarner Losh .proto = PROTO_NVME, 18908f13879SWarner Losh .name = "nvme", 19008f13879SWarner Losh .ops = &nvme_proto_ops, 19108f13879SWarner Losh }; 19208f13879SWarner Losh CAM_XPT_PROTO(nvme_proto); 19308f13879SWarner Losh 194baabaca3SWarner Losh static void 1959982b3eeSConrad Meyer nvme_probe_periph_init(void) 196baabaca3SWarner Losh { 197baabaca3SWarner Losh } 198baabaca3SWarner Losh 199baabaca3SWarner Losh static cam_status 200baabaca3SWarner Losh nvme_probe_register(struct cam_periph *periph, void *arg) 201baabaca3SWarner Losh { 202baabaca3SWarner Losh union ccb *request_ccb; /* CCB representing the probe request */ 203baabaca3SWarner Losh nvme_probe_softc *softc; 204baabaca3SWarner Losh 205baabaca3SWarner Losh request_ccb = (union ccb *)arg; 206baabaca3SWarner Losh if (request_ccb == NULL) { 207baabaca3SWarner Losh printf("nvme_probe_register: no probe CCB, " 208baabaca3SWarner Losh "can't register device\n"); 209baabaca3SWarner Losh return(CAM_REQ_CMP_ERR); 210baabaca3SWarner Losh } 211baabaca3SWarner Losh 212baabaca3SWarner Losh softc = (nvme_probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_ZERO | M_NOWAIT); 213baabaca3SWarner Losh 214baabaca3SWarner Losh if (softc == NULL) { 215baabaca3SWarner Losh printf("nvme_probe_register: Unable to probe new device. " 216baabaca3SWarner Losh "Unable to allocate softc\n"); 217baabaca3SWarner Losh return(CAM_REQ_CMP_ERR); 218baabaca3SWarner Losh } 219baabaca3SWarner Losh TAILQ_INIT(&softc->request_ccbs); 220baabaca3SWarner Losh TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, 221baabaca3SWarner Losh periph_links.tqe); 222baabaca3SWarner Losh softc->flags = 0; 223baabaca3SWarner Losh periph->softc = softc; 224baabaca3SWarner Losh softc->periph = periph; 225baabaca3SWarner Losh softc->action = NVME_PROBE_INVALID; 22699e7a4adSScott Long if (cam_periph_acquire(periph) != 0) 22799e7a4adSScott Long return (CAM_REQ_CMP_ERR); 22899e7a4adSScott Long 229baabaca3SWarner Losh CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe started\n")); 230baabaca3SWarner Losh 231baabaca3SWarner Losh // nvme_device_transport(periph->path); 232baabaca3SWarner Losh nvme_probe_schedule(periph); 233baabaca3SWarner Losh 234baabaca3SWarner Losh return(CAM_REQ_CMP); 235baabaca3SWarner Losh } 236baabaca3SWarner Losh 237baabaca3SWarner Losh static void 238baabaca3SWarner Losh nvme_probe_schedule(struct cam_periph *periph) 239baabaca3SWarner Losh { 240baabaca3SWarner Losh union ccb *ccb; 241baabaca3SWarner Losh nvme_probe_softc *softc; 242baabaca3SWarner Losh 243baabaca3SWarner Losh softc = (nvme_probe_softc *)periph->softc; 244baabaca3SWarner Losh ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); 245baabaca3SWarner Losh 246f439e3a4SAlexander Motin NVME_PROBE_SET_ACTION(softc, NVME_PROBE_IDENTIFY_CD); 247baabaca3SWarner Losh 248baabaca3SWarner Losh if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE) 249baabaca3SWarner Losh softc->flags |= NVME_PROBE_NO_ANNOUNCE; 250baabaca3SWarner Losh else 251baabaca3SWarner Losh softc->flags &= ~NVME_PROBE_NO_ANNOUNCE; 252baabaca3SWarner Losh 253baabaca3SWarner Losh xpt_schedule(periph, CAM_PRIORITY_XPT); 254baabaca3SWarner Losh } 255baabaca3SWarner Losh 256baabaca3SWarner Losh static void 257baabaca3SWarner Losh nvme_probe_start(struct cam_periph *periph, union ccb *start_ccb) 258baabaca3SWarner Losh { 259baabaca3SWarner Losh struct ccb_nvmeio *nvmeio; 260baabaca3SWarner Losh nvme_probe_softc *softc; 261baabaca3SWarner Losh lun_id_t lun; 262baabaca3SWarner Losh 263baabaca3SWarner Losh CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("nvme_probe_start\n")); 264baabaca3SWarner Losh 265baabaca3SWarner Losh softc = (nvme_probe_softc *)periph->softc; 266baabaca3SWarner Losh nvmeio = &start_ccb->nvmeio; 267f439e3a4SAlexander Motin lun = xpt_path_lun_id(periph->path); 268baabaca3SWarner Losh 269baabaca3SWarner Losh if (softc->restart) { 270baabaca3SWarner Losh softc->restart = 0; 271f439e3a4SAlexander Motin NVME_PROBE_SET_ACTION(softc, NVME_PROBE_IDENTIFY_CD); 272baabaca3SWarner Losh } 273baabaca3SWarner Losh 274baabaca3SWarner Losh switch (softc->action) { 275f439e3a4SAlexander Motin case NVME_PROBE_IDENTIFY_CD: 276f439e3a4SAlexander Motin cam_fill_nvmeadmin(nvmeio, 277f439e3a4SAlexander Motin 0, /* retries */ 278f439e3a4SAlexander Motin nvme_probe_done, /* cbfcnp */ 279f439e3a4SAlexander Motin CAM_DIR_IN, /* flags */ 280f439e3a4SAlexander Motin (uint8_t *)&softc->cd, /* data_ptr */ 281f439e3a4SAlexander Motin sizeof(softc->cd), /* dxfer_len */ 282f439e3a4SAlexander Motin 30 * 1000); /* timeout 30s */ 283f439e3a4SAlexander Motin nvme_ns_cmd(nvmeio, NVME_OPC_IDENTIFY, 0, 284f439e3a4SAlexander Motin 1, 0, 0, 0, 0, 0); 285f439e3a4SAlexander Motin break; 286f439e3a4SAlexander Motin case NVME_PROBE_IDENTIFY_NS: 287f439e3a4SAlexander Motin cam_fill_nvmeadmin(nvmeio, 288f439e3a4SAlexander Motin 0, /* retries */ 289f439e3a4SAlexander Motin nvme_probe_done, /* cbfcnp */ 290f439e3a4SAlexander Motin CAM_DIR_IN, /* flags */ 291f439e3a4SAlexander Motin (uint8_t *)&softc->ns, /* data_ptr */ 292f439e3a4SAlexander Motin sizeof(softc->ns), /* dxfer_len */ 293f439e3a4SAlexander Motin 30 * 1000); /* timeout 30s */ 294f439e3a4SAlexander Motin nvme_ns_cmd(nvmeio, NVME_OPC_IDENTIFY, lun, 295f439e3a4SAlexander Motin 0, 0, 0, 0, 0, 0); 296baabaca3SWarner Losh break; 297baabaca3SWarner Losh default: 298baabaca3SWarner Losh panic("nvme_probe_start: invalid action state 0x%x\n", softc->action); 299baabaca3SWarner Losh } 300f439e3a4SAlexander Motin start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 301f439e3a4SAlexander Motin xpt_action(start_ccb); 302baabaca3SWarner Losh } 303f439e3a4SAlexander Motin 304f439e3a4SAlexander Motin static void 305f439e3a4SAlexander Motin nvme_probe_done(struct cam_periph *periph, union ccb *done_ccb) 306f439e3a4SAlexander Motin { 307f439e3a4SAlexander Motin struct nvme_namespace_data *nvme_data; 308f439e3a4SAlexander Motin struct nvme_controller_data *nvme_cdata; 309f439e3a4SAlexander Motin nvme_probe_softc *softc; 310f439e3a4SAlexander Motin struct cam_path *path; 311654f53abSAlexander Motin struct scsi_vpd_device_id *did; 312654f53abSAlexander Motin struct scsi_vpd_id_descriptor *idd; 3137f85b11cSWarner Losh uint32_t priority; 314654f53abSAlexander Motin int found = 1, e, g, len; 315f439e3a4SAlexander Motin 316f439e3a4SAlexander Motin CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("nvme_probe_done\n")); 317f439e3a4SAlexander Motin 318f439e3a4SAlexander Motin softc = (nvme_probe_softc *)periph->softc; 319f439e3a4SAlexander Motin path = done_ccb->ccb_h.path; 320f439e3a4SAlexander Motin priority = done_ccb->ccb_h.pinfo.priority; 321f439e3a4SAlexander Motin 322f439e3a4SAlexander Motin if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 323f439e3a4SAlexander Motin if (cam_periph_error(done_ccb, 324f439e3a4SAlexander Motin 0, softc->restart ? (SF_NO_RECOVERY | SF_NO_RETRY) : 0 325f439e3a4SAlexander Motin ) == ERESTART) { 326f439e3a4SAlexander Motin out: 327f439e3a4SAlexander Motin /* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */ 328f439e3a4SAlexander Motin cam_release_devq(path, 0, 0, 0, FALSE); 329f439e3a4SAlexander Motin return; 330f439e3a4SAlexander Motin } 331f439e3a4SAlexander Motin if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 332f439e3a4SAlexander Motin /* Don't wedge the queue */ 333f439e3a4SAlexander Motin xpt_release_devq(path, /*count*/1, /*run_queue*/TRUE); 334f439e3a4SAlexander Motin } 335f439e3a4SAlexander Motin 336f439e3a4SAlexander Motin /* 337f439e3a4SAlexander Motin * If we get to this point, we got an error status back 338f439e3a4SAlexander Motin * from the inquiry and the error status doesn't require 339f439e3a4SAlexander Motin * automatically retrying the command. Therefore, the 340f439e3a4SAlexander Motin * inquiry failed. If we had inquiry information before 341f439e3a4SAlexander Motin * for this device, but this latest inquiry command failed, 342f439e3a4SAlexander Motin * the device has probably gone away. If this device isn't 343f439e3a4SAlexander Motin * already marked unconfigured, notify the peripheral 344f439e3a4SAlexander Motin * drivers that this device is no more. 345f439e3a4SAlexander Motin */ 346f439e3a4SAlexander Motin device_fail: if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) 347f439e3a4SAlexander Motin xpt_async(AC_LOST_DEVICE, path, NULL); 348f439e3a4SAlexander Motin NVME_PROBE_SET_ACTION(softc, NVME_PROBE_INVALID); 349f439e3a4SAlexander Motin found = 0; 350f439e3a4SAlexander Motin goto done; 351f439e3a4SAlexander Motin } 352f439e3a4SAlexander Motin if (softc->restart) 353f439e3a4SAlexander Motin goto done; 354f439e3a4SAlexander Motin switch (softc->action) { 355f439e3a4SAlexander Motin case NVME_PROBE_IDENTIFY_CD: 356f439e3a4SAlexander Motin nvme_controller_data_swapbytes(&softc->cd); 357f439e3a4SAlexander Motin 358f439e3a4SAlexander Motin nvme_cdata = path->device->nvme_cdata; 359f439e3a4SAlexander Motin if (nvme_cdata == NULL) { 360f439e3a4SAlexander Motin nvme_cdata = malloc(sizeof(*nvme_cdata), M_CAMXPT, 361f439e3a4SAlexander Motin M_NOWAIT); 362f439e3a4SAlexander Motin if (nvme_cdata == NULL) { 363f439e3a4SAlexander Motin xpt_print(path, "Can't allocate memory"); 364f439e3a4SAlexander Motin goto device_fail; 365f439e3a4SAlexander Motin } 366f439e3a4SAlexander Motin } 367f439e3a4SAlexander Motin bcopy(&softc->cd, nvme_cdata, sizeof(*nvme_cdata)); 368f439e3a4SAlexander Motin path->device->nvme_cdata = nvme_cdata; 369f439e3a4SAlexander Motin 370654f53abSAlexander Motin /* Save/update serial number. */ 371654f53abSAlexander Motin if (path->device->serial_num != NULL) { 372654f53abSAlexander Motin free(path->device->serial_num, M_CAMXPT); 373654f53abSAlexander Motin path->device->serial_num = NULL; 374654f53abSAlexander Motin path->device->serial_num_len = 0; 375654f53abSAlexander Motin } 3767f85b11cSWarner Losh path->device->serial_num = (uint8_t *) 377654f53abSAlexander Motin malloc(NVME_SERIAL_NUMBER_LENGTH + 1, M_CAMXPT, M_NOWAIT); 378654f53abSAlexander Motin if (path->device->serial_num != NULL) { 3793090d504SKenneth D. Merry cam_strvis_flag(path->device->serial_num, 3803090d504SKenneth D. Merry nvme_cdata->sn, sizeof(nvme_cdata->sn), 3813090d504SKenneth D. Merry NVME_SERIAL_NUMBER_LENGTH + 1, 3823090d504SKenneth D. Merry CAM_STRVIS_FLAG_NONASCII_SPC); 3833090d504SKenneth D. Merry 384654f53abSAlexander Motin path->device->serial_num_len = 385654f53abSAlexander Motin strlen(path->device->serial_num); 386654f53abSAlexander Motin } 387654f53abSAlexander Motin 388f439e3a4SAlexander Motin // nvme_find_quirk(path->device); 389f439e3a4SAlexander Motin nvme_device_transport(path); 390f439e3a4SAlexander Motin NVME_PROBE_SET_ACTION(softc, NVME_PROBE_IDENTIFY_NS); 391f439e3a4SAlexander Motin xpt_release_ccb(done_ccb); 392f439e3a4SAlexander Motin xpt_schedule(periph, priority); 393f439e3a4SAlexander Motin goto out; 394f439e3a4SAlexander Motin case NVME_PROBE_IDENTIFY_NS: 395f439e3a4SAlexander Motin nvme_namespace_data_swapbytes(&softc->ns); 396f439e3a4SAlexander Motin 397f439e3a4SAlexander Motin /* Check that the namespace exists. */ 398f439e3a4SAlexander Motin if (softc->ns.nsze == 0) 399f439e3a4SAlexander Motin goto device_fail; 400f439e3a4SAlexander Motin 401f439e3a4SAlexander Motin nvme_data = path->device->nvme_data; 402f439e3a4SAlexander Motin if (nvme_data == NULL) { 403f439e3a4SAlexander Motin nvme_data = malloc(sizeof(*nvme_data), M_CAMXPT, 404f439e3a4SAlexander Motin M_NOWAIT); 405f439e3a4SAlexander Motin if (nvme_data == NULL) { 406f439e3a4SAlexander Motin xpt_print(path, "Can't allocate memory"); 407f439e3a4SAlexander Motin goto device_fail; 408f439e3a4SAlexander Motin } 409f439e3a4SAlexander Motin } 410f439e3a4SAlexander Motin bcopy(&softc->ns, nvme_data, sizeof(*nvme_data)); 411f439e3a4SAlexander Motin path->device->nvme_data = nvme_data; 412f439e3a4SAlexander Motin 413654f53abSAlexander Motin /* Save/update device_id based on NGUID and/or EUI64. */ 414654f53abSAlexander Motin if (path->device->device_id != NULL) { 415654f53abSAlexander Motin free(path->device->device_id, M_CAMXPT); 416654f53abSAlexander Motin path->device->device_id = NULL; 417654f53abSAlexander Motin path->device->device_id_len = 0; 418654f53abSAlexander Motin } 419654f53abSAlexander Motin len = 0; 420654f53abSAlexander Motin for (g = 0; g < sizeof(nvme_data->nguid); g++) { 421654f53abSAlexander Motin if (nvme_data->nguid[g] != 0) 422654f53abSAlexander Motin break; 423654f53abSAlexander Motin } 424654f53abSAlexander Motin if (g < sizeof(nvme_data->nguid)) 425654f53abSAlexander Motin len += sizeof(struct scsi_vpd_id_descriptor) + 16; 426654f53abSAlexander Motin for (e = 0; e < sizeof(nvme_data->eui64); e++) { 427654f53abSAlexander Motin if (nvme_data->eui64[e] != 0) 428654f53abSAlexander Motin break; 429654f53abSAlexander Motin } 430654f53abSAlexander Motin if (e < sizeof(nvme_data->eui64)) 431654f53abSAlexander Motin len += sizeof(struct scsi_vpd_id_descriptor) + 8; 432654f53abSAlexander Motin if (len > 0) { 4337f85b11cSWarner Losh path->device->device_id = (uint8_t *) 434654f53abSAlexander Motin malloc(SVPD_DEVICE_ID_HDR_LEN + len, 435654f53abSAlexander Motin M_CAMXPT, M_NOWAIT); 436654f53abSAlexander Motin } 437654f53abSAlexander Motin if (path->device->device_id != NULL) { 438654f53abSAlexander Motin did = (struct scsi_vpd_device_id *)path->device->device_id; 439654f53abSAlexander Motin did->device = SID_QUAL_LU_CONNECTED | T_DIRECT; 440654f53abSAlexander Motin did->page_code = SVPD_DEVICE_ID; 441654f53abSAlexander Motin scsi_ulto2b(len, did->length); 442654f53abSAlexander Motin idd = (struct scsi_vpd_id_descriptor *)(did + 1); 443654f53abSAlexander Motin if (g < sizeof(nvme_data->nguid)) { 444654f53abSAlexander Motin idd->proto_codeset = SVPD_ID_CODESET_BINARY; 445654f53abSAlexander Motin idd->id_type = SVPD_ID_ASSOC_LUN | SVPD_ID_TYPE_EUI64; 446654f53abSAlexander Motin idd->length = 16; 447654f53abSAlexander Motin bcopy(nvme_data->nguid, idd->identifier, 16); 448654f53abSAlexander Motin idd = (struct scsi_vpd_id_descriptor *) 449654f53abSAlexander Motin &idd->identifier[16]; 450654f53abSAlexander Motin } 451654f53abSAlexander Motin if (e < sizeof(nvme_data->eui64)) { 452654f53abSAlexander Motin idd->proto_codeset = SVPD_ID_CODESET_BINARY; 453654f53abSAlexander Motin idd->id_type = SVPD_ID_ASSOC_LUN | SVPD_ID_TYPE_EUI64; 454654f53abSAlexander Motin idd->length = 8; 455654f53abSAlexander Motin bcopy(nvme_data->eui64, idd->identifier, 8); 456654f53abSAlexander Motin } 457654f53abSAlexander Motin path->device->device_id_len = SVPD_DEVICE_ID_HDR_LEN + len; 458654f53abSAlexander Motin } 459654f53abSAlexander Motin 460f439e3a4SAlexander Motin if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) { 461f439e3a4SAlexander Motin path->device->flags &= ~CAM_DEV_UNCONFIGURED; 462f439e3a4SAlexander Motin xpt_acquire_device(path->device); 463f439e3a4SAlexander Motin done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 464f439e3a4SAlexander Motin xpt_action(done_ccb); 465f439e3a4SAlexander Motin xpt_async(AC_FOUND_DEVICE, path, done_ccb); 466f439e3a4SAlexander Motin } 467f439e3a4SAlexander Motin NVME_PROBE_SET_ACTION(softc, NVME_PROBE_DONE); 468f439e3a4SAlexander Motin break; 469f439e3a4SAlexander Motin default: 470f439e3a4SAlexander Motin panic("nvme_probe_done: invalid action state 0x%x\n", softc->action); 471f439e3a4SAlexander Motin } 472f439e3a4SAlexander Motin done: 473f439e3a4SAlexander Motin if (softc->restart) { 474f439e3a4SAlexander Motin softc->restart = 0; 475f439e3a4SAlexander Motin xpt_release_ccb(done_ccb); 476f439e3a4SAlexander Motin nvme_probe_schedule(periph); 477f439e3a4SAlexander Motin goto out; 478f439e3a4SAlexander Motin } 479f439e3a4SAlexander Motin xpt_release_ccb(done_ccb); 480f439e3a4SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe completed\n")); 481f439e3a4SAlexander Motin while ((done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs))) { 482f439e3a4SAlexander Motin TAILQ_REMOVE(&softc->request_ccbs, 483f439e3a4SAlexander Motin &done_ccb->ccb_h, periph_links.tqe); 484f439e3a4SAlexander Motin done_ccb->ccb_h.status = found ? CAM_REQ_CMP : CAM_REQ_CMP_ERR; 485f439e3a4SAlexander Motin xpt_done(done_ccb); 486f439e3a4SAlexander Motin } 487f439e3a4SAlexander Motin /* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */ 488f439e3a4SAlexander Motin cam_release_devq(path, 0, 0, 0, FALSE); 489baabaca3SWarner Losh cam_periph_invalidate(periph); 490876f6a6aSScott Long cam_periph_release_locked(periph); 491baabaca3SWarner Losh } 492baabaca3SWarner Losh 493baabaca3SWarner Losh static void 494baabaca3SWarner Losh nvme_probe_cleanup(struct cam_periph *periph) 495baabaca3SWarner Losh { 496e0ce51cbSWarner Losh 497baabaca3SWarner Losh free(periph->softc, M_CAMXPT); 498baabaca3SWarner Losh } 499baabaca3SWarner Losh 500f24c011bSWarner Losh #if 0 501baabaca3SWarner Losh /* XXX should be used, don't delete */ 502baabaca3SWarner Losh static void 503baabaca3SWarner Losh nvme_find_quirk(struct cam_ed *device) 504baabaca3SWarner Losh { 505baabaca3SWarner Losh struct nvme_quirk_entry *quirk; 506baabaca3SWarner Losh caddr_t match; 507baabaca3SWarner Losh 508baabaca3SWarner Losh match = cam_quirkmatch((caddr_t)&device->nvme_data, 509baabaca3SWarner Losh (caddr_t)nvme_quirk_table, 510baabaca3SWarner Losh nvme_quirk_table_size, 511baabaca3SWarner Losh sizeof(*nvme_quirk_table), nvme_identify_match); 512baabaca3SWarner Losh 513baabaca3SWarner Losh if (match == NULL) 514baabaca3SWarner Losh panic("xpt_find_quirk: device didn't match wildcard entry!!"); 515baabaca3SWarner Losh 516baabaca3SWarner Losh quirk = (struct nvme_quirk_entry *)match; 517baabaca3SWarner Losh device->quirk = quirk; 518baabaca3SWarner Losh if (quirk->quirks & CAM_QUIRK_MAXTAGS) { 519baabaca3SWarner Losh device->mintags = quirk->mintags; 520baabaca3SWarner Losh device->maxtags = quirk->maxtags; 521baabaca3SWarner Losh } 522baabaca3SWarner Losh } 523f24c011bSWarner Losh #endif 524baabaca3SWarner Losh 525baabaca3SWarner Losh static void 526baabaca3SWarner Losh nvme_scan_lun(struct cam_periph *periph, struct cam_path *path, 527baabaca3SWarner Losh cam_flags flags, union ccb *request_ccb) 528baabaca3SWarner Losh { 529baabaca3SWarner Losh struct ccb_pathinq cpi; 530baabaca3SWarner Losh cam_status status; 531baabaca3SWarner Losh struct cam_periph *old_periph; 532baabaca3SWarner Losh int lock; 533baabaca3SWarner Losh 534baabaca3SWarner Losh CAM_DEBUG(path, CAM_DEBUG_TRACE, ("nvme_scan_lun\n")); 535baabaca3SWarner Losh 536762a7f4fSWarner Losh xpt_path_inq(&cpi, path); 537baabaca3SWarner Losh 538baabaca3SWarner Losh if (cpi.ccb_h.status != CAM_REQ_CMP) { 539baabaca3SWarner Losh if (request_ccb != NULL) { 540baabaca3SWarner Losh request_ccb->ccb_h.status = cpi.ccb_h.status; 541baabaca3SWarner Losh xpt_done(request_ccb); 542baabaca3SWarner Losh } 543baabaca3SWarner Losh return; 544baabaca3SWarner Losh } 545baabaca3SWarner Losh 546baabaca3SWarner Losh if (xpt_path_lun_id(path) == CAM_LUN_WILDCARD) { 547baabaca3SWarner Losh CAM_DEBUG(path, CAM_DEBUG_TRACE, ("nvme_scan_lun ignoring bus\n")); 548baabaca3SWarner Losh request_ccb->ccb_h.status = CAM_REQ_CMP; /* XXX signal error ? */ 549baabaca3SWarner Losh xpt_done(request_ccb); 550baabaca3SWarner Losh return; 551baabaca3SWarner Losh } 552baabaca3SWarner Losh 553baabaca3SWarner Losh lock = (xpt_path_owned(path) == 0); 554baabaca3SWarner Losh if (lock) 555baabaca3SWarner Losh xpt_path_lock(path); 556baabaca3SWarner Losh if ((old_periph = cam_periph_find(path, "nvme_probe")) != NULL) { 557baabaca3SWarner Losh if ((old_periph->flags & CAM_PERIPH_INVALID) == 0) { 558baabaca3SWarner Losh nvme_probe_softc *softc; 559baabaca3SWarner Losh 560baabaca3SWarner Losh softc = (nvme_probe_softc *)old_periph->softc; 561baabaca3SWarner Losh TAILQ_INSERT_TAIL(&softc->request_ccbs, 562baabaca3SWarner Losh &request_ccb->ccb_h, periph_links.tqe); 563baabaca3SWarner Losh softc->restart = 1; 564baabaca3SWarner Losh CAM_DEBUG(path, CAM_DEBUG_TRACE, 565baabaca3SWarner Losh ("restarting nvme_probe device\n")); 566baabaca3SWarner Losh } else { 567baabaca3SWarner Losh request_ccb->ccb_h.status = CAM_REQ_CMP_ERR; 568baabaca3SWarner Losh CAM_DEBUG(path, CAM_DEBUG_TRACE, 569baabaca3SWarner Losh ("Failing to restart nvme_probe device\n")); 570baabaca3SWarner Losh xpt_done(request_ccb); 571baabaca3SWarner Losh } 572baabaca3SWarner Losh } else { 573baabaca3SWarner Losh CAM_DEBUG(path, CAM_DEBUG_TRACE, 574baabaca3SWarner Losh ("Adding nvme_probe device\n")); 575baabaca3SWarner Losh status = cam_periph_alloc(nvme_probe_register, NULL, nvme_probe_cleanup, 576baabaca3SWarner Losh nvme_probe_start, "nvme_probe", 577baabaca3SWarner Losh CAM_PERIPH_BIO, 578baabaca3SWarner Losh request_ccb->ccb_h.path, NULL, 0, 579baabaca3SWarner Losh request_ccb); 580baabaca3SWarner Losh 581baabaca3SWarner Losh if (status != CAM_REQ_CMP) { 582baabaca3SWarner Losh xpt_print(path, "xpt_scan_lun: cam_alloc_periph " 583baabaca3SWarner Losh "returned an error, can't continue probe\n"); 584baabaca3SWarner Losh request_ccb->ccb_h.status = status; 585baabaca3SWarner Losh xpt_done(request_ccb); 586baabaca3SWarner Losh } 587baabaca3SWarner Losh } 588baabaca3SWarner Losh if (lock) 589baabaca3SWarner Losh xpt_path_unlock(path); 590baabaca3SWarner Losh } 591baabaca3SWarner Losh 592baabaca3SWarner Losh static struct cam_ed * 593baabaca3SWarner Losh nvme_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) 594baabaca3SWarner Losh { 595baabaca3SWarner Losh struct nvme_quirk_entry *quirk; 596baabaca3SWarner Losh struct cam_ed *device; 597baabaca3SWarner Losh 598baabaca3SWarner Losh device = xpt_alloc_device(bus, target, lun_id); 599baabaca3SWarner Losh if (device == NULL) 600baabaca3SWarner Losh return (NULL); 601baabaca3SWarner Losh 602baabaca3SWarner Losh /* 603baabaca3SWarner Losh * Take the default quirk entry until we have inquiry 604baabaca3SWarner Losh * data from nvme and can determine a better quirk to use. 605baabaca3SWarner Losh */ 606baabaca3SWarner Losh quirk = &nvme_quirk_table[nvme_quirk_table_size - 1]; 607baabaca3SWarner Losh device->quirk = (void *)quirk; 608baabaca3SWarner Losh device->mintags = 0; 609baabaca3SWarner Losh device->maxtags = 0; 610baabaca3SWarner Losh device->inq_flags = 0; 611baabaca3SWarner Losh device->queue_flags = 0; 612654f53abSAlexander Motin device->device_id = NULL; 613baabaca3SWarner Losh device->device_id_len = 0; 614654f53abSAlexander Motin device->serial_num = NULL; 615baabaca3SWarner Losh device->serial_num_len = 0; 616baabaca3SWarner Losh return (device); 617baabaca3SWarner Losh } 618baabaca3SWarner Losh 619baabaca3SWarner Losh static void 620baabaca3SWarner Losh nvme_device_transport(struct cam_path *path) 621baabaca3SWarner Losh { 622baabaca3SWarner Losh struct ccb_pathinq cpi; 623baabaca3SWarner Losh struct ccb_trans_settings cts; 624baabaca3SWarner Losh /* XXX get data from nvme namespace and other info ??? */ 625baabaca3SWarner Losh 626baabaca3SWarner Losh /* Get transport information from the SIM */ 627762a7f4fSWarner Losh xpt_path_inq(&cpi, path); 628baabaca3SWarner Losh 629baabaca3SWarner Losh path->device->transport = cpi.transport; 630baabaca3SWarner Losh path->device->transport_version = cpi.transport_version; 631baabaca3SWarner Losh 632baabaca3SWarner Losh path->device->protocol = cpi.protocol; 633baabaca3SWarner Losh path->device->protocol_version = cpi.protocol_version; 634baabaca3SWarner Losh 635baabaca3SWarner Losh /* Tell the controller what we think */ 636ec5325dbSEdward Tomasz Napierala memset(&cts, 0, sizeof(cts)); 637baabaca3SWarner Losh xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 638baabaca3SWarner Losh cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 639baabaca3SWarner Losh cts.type = CTS_TYPE_CURRENT_SETTINGS; 640baabaca3SWarner Losh cts.transport = path->device->transport; 641baabaca3SWarner Losh cts.transport_version = path->device->transport_version; 642baabaca3SWarner Losh cts.protocol = path->device->protocol; 643baabaca3SWarner Losh cts.protocol_version = path->device->protocol_version; 644baabaca3SWarner Losh cts.proto_specific.valid = 0; 645baabaca3SWarner Losh cts.xport_specific.valid = 0; 646baabaca3SWarner Losh xpt_action((union ccb *)&cts); 647baabaca3SWarner Losh } 648baabaca3SWarner Losh 649baabaca3SWarner Losh static void 650baabaca3SWarner Losh nvme_dev_advinfo(union ccb *start_ccb) 651baabaca3SWarner Losh { 652baabaca3SWarner Losh struct cam_ed *device; 653baabaca3SWarner Losh struct ccb_dev_advinfo *cdai; 654baabaca3SWarner Losh off_t amt; 655baabaca3SWarner Losh 6566a216c0bSAlexander Motin xpt_path_assert(start_ccb->ccb_h.path, MA_OWNED); 657baabaca3SWarner Losh start_ccb->ccb_h.status = CAM_REQ_INVALID; 658baabaca3SWarner Losh device = start_ccb->ccb_h.path->device; 659baabaca3SWarner Losh cdai = &start_ccb->cdai; 660baabaca3SWarner Losh switch(cdai->buftype) { 661baabaca3SWarner Losh case CDAI_TYPE_SCSI_DEVID: 662baabaca3SWarner Losh if (cdai->flags & CDAI_FLAG_STORE) 663baabaca3SWarner Losh return; 664baabaca3SWarner Losh cdai->provsiz = device->device_id_len; 665baabaca3SWarner Losh if (device->device_id_len == 0) 666baabaca3SWarner Losh break; 667baabaca3SWarner Losh amt = device->device_id_len; 668baabaca3SWarner Losh if (cdai->provsiz > cdai->bufsiz) 669baabaca3SWarner Losh amt = cdai->bufsiz; 670baabaca3SWarner Losh memcpy(cdai->buf, device->device_id, amt); 671baabaca3SWarner Losh break; 672baabaca3SWarner Losh case CDAI_TYPE_SERIAL_NUM: 673baabaca3SWarner Losh if (cdai->flags & CDAI_FLAG_STORE) 674baabaca3SWarner Losh return; 675baabaca3SWarner Losh cdai->provsiz = device->serial_num_len; 676baabaca3SWarner Losh if (device->serial_num_len == 0) 677baabaca3SWarner Losh break; 678baabaca3SWarner Losh amt = device->serial_num_len; 679baabaca3SWarner Losh if (cdai->provsiz > cdai->bufsiz) 680baabaca3SWarner Losh amt = cdai->bufsiz; 681baabaca3SWarner Losh memcpy(cdai->buf, device->serial_num, amt); 682baabaca3SWarner Losh break; 683baabaca3SWarner Losh case CDAI_TYPE_PHYS_PATH: 684baabaca3SWarner Losh if (cdai->flags & CDAI_FLAG_STORE) { 685431ddd94SYoung Xiao if (device->physpath != NULL) { 686baabaca3SWarner Losh free(device->physpath, M_CAMXPT); 687431ddd94SYoung Xiao device->physpath = NULL; 688431ddd94SYoung Xiao device->physpath_len = 0; 689431ddd94SYoung Xiao } 690baabaca3SWarner Losh /* Clear existing buffer if zero length */ 691baabaca3SWarner Losh if (cdai->bufsiz == 0) 692baabaca3SWarner Losh break; 693baabaca3SWarner Losh device->physpath = malloc(cdai->bufsiz, M_CAMXPT, M_NOWAIT); 694baabaca3SWarner Losh if (device->physpath == NULL) { 695baabaca3SWarner Losh start_ccb->ccb_h.status = CAM_REQ_ABORTED; 696baabaca3SWarner Losh return; 697baabaca3SWarner Losh } 698431ddd94SYoung Xiao device->physpath_len = cdai->bufsiz; 699baabaca3SWarner Losh memcpy(device->physpath, cdai->buf, cdai->bufsiz); 700baabaca3SWarner Losh } else { 701baabaca3SWarner Losh cdai->provsiz = device->physpath_len; 702baabaca3SWarner Losh if (device->physpath_len == 0) 703baabaca3SWarner Losh break; 704baabaca3SWarner Losh amt = device->physpath_len; 705baabaca3SWarner Losh if (cdai->provsiz > cdai->bufsiz) 706baabaca3SWarner Losh amt = cdai->bufsiz; 707baabaca3SWarner Losh memcpy(cdai->buf, device->physpath, amt); 708baabaca3SWarner Losh } 709baabaca3SWarner Losh break; 7109f8ed7e4SWarner Losh case CDAI_TYPE_NVME_CNTRL: 7119f8ed7e4SWarner Losh if (cdai->flags & CDAI_FLAG_STORE) 7129f8ed7e4SWarner Losh return; 7139f8ed7e4SWarner Losh amt = sizeof(struct nvme_controller_data); 7149f8ed7e4SWarner Losh cdai->provsiz = amt; 7159f8ed7e4SWarner Losh if (amt > cdai->bufsiz) 7169f8ed7e4SWarner Losh amt = cdai->bufsiz; 7179f8ed7e4SWarner Losh memcpy(cdai->buf, device->nvme_cdata, amt); 7189f8ed7e4SWarner Losh break; 7199f8ed7e4SWarner Losh case CDAI_TYPE_NVME_NS: 7209f8ed7e4SWarner Losh if (cdai->flags & CDAI_FLAG_STORE) 7219f8ed7e4SWarner Losh return; 7229f8ed7e4SWarner Losh amt = sizeof(struct nvme_namespace_data); 7239f8ed7e4SWarner Losh cdai->provsiz = amt; 7249f8ed7e4SWarner Losh if (amt > cdai->bufsiz) 7259f8ed7e4SWarner Losh amt = cdai->bufsiz; 7269f8ed7e4SWarner Losh memcpy(cdai->buf, device->nvme_data, amt); 7279f8ed7e4SWarner Losh break; 728baabaca3SWarner Losh default: 729baabaca3SWarner Losh return; 730baabaca3SWarner Losh } 731baabaca3SWarner Losh start_ccb->ccb_h.status = CAM_REQ_CMP; 732baabaca3SWarner Losh 733baabaca3SWarner Losh if (cdai->flags & CDAI_FLAG_STORE) { 734baabaca3SWarner Losh xpt_async(AC_ADVINFO_CHANGED, start_ccb->ccb_h.path, 735baabaca3SWarner Losh (void *)(uintptr_t)cdai->buftype); 736baabaca3SWarner Losh } 737baabaca3SWarner Losh } 738baabaca3SWarner Losh 739baabaca3SWarner Losh static void 740baabaca3SWarner Losh nvme_action(union ccb *start_ccb) 741baabaca3SWarner Losh { 742baabaca3SWarner Losh CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, 743baabaca3SWarner Losh ("nvme_action: func= %#x\n", start_ccb->ccb_h.func_code)); 744baabaca3SWarner Losh 745baabaca3SWarner Losh switch (start_ccb->ccb_h.func_code) { 746baabaca3SWarner Losh case XPT_SCAN_BUS: 747baabaca3SWarner Losh case XPT_SCAN_TGT: 748baabaca3SWarner Losh case XPT_SCAN_LUN: 749baabaca3SWarner Losh nvme_scan_lun(start_ccb->ccb_h.path->periph, 750baabaca3SWarner Losh start_ccb->ccb_h.path, start_ccb->crcn.flags, 751baabaca3SWarner Losh start_ccb); 752baabaca3SWarner Losh break; 753baabaca3SWarner Losh case XPT_DEV_ADVINFO: 754baabaca3SWarner Losh nvme_dev_advinfo(start_ccb); 755baabaca3SWarner Losh break; 756baabaca3SWarner Losh 757baabaca3SWarner Losh default: 758baabaca3SWarner Losh xpt_action_default(start_ccb); 759baabaca3SWarner Losh break; 760baabaca3SWarner Losh } 761baabaca3SWarner Losh } 762baabaca3SWarner Losh 763baabaca3SWarner Losh /* 764baabaca3SWarner Losh * Handle any per-device event notifications that require action by the XPT. 765baabaca3SWarner Losh */ 766baabaca3SWarner Losh static void 7677f85b11cSWarner Losh nvme_dev_async(uint32_t async_code, struct cam_eb *bus, struct cam_et *target, 768baabaca3SWarner Losh struct cam_ed *device, void *async_arg) 769baabaca3SWarner Losh { 770baabaca3SWarner Losh 771baabaca3SWarner Losh /* 772baabaca3SWarner Losh * We only need to handle events for real devices. 773baabaca3SWarner Losh */ 774baabaca3SWarner Losh if (target->target_id == CAM_TARGET_WILDCARD 775baabaca3SWarner Losh || device->lun_id == CAM_LUN_WILDCARD) 776baabaca3SWarner Losh return; 777baabaca3SWarner Losh 778baabaca3SWarner Losh if (async_code == AC_LOST_DEVICE && 779baabaca3SWarner Losh (device->flags & CAM_DEV_UNCONFIGURED) == 0) { 780baabaca3SWarner Losh device->flags |= CAM_DEV_UNCONFIGURED; 781baabaca3SWarner Losh xpt_release_device(device); 782baabaca3SWarner Losh } 783baabaca3SWarner Losh } 784baabaca3SWarner Losh 785baabaca3SWarner Losh static void 7867eb53897SJohn Baldwin nvme_announce_periph_sbuf(struct cam_periph *periph, struct sbuf *sb) 787baabaca3SWarner Losh { 788baabaca3SWarner Losh struct ccb_pathinq cpi; 789baabaca3SWarner Losh struct ccb_trans_settings cts; 790baabaca3SWarner Losh struct cam_path *path = periph->path; 7915e8a39f6SWarner Losh struct ccb_trans_settings_nvme *nvmex; 792baabaca3SWarner Losh 793baabaca3SWarner Losh cam_periph_assert(periph, MA_OWNED); 794baabaca3SWarner Losh 7955e8a39f6SWarner Losh /* Ask the SIM for connection details */ 796ec5325dbSEdward Tomasz Napierala memset(&cts, 0, sizeof(cts)); 797baabaca3SWarner Losh xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL); 798baabaca3SWarner Losh cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 799baabaca3SWarner Losh cts.type = CTS_TYPE_CURRENT_SETTINGS; 800baabaca3SWarner Losh xpt_action((union ccb*)&cts); 801baabaca3SWarner Losh if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 802baabaca3SWarner Losh return; 8035e8a39f6SWarner Losh 804baabaca3SWarner Losh /* Ask the SIM for its base transfer speed */ 805762a7f4fSWarner Losh xpt_path_inq(&cpi, periph->path); 8067eb53897SJohn Baldwin sbuf_printf(sb, "%s%d: nvme version %d.%d", 8075e8a39f6SWarner Losh periph->periph_name, periph->unit_number, 808af296130SJohn Baldwin NVME_MAJOR(cts.protocol_version), 809af296130SJohn Baldwin NVME_MINOR(cts.protocol_version)); 810af296130SJohn Baldwin if (cts.transport == XPORT_NVME) { 811af296130SJohn Baldwin nvmex = &cts.proto_specific.nvme; 812b1f14710SChuck Tuffli if (nvmex->valid & CTS_NVME_VALID_LINK) 8137eb53897SJohn Baldwin sbuf_printf(sb, 814af296130SJohn Baldwin " x%d (max x%d) lanes PCIe Gen%d (max Gen%d) link", 8155e8a39f6SWarner Losh nvmex->lanes, nvmex->max_lanes, 8165e8a39f6SWarner Losh nvmex->speed, nvmex->max_speed); 817af296130SJohn Baldwin } 818519b24f0SAlexander Motin sbuf_putc(sb, '\n'); 8197eb53897SJohn Baldwin } 8207eb53897SJohn Baldwin 8217eb53897SJohn Baldwin static void 8227eb53897SJohn Baldwin nvme_proto_announce_sbuf(struct cam_ed *device, struct sbuf *sb) 8237eb53897SJohn Baldwin { 8247eb53897SJohn Baldwin nvme_print_ident(device->nvme_cdata, device->nvme_data, sb); 8257eb53897SJohn Baldwin } 8267eb53897SJohn Baldwin 8277eb53897SJohn Baldwin static void 8287eb53897SJohn Baldwin nvme_proto_denounce_sbuf(struct cam_ed *device, struct sbuf *sb) 8297eb53897SJohn Baldwin { 8307eb53897SJohn Baldwin nvme_print_ident_short(device->nvme_cdata, device->nvme_data, sb); 8317eb53897SJohn Baldwin } 8327eb53897SJohn Baldwin 8337eb53897SJohn Baldwin static void 83408f13879SWarner Losh nvme_proto_debug_out(union ccb *ccb) 83508f13879SWarner Losh { 83608f13879SWarner Losh char cdb_str[(sizeof(struct nvme_command) * 3) + 1]; 83708f13879SWarner Losh 8389c91a265SAlexander Motin if (ccb->ccb_h.func_code != XPT_NVME_IO && 839e40d8dbbSAlexander Motin ccb->ccb_h.func_code != XPT_NVME_ADMIN) 84008f13879SWarner Losh return; 84108f13879SWarner Losh 84208f13879SWarner Losh CAM_DEBUG(ccb->ccb_h.path, 843e40d8dbbSAlexander Motin CAM_DEBUG_CDB,("%s. NCB: %s\n", nvme_op_string(&ccb->nvmeio.cmd, 844e40d8dbbSAlexander Motin ccb->ccb_h.func_code == XPT_NVME_ADMIN), 84508f13879SWarner Losh nvme_cmd_string(&ccb->nvmeio.cmd, cdb_str, sizeof(cdb_str)))); 84608f13879SWarner Losh } 847