1 /* 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2020-2025, Broadcom Inc. All rights reserved. 5 * Support: <fbsd-storage-driver.pdl@broadcom.com> 6 * 7 * Authors: Sumit Saxena <sumit.saxena@broadcom.com> 8 * Chandrakanth Patil <chandrakanth.patil@broadcom.com> 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions are 12 * met: 13 * 14 * 1. Redistributions of source code must retain the above copyright notice, 15 * this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright notice, 17 * this list of conditions and the following disclaimer in the documentation and/or other 18 * materials provided with the distribution. 19 * 3. Neither the name of the Broadcom Inc. nor the names of its contributors 20 * may be used to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 * 35 * The views and conclusions contained in the software and documentation are 36 * those of the authors and should not be interpreted as representing 37 * official policies,either expressed or implied, of the FreeBSD Project. 38 * 39 * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 40 * 41 * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD 42 */ 43 44 #include "mpi3mr.h" 45 #include "mpi3mr_cam.h" 46 #include "mpi3mr_app.h" 47 48 static int sc_ids; 49 static int mpi3mr_pci_probe(device_t); 50 static int mpi3mr_pci_attach(device_t); 51 static int mpi3mr_pci_detach(device_t); 52 static int mpi3mr_pci_suspend(device_t); 53 static int mpi3mr_pci_resume(device_t); 54 static int mpi3mr_setup_resources(struct mpi3mr_softc *sc); 55 static void mpi3mr_release_resources(struct mpi3mr_softc *); 56 static void mpi3mr_teardown_irqs(struct mpi3mr_softc *sc); 57 58 extern void mpi3mr_watchdog_thread(void *arg); 59 60 static device_method_t mpi3mr_methods[] = { 61 DEVMETHOD(device_probe, mpi3mr_pci_probe), 62 DEVMETHOD(device_attach, mpi3mr_pci_attach), 63 DEVMETHOD(device_detach, mpi3mr_pci_detach), 64 DEVMETHOD(device_suspend, mpi3mr_pci_suspend), 65 DEVMETHOD(device_resume, mpi3mr_pci_resume), 66 DEVMETHOD(bus_print_child, bus_generic_print_child), 67 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 68 { 0, 0 } 69 }; 70 71 char fmt_os_ver[16]; 72 73 SYSCTL_NODE(_hw, OID_AUTO, mpi3mr, CTLFLAG_RD, 0, "MPI3MR Driver Parameters"); 74 MALLOC_DEFINE(M_MPI3MR, "mpi3mrbuf", "Buffers for the MPI3MR driver"); 75 76 static driver_t mpi3mr_pci_driver = { 77 "mpi3mr", 78 mpi3mr_methods, 79 sizeof(struct mpi3mr_softc) 80 }; 81 82 struct mpi3mr_ident { 83 uint16_t vendor; 84 uint16_t device; 85 uint16_t subvendor; 86 uint16_t subdevice; 87 u_int flags; 88 const char *desc; 89 } mpi3mr_identifiers[] = { 90 { MPI3_MFGPAGE_VENDORID_BROADCOM, MPI3_MFGPAGE_DEVID_SAS4116, 91 0xffff, 0xffff, 0, "Broadcom MPIMR 3.0 controller" }, 92 { 0 } 93 }; 94 95 DRIVER_MODULE(mpi3mr, pci, mpi3mr_pci_driver, 0, 0); 96 MODULE_PNP_INFO("U16:vendor;U16:device;U16:subvendor;U16:subdevice;D:#", pci, 97 mpi3mr, mpi3mr_identifiers, nitems(mpi3mr_identifiers) - 1); 98 99 MODULE_DEPEND(mpi3mr, cam, 1, 1, 1); 100 101 /* 102 * mpi3mr_setup_sysctl: setup sysctl values for mpi3mr 103 * input: Adapter instance soft state 104 * 105 * Setup sysctl entries for mpi3mr driver. 106 */ 107 static void 108 mpi3mr_setup_sysctl(struct mpi3mr_softc *sc) 109 { 110 struct sysctl_ctx_list *sysctl_ctx = NULL; 111 struct sysctl_oid *sysctl_tree = NULL; 112 char tmpstr[80], tmpstr2[80]; 113 114 /* 115 * Setup the sysctl variable so the user can change the debug level 116 * on the fly. 117 */ 118 snprintf(tmpstr, sizeof(tmpstr), "MPI3MR controller %d", 119 device_get_unit(sc->mpi3mr_dev)); 120 snprintf(tmpstr2, sizeof(tmpstr2), "%d", device_get_unit(sc->mpi3mr_dev)); 121 122 sysctl_ctx = device_get_sysctl_ctx(sc->mpi3mr_dev); 123 if (sysctl_ctx != NULL) 124 sysctl_tree = device_get_sysctl_tree(sc->mpi3mr_dev); 125 126 if (sysctl_tree == NULL) { 127 sysctl_ctx_init(&sc->sysctl_ctx); 128 sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 129 SYSCTL_STATIC_CHILDREN(_hw_mpi3mr), OID_AUTO, tmpstr2, 130 CTLFLAG_RD, 0, tmpstr); 131 if (sc->sysctl_tree == NULL) 132 return; 133 sysctl_ctx = &sc->sysctl_ctx; 134 sysctl_tree = sc->sysctl_tree; 135 } 136 137 SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 138 OID_AUTO, "driver_version", CTLFLAG_RD, MPI3MR_DRIVER_VERSION, 139 strlen(MPI3MR_DRIVER_VERSION), "driver version"); 140 141 SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 142 OID_AUTO, "fw_outstanding", CTLFLAG_RD, 143 &sc->fw_outstanding.val_rdonly, 0, "FW outstanding commands"); 144 145 SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 146 OID_AUTO, "io_cmds_highwater", CTLFLAG_RD, 147 &sc->io_cmds_highwater, 0, "Max FW outstanding commands"); 148 149 SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 150 OID_AUTO, "firmware_version", CTLFLAG_RD, sc->fw_version, 151 strlen(sc->fw_version), "firmware version"); 152 153 SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 154 OID_AUTO, "mpi3mr_debug", CTLFLAG_RW, &sc->mpi3mr_debug, 0, 155 "Driver debug level"); 156 SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 157 OID_AUTO, "reset", CTLFLAG_RW, &sc->reset.type, 0, 158 "Soft reset(1)/Diag reset(2)"); 159 SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 160 OID_AUTO, "iot_enable", CTLFLAG_RW, &sc->iot_enable, 0, 161 "IO throttling enable at driver level(for debug purpose)"); 162 } 163 164 /* 165 * mpi3mr_get_tunables: get tunable parameters. 166 * input: Adapter instance soft state 167 * 168 * Get tunable parameters. This will help to debug driver at boot time. 169 */ 170 static void 171 mpi3mr_get_tunables(struct mpi3mr_softc *sc) 172 { 173 char tmpstr[80]; 174 175 sc->mpi3mr_debug = 176 (MPI3MR_ERROR | MPI3MR_INFO | MPI3MR_FAULT); 177 178 sc->reset_in_progress = 0; 179 sc->reset.type = 0; 180 sc->iot_enable = 1; 181 sc->max_sgl_entries = maxphys / PAGE_SIZE; 182 183 /* 184 * Grab the global variables. 185 */ 186 TUNABLE_INT_FETCH("hw.mpi3mr.debug_level", &sc->mpi3mr_debug); 187 TUNABLE_INT_FETCH("hw.mpi3mr.ctrl_reset", &sc->reset.type); 188 TUNABLE_INT_FETCH("hw.mpi3mr.iot_enable", &sc->iot_enable); 189 TUNABLE_INT_FETCH("hw.mpi3mr.max_sgl_entries", &sc->max_sgl_entries); 190 191 /* Grab the unit-instance variables */ 192 snprintf(tmpstr, sizeof(tmpstr), "dev.mpi3mr.%d.debug_level", 193 device_get_unit(sc->mpi3mr_dev)); 194 TUNABLE_INT_FETCH(tmpstr, &sc->mpi3mr_debug); 195 196 snprintf(tmpstr, sizeof(tmpstr), "dev.mpi3mr.%d.reset", 197 device_get_unit(sc->mpi3mr_dev)); 198 TUNABLE_INT_FETCH(tmpstr, &sc->reset.type); 199 200 snprintf(tmpstr, sizeof(tmpstr), "dev.mpi3mr.%d.iot_enable", 201 device_get_unit(sc->mpi3mr_dev)); 202 TUNABLE_INT_FETCH(tmpstr, &sc->iot_enable); 203 204 snprintf(tmpstr, sizeof(tmpstr), "dev.mpi3mr.%d.max_sgl_entries", 205 device_get_unit(sc->mpi3mr_dev)); 206 TUNABLE_INT_FETCH(tmpstr, &sc->max_sgl_entries); 207 } 208 209 static struct mpi3mr_ident * 210 mpi3mr_find_ident(device_t dev) 211 { 212 struct mpi3mr_ident *m; 213 214 for (m = mpi3mr_identifiers; m->vendor != 0; m++) { 215 if (m->vendor != pci_get_vendor(dev)) 216 continue; 217 if (m->device != pci_get_device(dev)) 218 continue; 219 if ((m->subvendor != 0xffff) && 220 (m->subvendor != pci_get_subvendor(dev))) 221 continue; 222 if ((m->subdevice != 0xffff) && 223 (m->subdevice != pci_get_subdevice(dev))) 224 continue; 225 return (m); 226 } 227 228 return (NULL); 229 } 230 231 static int 232 mpi3mr_pci_probe(device_t dev) 233 { 234 static u_int8_t first_ctrl = 1; 235 struct mpi3mr_ident *id; 236 char raw_os_ver[16]; 237 238 if ((id = mpi3mr_find_ident(dev)) != NULL) { 239 if (first_ctrl) { 240 first_ctrl = 0; 241 MPI3MR_OS_VERSION(raw_os_ver, fmt_os_ver); 242 printf("mpi3mr: Loading Broadcom mpi3mr driver version: %s OS version: %s\n", 243 MPI3MR_DRIVER_VERSION, fmt_os_ver); 244 } 245 device_set_desc(dev, id->desc); 246 device_set_desc(dev, id->desc); 247 return (BUS_PROBE_DEFAULT); 248 } 249 return (ENXIO); 250 } 251 252 static void 253 mpi3mr_release_resources(struct mpi3mr_softc *sc) 254 { 255 if (sc->mpi3mr_parent_dmat != NULL) { 256 bus_dma_tag_destroy(sc->mpi3mr_parent_dmat); 257 } 258 259 if (sc->mpi3mr_regs_resource != NULL) { 260 bus_release_resource(sc->mpi3mr_dev, SYS_RES_MEMORY, 261 sc->mpi3mr_regs_rid, sc->mpi3mr_regs_resource); 262 } 263 } 264 265 static int mpi3mr_setup_resources(struct mpi3mr_softc *sc) 266 { 267 bus_dma_template_t t; 268 int i; 269 device_t dev = sc->mpi3mr_dev; 270 271 pci_enable_busmaster(dev); 272 273 for (i = 0; i < PCI_MAXMAPS_0; i++) { 274 sc->mpi3mr_regs_rid = PCIR_BAR(i); 275 276 if ((sc->mpi3mr_regs_resource = bus_alloc_resource_any(dev, 277 SYS_RES_MEMORY, &sc->mpi3mr_regs_rid, RF_ACTIVE)) != NULL) 278 break; 279 } 280 281 if (sc->mpi3mr_regs_resource == NULL) { 282 mpi3mr_printf(sc, "Cannot allocate PCI registers\n"); 283 return (ENXIO); 284 } 285 286 sc->mpi3mr_btag = rman_get_bustag(sc->mpi3mr_regs_resource); 287 sc->mpi3mr_bhandle = rman_get_bushandle(sc->mpi3mr_regs_resource); 288 289 /* 290 * XXX Perhaps we should move this to after we read iocfacts and use 291 * that to create the proper parent tag. However, to get the iocfacts 292 * we need to have a dmatag for both the admin queue and the iocfacts 293 * DMA transfer. So for now, we just create a 'no restriction' tag and 294 * use sc->dma_loaddr for all the other tag_create calls to get the 295 * right value. It would be nice if one could retroactively adjust a 296 * created tag. The Linux driver effectively does this by setting the 297 * dma_mask on the device. 298 */ 299 /* Allocate the parent DMA tag */ 300 bus_dma_template_init(&t, bus_get_dma_tag(dev)); 301 if (bus_dma_template_tag(&t, &sc->mpi3mr_parent_dmat)) { 302 mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate parent DMA tag\n"); 303 return (ENOMEM); 304 } 305 306 sc->max_msix_vectors = pci_msix_count(dev); 307 308 return 0; 309 } 310 311 static int 312 mpi3mr_startup(struct mpi3mr_softc *sc) 313 { 314 sc->mpi3mr_flags &= ~MPI3MR_FLAGS_PORT_ENABLE_DONE; 315 mpi3mr_issue_port_enable(sc, 1); 316 return (0); 317 } 318 319 /* Run through any late-start handlers. */ 320 static void 321 mpi3mr_ich_startup(void *arg) 322 { 323 struct mpi3mr_softc *sc; 324 int error; 325 326 sc = (struct mpi3mr_softc *)arg; 327 mpi3mr_dprint(sc, MPI3MR_XINFO, "%s entry\n", __func__); 328 329 mtx_lock(&sc->mpi3mr_mtx); 330 331 mpi3mr_startup(sc); 332 333 mtx_unlock(&sc->mpi3mr_mtx); 334 335 error = mpi3mr_kproc_create(mpi3mr_timestamp_thread, sc, 336 &sc->timestamp_thread_proc, 0, 0, 337 "mpi3mr_timestamp_thread%d", 338 device_get_unit(sc->mpi3mr_dev)); 339 if (error) 340 device_printf(sc->mpi3mr_dev, "Error %d starting timestamp thread\n", error); 341 342 error = mpi3mr_kproc_create(mpi3mr_watchdog_thread, sc, 343 &sc->watchdog_thread, 0, 0, "mpi3mr_watchdog%d", 344 device_get_unit(sc->mpi3mr_dev)); 345 346 if (error) 347 device_printf(sc->mpi3mr_dev, "Error %d starting OCR thread\n", error); 348 349 mpi3mr_dprint(sc, MPI3MR_XINFO, "disestablish config intrhook\n"); 350 config_intrhook_disestablish(&sc->mpi3mr_ich); 351 sc->mpi3mr_ich.ich_arg = NULL; 352 353 mpi3mr_dprint(sc, MPI3MR_XINFO, "%s exit\n", __func__); 354 } 355 356 /** 357 * mpi3mr_ctrl_security_status -Check controller secure status 358 * @pdev: PCI device instance 359 * 360 * Read the Device Serial Number capability from PCI config 361 * space and decide whether the controller is secure or not. 362 * 363 * Return: 0 on success, non-zero on failure. 364 */ 365 static int 366 mpi3mr_ctrl_security_status(device_t dev) 367 { 368 int dev_serial_num, retval = 0; 369 uint32_t cap_data, ctrl_status, debug_status; 370 /* Check if Device serial number extended capability is supported */ 371 if (pci_find_extcap(dev, PCIZ_SERNUM, &dev_serial_num) != 0) { 372 device_printf(dev, 373 "PCIZ_SERNUM is not supported\n"); 374 return -1; 375 } 376 377 cap_data = pci_read_config(dev, dev_serial_num + 4, 4); 378 379 debug_status = cap_data & MPI3MR_CTLR_SECURE_DBG_STATUS_MASK; 380 ctrl_status = cap_data & MPI3MR_CTLR_SECURITY_STATUS_MASK; 381 382 switch (ctrl_status) { 383 case MPI3MR_INVALID_DEVICE: 384 device_printf(dev, 385 "Invalid (Non secure) controller is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n", 386 pci_get_device(dev), pci_get_subvendor(dev), 387 pci_get_subdevice(dev)); 388 retval = -1; 389 break; 390 case MPI3MR_CONFIG_SECURE_DEVICE: 391 if (!debug_status) 392 device_printf(dev, "Config secure controller is detected\n"); 393 break; 394 case MPI3MR_HARD_SECURE_DEVICE: 395 device_printf(dev, "Hard secure controller is detected\n"); 396 break; 397 case MPI3MR_TAMPERED_DEVICE: 398 device_printf(dev, 399 "Tampered (Non secure) controller is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n", 400 pci_get_device(dev), pci_get_subvendor(dev), 401 pci_get_subdevice(dev)); 402 retval = -1; 403 break; 404 default: 405 retval = -1; 406 break; 407 } 408 409 if (!retval && debug_status) { 410 device_printf(dev, 411 "Secure Debug (Non secure) controller is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n", 412 pci_get_device(dev), pci_get_subvendor(dev), 413 pci_get_subdevice(dev)); 414 retval = -1; 415 } 416 417 return retval; 418 } 419 /* 420 * mpi3mr_pci_attach - PCI entry point 421 * @dev: pointer to device struct 422 * 423 * This function does the setup of PCI and registers, allocates controller resources, 424 * initializes mutexes, linked lists and registers interrupts, CAM and initializes 425 * the controller. 426 * 427 * Return: 0 on success and proper error codes on failure 428 */ 429 static int 430 mpi3mr_pci_attach(device_t dev) 431 { 432 struct mpi3mr_softc *sc; 433 int error; 434 435 sc = device_get_softc(dev); 436 bzero(sc, sizeof(*sc)); 437 sc->mpi3mr_dev = dev; 438 439 /* Don't load driver for Non-Secure controllers */ 440 if (mpi3mr_ctrl_security_status(dev)) { 441 sc->secure_ctrl = false; 442 return 0; 443 } 444 445 sc->secure_ctrl = true; 446 447 if ((error = mpi3mr_setup_resources(sc)) != 0) 448 goto load_failed; 449 450 sc->id = sc_ids++; 451 mpi3mr_atomic_set(&sc->fw_outstanding, 0); 452 mpi3mr_atomic_set(&sc->pend_ioctls, 0); 453 sc->admin_req = NULL; 454 sc->admin_reply = NULL; 455 sprintf(sc->driver_name, "%s", MPI3MR_DRIVER_NAME); 456 sprintf(sc->name, "%s%d", sc->driver_name, sc->id); 457 458 sc->mpi3mr_dev = dev; 459 mpi3mr_get_tunables(sc); 460 461 if (sc->max_sgl_entries > MPI3MR_MAX_SGL_ENTRIES) 462 sc->max_sgl_entries = MPI3MR_MAX_SGL_ENTRIES; 463 else if (sc->max_sgl_entries < MPI3MR_DEFAULT_SGL_ENTRIES) 464 sc->max_sgl_entries = MPI3MR_DEFAULT_SGL_ENTRIES; 465 else { 466 sc->max_sgl_entries /= MPI3MR_DEFAULT_SGL_ENTRIES; 467 sc->max_sgl_entries *= MPI3MR_DEFAULT_SGL_ENTRIES; 468 } 469 470 if ((error = mpi3mr_initialize_ioc(sc, MPI3MR_INIT_TYPE_INIT)) != 0) { 471 mpi3mr_dprint(sc, MPI3MR_ERROR, "FW initialization failed\n"); 472 goto load_failed; 473 } 474 475 if ((error = mpi3mr_alloc_requests(sc)) != 0) { 476 mpi3mr_dprint(sc, MPI3MR_ERROR, "Command frames allocation failed\n"); 477 goto load_failed; 478 } 479 480 if ((error = mpi3mr_cam_attach(sc)) != 0) { 481 mpi3mr_dprint(sc, MPI3MR_ERROR, "CAM attach failed\n"); 482 goto load_failed; 483 } 484 485 sc->mpi3mr_ich.ich_func = mpi3mr_ich_startup; 486 sc->mpi3mr_ich.ich_arg = sc; 487 if (config_intrhook_establish(&sc->mpi3mr_ich) != 0) { 488 mpi3mr_dprint(sc, MPI3MR_ERROR, 489 "Cannot establish MPI3MR ICH config hook\n"); 490 error = EINVAL; 491 } 492 493 mpi3mr_dprint(sc, MPI3MR_INFO, "allocating ioctl dma buffers\n"); 494 mpi3mr_alloc_ioctl_dma_memory(sc); 495 496 if ((error = mpi3mr_app_attach(sc)) != 0) { 497 mpi3mr_dprint(sc, MPI3MR_ERROR, "APP/IOCTL attach failed\n"); 498 goto load_failed; 499 } 500 501 mpi3mr_setup_sysctl(sc); 502 503 return 0; 504 505 load_failed: 506 mpi3mr_cleanup_interrupts(sc); 507 mpi3mr_free_mem(sc); 508 mpi3mr_app_detach(sc); 509 mpi3mr_cam_detach(sc); 510 mpi3mr_destory_mtx(sc); 511 mpi3mr_release_resources(sc); 512 return error; 513 } 514 515 void mpi3mr_cleanup_interrupts(struct mpi3mr_softc *sc) 516 { 517 mpi3mr_disable_interrupts(sc); 518 519 mpi3mr_teardown_irqs(sc); 520 521 if (sc->irq_ctx) { 522 free(sc->irq_ctx, M_MPI3MR); 523 sc->irq_ctx = NULL; 524 } 525 526 if (sc->msix_enable) 527 pci_release_msi(sc->mpi3mr_dev); 528 529 sc->msix_count = 0; 530 531 } 532 533 int mpi3mr_setup_irqs(struct mpi3mr_softc *sc) 534 { 535 device_t dev; 536 int error; 537 int i, rid, initial_rid; 538 struct mpi3mr_irq_context *irq_ctx; 539 struct irq_info *irq_info; 540 541 dev = sc->mpi3mr_dev; 542 error = -1; 543 544 if (sc->msix_enable) 545 initial_rid = 1; 546 else 547 initial_rid = 0; 548 549 for (i = 0; i < sc->msix_count; i++) { 550 irq_ctx = &sc->irq_ctx[i]; 551 irq_ctx->msix_index = i; 552 irq_ctx->sc = sc; 553 irq_info = &irq_ctx->irq_info; 554 rid = i + initial_rid; 555 irq_info->irq_rid = rid; 556 irq_info->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 557 &irq_info->irq_rid, RF_ACTIVE); 558 if (irq_info->irq == NULL) { 559 mpi3mr_dprint(sc, MPI3MR_ERROR, 560 "Cannot allocate interrupt RID %d\n", rid); 561 sc->msix_count = i; 562 break; 563 } 564 error = bus_setup_intr(dev, irq_info->irq, 565 INTR_MPSAFE | INTR_TYPE_CAM, NULL, mpi3mr_isr, 566 irq_ctx, &irq_info->intrhand); 567 if (error) { 568 mpi3mr_dprint(sc, MPI3MR_ERROR, 569 "Cannot setup interrupt RID %d\n", rid); 570 sc->msix_count = i; 571 break; 572 } 573 } 574 575 mpi3mr_dprint(sc, MPI3MR_INFO, "Set up %d MSI-x interrupts\n", sc->msix_count); 576 577 return (error); 578 579 } 580 581 static void 582 mpi3mr_teardown_irqs(struct mpi3mr_softc *sc) 583 { 584 struct irq_info *irq_info; 585 int i; 586 587 for (i = 0; i < sc->msix_count; i++) { 588 irq_info = &sc->irq_ctx[i].irq_info; 589 if (irq_info->irq != NULL) { 590 bus_teardown_intr(sc->mpi3mr_dev, irq_info->irq, 591 irq_info->intrhand); 592 bus_release_resource(sc->mpi3mr_dev, SYS_RES_IRQ, 593 irq_info->irq_rid, irq_info->irq); 594 } 595 } 596 597 } 598 599 /* 600 * Allocate, but don't assign interrupts early. Doing it before requesting 601 * the IOCFacts message informs the firmware that we want to do MSI-X 602 * multiqueue. We might not use all of the available messages, but there's 603 * no reason to re-alloc if we don't. 604 */ 605 int 606 mpi3mr_alloc_interrupts(struct mpi3mr_softc *sc, U16 setup_one) 607 { 608 int error, msgs; 609 U16 num_queues; 610 611 error = 0; 612 msgs = 0; 613 614 mpi3mr_cleanup_interrupts(sc); 615 616 if (setup_one) { 617 msgs = 1; 618 } else { 619 msgs = min(sc->max_msix_vectors, sc->cpu_count); 620 num_queues = min(sc->facts.max_op_reply_q, sc->facts.max_op_req_q); 621 msgs = min(msgs, num_queues); 622 623 mpi3mr_dprint(sc, MPI3MR_INFO, "Supported MSI-x count: %d " 624 " CPU count: %d Requested MSI-x count: %d\n", 625 sc->max_msix_vectors, 626 sc->cpu_count, msgs); 627 } 628 629 if (msgs != 0) { 630 error = pci_alloc_msix(sc->mpi3mr_dev, &msgs); 631 if (error) { 632 mpi3mr_dprint(sc, MPI3MR_ERROR, 633 "Could not allocate MSI-x interrupts Error: %x\n", error); 634 goto out_failed; 635 } else 636 sc->msix_enable = 1; 637 } 638 639 sc->msix_count = msgs; 640 sc->irq_ctx = malloc(sizeof(struct mpi3mr_irq_context) * msgs, 641 M_MPI3MR, M_NOWAIT | M_ZERO); 642 643 if (!sc->irq_ctx) { 644 mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot alloc memory for interrupt info\n"); 645 error = -1; 646 goto out_failed; 647 } 648 649 mpi3mr_dprint(sc, MPI3MR_XINFO, "Allocated %d MSI-x interrupts\n", msgs); 650 651 return error; 652 out_failed: 653 mpi3mr_cleanup_interrupts(sc); 654 return (error); 655 } 656 657 static int 658 mpi3mr_pci_detach(device_t dev) 659 { 660 struct mpi3mr_softc *sc; 661 int i = 0; 662 663 sc = device_get_softc(dev); 664 665 if (!sc->secure_ctrl) 666 return 0; 667 668 669 if (sc->sysctl_tree != NULL) 670 sysctl_ctx_free(&sc->sysctl_ctx); 671 672 mtx_lock(&sc->reset_mutex); 673 sc->mpi3mr_flags |= MPI3MR_FLAGS_SHUTDOWN; 674 if (sc->timestamp_thread_active) 675 wakeup(&sc->timestamp_chan); 676 677 if (sc->watchdog_thread_active) 678 wakeup(&sc->watchdog_chan); 679 mtx_unlock(&sc->reset_mutex); 680 681 i = 0; 682 while (sc->timestamp_thread_active && (i < 180)) { 683 i++; 684 if (!(i % 5)) { 685 mpi3mr_dprint(sc, MPI3MR_INFO, 686 "[%2d]waiting for " 687 "timestamp thread to quit reset %d\n", i, 688 sc->timestamp_thread_active); 689 } 690 pause("mpi3mr_shutdown", hz); 691 } 692 693 i = 0; 694 while (sc->reset_in_progress && (i < PEND_IOCTLS_COMP_WAIT_TIME)) { 695 i++; 696 if (!(i % 5)) { 697 mpi3mr_dprint(sc, MPI3MR_INFO, 698 "[%2d]waiting for reset to be finished from %s\n", i, __func__); 699 } 700 pause("mpi3mr_shutdown", hz); 701 } 702 703 i = 0; 704 while (sc->watchdog_thread_active && (i < 180)) { 705 i++; 706 if (!(i % 5)) { 707 mpi3mr_dprint(sc, MPI3MR_INFO, 708 "[%2d]waiting for " 709 "mpi3mr_reset thread to quit reset %d\n", i, 710 sc->watchdog_thread_active); 711 } 712 pause("mpi3mr_shutdown", hz); 713 } 714 715 i = 0; 716 while (mpi3mr_atomic_read(&sc->pend_ioctls) && (i < 180)) { 717 i++; 718 if (!(i % 5)) { 719 mpi3mr_dprint(sc, MPI3MR_INFO, 720 "[%2d]waiting for IOCTL to be finished from %s\n", i, __func__); 721 } 722 pause("mpi3mr_shutdown", hz); 723 } 724 725 mpi3mr_cleanup_ioc(sc); 726 mpi3mr_cleanup_event_taskq(sc); 727 mpi3mr_app_detach(sc); 728 mpi3mr_cam_detach(sc); 729 mpi3mr_cleanup_interrupts(sc); 730 mpi3mr_destory_mtx(sc); 731 mpi3mr_free_mem(sc); 732 mpi3mr_release_resources(sc); 733 sc_ids--; 734 return (0); 735 } 736 737 static int 738 mpi3mr_pci_suspend(device_t dev) 739 { 740 return (EINVAL); 741 } 742 743 static int 744 mpi3mr_pci_resume(device_t dev) 745 { 746 return (EINVAL); 747 } 748