12d1d418eSSumit Saxena /* 22d1d418eSSumit Saxena * SPDX-License-Identifier: BSD-2-Clause 32d1d418eSSumit Saxena * 42d1d418eSSumit Saxena * Copyright (c) 2020-2023, Broadcom Inc. All rights reserved. 52d1d418eSSumit Saxena * Support: <fbsd-storage-driver.pdl@broadcom.com> 62d1d418eSSumit Saxena * 72d1d418eSSumit Saxena * Authors: Sumit Saxena <sumit.saxena@broadcom.com> 82d1d418eSSumit Saxena * Chandrakanth Patil <chandrakanth.patil@broadcom.com> 92d1d418eSSumit Saxena * 102d1d418eSSumit Saxena * Redistribution and use in source and binary forms, with or without 112d1d418eSSumit Saxena * modification, are permitted provided that the following conditions are 122d1d418eSSumit Saxena * met: 132d1d418eSSumit Saxena * 142d1d418eSSumit Saxena * 1. Redistributions of source code must retain the above copyright notice, 152d1d418eSSumit Saxena * this list of conditions and the following disclaimer. 162d1d418eSSumit Saxena * 2. Redistributions in binary form must reproduce the above copyright notice, 172d1d418eSSumit Saxena * this list of conditions and the following disclaimer in the documentation and/or other 182d1d418eSSumit Saxena * materials provided with the distribution. 192d1d418eSSumit Saxena * 3. Neither the name of the Broadcom Inc. nor the names of its contributors 202d1d418eSSumit Saxena * may be used to endorse or promote products derived from this software without 212d1d418eSSumit Saxena * specific prior written permission. 222d1d418eSSumit Saxena * 232d1d418eSSumit Saxena * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 242d1d418eSSumit Saxena * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 252d1d418eSSumit Saxena * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 262d1d418eSSumit Saxena * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 272d1d418eSSumit Saxena * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 282d1d418eSSumit Saxena * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 292d1d418eSSumit Saxena * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 302d1d418eSSumit Saxena * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 312d1d418eSSumit Saxena * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 322d1d418eSSumit Saxena * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 332d1d418eSSumit Saxena * POSSIBILITY OF SUCH DAMAGE. 342d1d418eSSumit Saxena * 352d1d418eSSumit Saxena * The views and conclusions contained in the software and documentation are 362d1d418eSSumit Saxena * those of the authors and should not be interpreted as representing 372d1d418eSSumit Saxena * official policies,either expressed or implied, of the FreeBSD Project. 382d1d418eSSumit Saxena * 392d1d418eSSumit Saxena * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 402d1d418eSSumit Saxena * 412d1d418eSSumit Saxena * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD 422d1d418eSSumit Saxena */ 432d1d418eSSumit Saxena 442d1d418eSSumit Saxena #include "mpi3mr.h" 452d1d418eSSumit Saxena #include "mpi3mr_cam.h" 462d1d418eSSumit Saxena #include "mpi3mr_app.h" 472d1d418eSSumit Saxena 482d1d418eSSumit Saxena static int sc_ids; 492d1d418eSSumit Saxena static int mpi3mr_pci_probe(device_t); 502d1d418eSSumit Saxena static int mpi3mr_pci_attach(device_t); 512d1d418eSSumit Saxena static int mpi3mr_pci_detach(device_t); 522d1d418eSSumit Saxena static int mpi3mr_pci_suspend(device_t); 532d1d418eSSumit Saxena static int mpi3mr_pci_resume(device_t); 542d1d418eSSumit Saxena static int mpi3mr_setup_resources(struct mpi3mr_softc *sc); 552d1d418eSSumit Saxena static void mpi3mr_release_resources(struct mpi3mr_softc *); 562d1d418eSSumit Saxena static void mpi3mr_teardown_irqs(struct mpi3mr_softc *sc); 572d1d418eSSumit Saxena 582d1d418eSSumit Saxena extern void mpi3mr_watchdog_thread(void *arg); 592d1d418eSSumit Saxena 602d1d418eSSumit Saxena static device_method_t mpi3mr_methods[] = { 612d1d418eSSumit Saxena DEVMETHOD(device_probe, mpi3mr_pci_probe), 622d1d418eSSumit Saxena DEVMETHOD(device_attach, mpi3mr_pci_attach), 632d1d418eSSumit Saxena DEVMETHOD(device_detach, mpi3mr_pci_detach), 642d1d418eSSumit Saxena DEVMETHOD(device_suspend, mpi3mr_pci_suspend), 652d1d418eSSumit Saxena DEVMETHOD(device_resume, mpi3mr_pci_resume), 662d1d418eSSumit Saxena DEVMETHOD(bus_print_child, bus_generic_print_child), 672d1d418eSSumit Saxena DEVMETHOD(bus_driver_added, bus_generic_driver_added), 682d1d418eSSumit Saxena { 0, 0 } 692d1d418eSSumit Saxena }; 702d1d418eSSumit Saxena 712d1d418eSSumit Saxena char fmt_os_ver[16]; 722d1d418eSSumit Saxena 732d1d418eSSumit Saxena SYSCTL_NODE(_hw, OID_AUTO, mpi3mr, CTLFLAG_RD, 0, "MPI3MR Driver Parameters"); 742d1d418eSSumit Saxena MALLOC_DEFINE(M_MPI3MR, "mpi3mrbuf", "Buffers for the MPI3MR driver"); 752d1d418eSSumit Saxena 762d1d418eSSumit Saxena static driver_t mpi3mr_pci_driver = { 772d1d418eSSumit Saxena "mpi3mr", 782d1d418eSSumit Saxena mpi3mr_methods, 792d1d418eSSumit Saxena sizeof(struct mpi3mr_softc) 802d1d418eSSumit Saxena }; 812d1d418eSSumit Saxena 822d1d418eSSumit Saxena struct mpi3mr_ident { 832d1d418eSSumit Saxena uint16_t vendor; 842d1d418eSSumit Saxena uint16_t device; 852d1d418eSSumit Saxena uint16_t subvendor; 862d1d418eSSumit Saxena uint16_t subdevice; 872d1d418eSSumit Saxena u_int flags; 882d1d418eSSumit Saxena const char *desc; 892d1d418eSSumit Saxena } mpi3mr_identifiers[] = { 902d1d418eSSumit Saxena { MPI3_MFGPAGE_VENDORID_BROADCOM, MPI3_MFGPAGE_DEVID_SAS4116, 912d1d418eSSumit Saxena 0xffff, 0xffff, 0, "Broadcom MPIMR 3.0 controller" }, 922d1d418eSSumit Saxena }; 932d1d418eSSumit Saxena 942d1d418eSSumit Saxena DRIVER_MODULE(mpi3mr, pci, mpi3mr_pci_driver, 0, 0); 952d1d418eSSumit Saxena MODULE_PNP_INFO("U16:vendor;U16:device;U16:subvendor;U16:subdevice;D:#", pci, 962d1d418eSSumit Saxena mpi3mr, mpi3mr_identifiers, nitems(mpi3mr_identifiers) - 1); 972d1d418eSSumit Saxena 982d1d418eSSumit Saxena MODULE_DEPEND(mpi3mr, cam, 1, 1, 1); 992d1d418eSSumit Saxena 1002d1d418eSSumit Saxena /* 1012d1d418eSSumit Saxena * mpi3mr_setup_sysctl: setup sysctl values for mpi3mr 1022d1d418eSSumit Saxena * input: Adapter instance soft state 1032d1d418eSSumit Saxena * 1042d1d418eSSumit Saxena * Setup sysctl entries for mpi3mr driver. 1052d1d418eSSumit Saxena */ 1062d1d418eSSumit Saxena static void 1072d1d418eSSumit Saxena mpi3mr_setup_sysctl(struct mpi3mr_softc *sc) 1082d1d418eSSumit Saxena { 1092d1d418eSSumit Saxena struct sysctl_ctx_list *sysctl_ctx = NULL; 1102d1d418eSSumit Saxena struct sysctl_oid *sysctl_tree = NULL; 1112d1d418eSSumit Saxena char tmpstr[80], tmpstr2[80]; 1122d1d418eSSumit Saxena 1132d1d418eSSumit Saxena /* 1142d1d418eSSumit Saxena * Setup the sysctl variable so the user can change the debug level 1152d1d418eSSumit Saxena * on the fly. 1162d1d418eSSumit Saxena */ 1172d1d418eSSumit Saxena snprintf(tmpstr, sizeof(tmpstr), "MPI3MR controller %d", 1182d1d418eSSumit Saxena device_get_unit(sc->mpi3mr_dev)); 1192d1d418eSSumit Saxena snprintf(tmpstr2, sizeof(tmpstr2), "%d", device_get_unit(sc->mpi3mr_dev)); 1202d1d418eSSumit Saxena 1212d1d418eSSumit Saxena sysctl_ctx = device_get_sysctl_ctx(sc->mpi3mr_dev); 1222d1d418eSSumit Saxena if (sysctl_ctx != NULL) 1232d1d418eSSumit Saxena sysctl_tree = device_get_sysctl_tree(sc->mpi3mr_dev); 1242d1d418eSSumit Saxena 1252d1d418eSSumit Saxena if (sysctl_tree == NULL) { 1262d1d418eSSumit Saxena sysctl_ctx_init(&sc->sysctl_ctx); 1272d1d418eSSumit Saxena sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 1282d1d418eSSumit Saxena SYSCTL_STATIC_CHILDREN(_hw_mpi3mr), OID_AUTO, tmpstr2, 1292d1d418eSSumit Saxena CTLFLAG_RD, 0, tmpstr); 1302d1d418eSSumit Saxena if (sc->sysctl_tree == NULL) 1312d1d418eSSumit Saxena return; 1322d1d418eSSumit Saxena sysctl_ctx = &sc->sysctl_ctx; 1332d1d418eSSumit Saxena sysctl_tree = sc->sysctl_tree; 1342d1d418eSSumit Saxena } 1352d1d418eSSumit Saxena 1362d1d418eSSumit Saxena SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1372d1d418eSSumit Saxena OID_AUTO, "driver_version", CTLFLAG_RD, MPI3MR_DRIVER_VERSION, 1382d1d418eSSumit Saxena strlen(MPI3MR_DRIVER_VERSION), "driver version"); 1392d1d418eSSumit Saxena 1402d1d418eSSumit Saxena SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1412d1d418eSSumit Saxena OID_AUTO, "fw_outstanding", CTLFLAG_RD, 1422d1d418eSSumit Saxena &sc->fw_outstanding.val_rdonly, 0, "FW outstanding commands"); 1432d1d418eSSumit Saxena 1442d1d418eSSumit Saxena SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1452d1d418eSSumit Saxena OID_AUTO, "io_cmds_highwater", CTLFLAG_RD, 1462d1d418eSSumit Saxena &sc->io_cmds_highwater, 0, "Max FW outstanding commands"); 1472d1d418eSSumit Saxena 14828a27434SWarner Losh SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 14928a27434SWarner Losh OID_AUTO, "firmware_version", CTLFLAG_RD, sc->fw_version, 15028a27434SWarner Losh strlen(sc->fw_version), "firmware version"); 15128a27434SWarner Losh 1522d1d418eSSumit Saxena SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1532d1d418eSSumit Saxena OID_AUTO, "mpi3mr_debug", CTLFLAG_RW, &sc->mpi3mr_debug, 0, 1542d1d418eSSumit Saxena "Driver debug level"); 1552d1d418eSSumit Saxena SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1562d1d418eSSumit Saxena OID_AUTO, "reset", CTLFLAG_RW, &sc->reset.type, 0, 1572d1d418eSSumit Saxena "Soft reset(1)/Diag reset(2)"); 1582d1d418eSSumit Saxena SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1592d1d418eSSumit Saxena OID_AUTO, "iot_enable", CTLFLAG_RW, &sc->iot_enable, 0, 1602d1d418eSSumit Saxena "IO throttling enable at driver level(for debug purpose)"); 1612d1d418eSSumit Saxena } 1622d1d418eSSumit Saxena 1632d1d418eSSumit Saxena /* 1642d1d418eSSumit Saxena * mpi3mr_get_tunables: get tunable parameters. 1652d1d418eSSumit Saxena * input: Adapter instance soft state 1662d1d418eSSumit Saxena * 1672d1d418eSSumit Saxena * Get tunable parameters. This will help to debug driver at boot time. 1682d1d418eSSumit Saxena */ 1692d1d418eSSumit Saxena static void 1702d1d418eSSumit Saxena mpi3mr_get_tunables(struct mpi3mr_softc *sc) 1712d1d418eSSumit Saxena { 1722d1d418eSSumit Saxena char tmpstr[80]; 1732d1d418eSSumit Saxena 1742d1d418eSSumit Saxena sc->mpi3mr_debug = 1752d1d418eSSumit Saxena (MPI3MR_ERROR | MPI3MR_INFO | MPI3MR_FAULT); 1762d1d418eSSumit Saxena 1772d1d418eSSumit Saxena sc->reset_in_progress = 0; 1782d1d418eSSumit Saxena sc->reset.type = 0; 1792d1d418eSSumit Saxena sc->iot_enable = 1; 1802d1d418eSSumit Saxena /* 1812d1d418eSSumit Saxena * Grab the global variables. 1822d1d418eSSumit Saxena */ 1832d1d418eSSumit Saxena TUNABLE_INT_FETCH("hw.mpi3mr.debug_level", &sc->mpi3mr_debug); 1842d1d418eSSumit Saxena TUNABLE_INT_FETCH("hw.mpi3mr.ctrl_reset", &sc->reset.type); 1852d1d418eSSumit Saxena TUNABLE_INT_FETCH("hw.mpi3mr.iot_enable", &sc->iot_enable); 1862d1d418eSSumit Saxena 1872d1d418eSSumit Saxena /* Grab the unit-instance variables */ 1882d1d418eSSumit Saxena snprintf(tmpstr, sizeof(tmpstr), "dev.mpi3mr.%d.debug_level", 1892d1d418eSSumit Saxena device_get_unit(sc->mpi3mr_dev)); 1902d1d418eSSumit Saxena TUNABLE_INT_FETCH(tmpstr, &sc->mpi3mr_debug); 1912d1d418eSSumit Saxena 1922d1d418eSSumit Saxena snprintf(tmpstr, sizeof(tmpstr), "dev.mpi3mr.%d.reset", 1932d1d418eSSumit Saxena device_get_unit(sc->mpi3mr_dev)); 1942d1d418eSSumit Saxena TUNABLE_INT_FETCH(tmpstr, &sc->reset.type); 1952d1d418eSSumit Saxena 1962d1d418eSSumit Saxena snprintf(tmpstr, sizeof(tmpstr), "dev.mpi3mr.%d.iot_enable", 1972d1d418eSSumit Saxena device_get_unit(sc->mpi3mr_dev)); 1982d1d418eSSumit Saxena TUNABLE_INT_FETCH(tmpstr, &sc->iot_enable); 1992d1d418eSSumit Saxena } 2002d1d418eSSumit Saxena 2012d1d418eSSumit Saxena static struct mpi3mr_ident * 2022d1d418eSSumit Saxena mpi3mr_find_ident(device_t dev) 2032d1d418eSSumit Saxena { 2042d1d418eSSumit Saxena struct mpi3mr_ident *m; 2052d1d418eSSumit Saxena 2062d1d418eSSumit Saxena for (m = mpi3mr_identifiers; m->vendor != 0; m++) { 2072d1d418eSSumit Saxena if (m->vendor != pci_get_vendor(dev)) 2082d1d418eSSumit Saxena continue; 2092d1d418eSSumit Saxena if (m->device != pci_get_device(dev)) 2102d1d418eSSumit Saxena continue; 2112d1d418eSSumit Saxena if ((m->subvendor != 0xffff) && 2122d1d418eSSumit Saxena (m->subvendor != pci_get_subvendor(dev))) 2132d1d418eSSumit Saxena continue; 2142d1d418eSSumit Saxena if ((m->subdevice != 0xffff) && 2152d1d418eSSumit Saxena (m->subdevice != pci_get_subdevice(dev))) 2162d1d418eSSumit Saxena continue; 2172d1d418eSSumit Saxena return (m); 2182d1d418eSSumit Saxena } 2192d1d418eSSumit Saxena 2202d1d418eSSumit Saxena return (NULL); 2212d1d418eSSumit Saxena } 2222d1d418eSSumit Saxena 2232d1d418eSSumit Saxena static int 2242d1d418eSSumit Saxena mpi3mr_pci_probe(device_t dev) 2252d1d418eSSumit Saxena { 2262d1d418eSSumit Saxena static u_int8_t first_ctrl = 1; 2272d1d418eSSumit Saxena struct mpi3mr_ident *id; 2282d1d418eSSumit Saxena char raw_os_ver[16]; 2292d1d418eSSumit Saxena 2302d1d418eSSumit Saxena if ((id = mpi3mr_find_ident(dev)) != NULL) { 2312d1d418eSSumit Saxena if (first_ctrl) { 2322d1d418eSSumit Saxena first_ctrl = 0; 2332d1d418eSSumit Saxena MPI3MR_OS_VERSION(raw_os_ver, fmt_os_ver); 2342d1d418eSSumit Saxena printf("mpi3mr: Loading Broadcom mpi3mr driver version: %s OS version: %s\n", 2352d1d418eSSumit Saxena MPI3MR_DRIVER_VERSION, fmt_os_ver); 2362d1d418eSSumit Saxena } 2372d1d418eSSumit Saxena device_set_desc(dev, id->desc); 2382d1d418eSSumit Saxena device_set_desc(dev, id->desc); 2392d1d418eSSumit Saxena return (BUS_PROBE_DEFAULT); 2402d1d418eSSumit Saxena } 2412d1d418eSSumit Saxena return (ENXIO); 2422d1d418eSSumit Saxena } 2432d1d418eSSumit Saxena 2442d1d418eSSumit Saxena static void 2452d1d418eSSumit Saxena mpi3mr_release_resources(struct mpi3mr_softc *sc) 2462d1d418eSSumit Saxena { 2472d1d418eSSumit Saxena if (sc->mpi3mr_parent_dmat != NULL) { 2482d1d418eSSumit Saxena bus_dma_tag_destroy(sc->mpi3mr_parent_dmat); 2492d1d418eSSumit Saxena } 2502d1d418eSSumit Saxena 2512d1d418eSSumit Saxena if (sc->mpi3mr_regs_resource != NULL) { 2522d1d418eSSumit Saxena bus_release_resource(sc->mpi3mr_dev, SYS_RES_MEMORY, 2532d1d418eSSumit Saxena sc->mpi3mr_regs_rid, sc->mpi3mr_regs_resource); 2542d1d418eSSumit Saxena } 2552d1d418eSSumit Saxena } 2562d1d418eSSumit Saxena 2572d1d418eSSumit Saxena static int mpi3mr_setup_resources(struct mpi3mr_softc *sc) 2582d1d418eSSumit Saxena { 259*489eee0dSAlexander Motin bus_dma_template_t t; 2602d1d418eSSumit Saxena int i; 2612d1d418eSSumit Saxena device_t dev = sc->mpi3mr_dev; 2622d1d418eSSumit Saxena 2632d1d418eSSumit Saxena pci_enable_busmaster(dev); 2642d1d418eSSumit Saxena 2652d1d418eSSumit Saxena for (i = 0; i < PCI_MAXMAPS_0; i++) { 2662d1d418eSSumit Saxena sc->mpi3mr_regs_rid = PCIR_BAR(i); 2672d1d418eSSumit Saxena 2682d1d418eSSumit Saxena if ((sc->mpi3mr_regs_resource = bus_alloc_resource_any(dev, 2692d1d418eSSumit Saxena SYS_RES_MEMORY, &sc->mpi3mr_regs_rid, RF_ACTIVE)) != NULL) 2702d1d418eSSumit Saxena break; 2712d1d418eSSumit Saxena } 2722d1d418eSSumit Saxena 2732d1d418eSSumit Saxena if (sc->mpi3mr_regs_resource == NULL) { 2742d1d418eSSumit Saxena mpi3mr_printf(sc, "Cannot allocate PCI registers\n"); 2752d1d418eSSumit Saxena return (ENXIO); 2762d1d418eSSumit Saxena } 2772d1d418eSSumit Saxena 2782d1d418eSSumit Saxena sc->mpi3mr_btag = rman_get_bustag(sc->mpi3mr_regs_resource); 2792d1d418eSSumit Saxena sc->mpi3mr_bhandle = rman_get_bushandle(sc->mpi3mr_regs_resource); 2802d1d418eSSumit Saxena 28191d96135SWarner Losh /* 28291d96135SWarner Losh * XXX Perhaps we should move this to after we read iocfacts and use 28391d96135SWarner Losh * that to create the proper parent tag. However, to get the iocfacts 28491d96135SWarner Losh * we need to have a dmatag for both the admin queue and the iocfacts 28591d96135SWarner Losh * DMA transfer. So for now, we just create a 'no restriction' tag and 28691d96135SWarner Losh * use sc->dma_loaddr for all the other tag_create calls to get the 28791d96135SWarner Losh * right value. It would be nice if one could retroactively adjust a 28891d96135SWarner Losh * created tag. The Linux driver effectively does this by setting the 28991d96135SWarner Losh * dma_mask on the device. 29091d96135SWarner Losh */ 2912d1d418eSSumit Saxena /* Allocate the parent DMA tag */ 292*489eee0dSAlexander Motin bus_dma_template_init(&t, bus_get_dma_tag(dev)); 293*489eee0dSAlexander Motin if (bus_dma_template_tag(&t, &sc->mpi3mr_parent_dmat)) { 2942d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate parent DMA tag\n"); 2952d1d418eSSumit Saxena return (ENOMEM); 2962d1d418eSSumit Saxena } 2972d1d418eSSumit Saxena 2982d1d418eSSumit Saxena sc->max_msix_vectors = pci_msix_count(dev); 2992d1d418eSSumit Saxena 3002d1d418eSSumit Saxena return 0; 3012d1d418eSSumit Saxena } 3022d1d418eSSumit Saxena 3032d1d418eSSumit Saxena static int 3042d1d418eSSumit Saxena mpi3mr_startup(struct mpi3mr_softc *sc) 3052d1d418eSSumit Saxena { 3062d1d418eSSumit Saxena sc->mpi3mr_flags &= ~MPI3MR_FLAGS_PORT_ENABLE_DONE; 3072d1d418eSSumit Saxena mpi3mr_issue_port_enable(sc, 1); 3082d1d418eSSumit Saxena return (0); 3092d1d418eSSumit Saxena } 3102d1d418eSSumit Saxena 3112d1d418eSSumit Saxena /* Run through any late-start handlers. */ 3122d1d418eSSumit Saxena static void 3132d1d418eSSumit Saxena mpi3mr_ich_startup(void *arg) 3142d1d418eSSumit Saxena { 3152d1d418eSSumit Saxena struct mpi3mr_softc *sc; 3167e02c707SSumit Saxena int error; 3172d1d418eSSumit Saxena 3182d1d418eSSumit Saxena sc = (struct mpi3mr_softc *)arg; 3192d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "%s entry\n", __func__); 3202d1d418eSSumit Saxena 3212d1d418eSSumit Saxena mtx_lock(&sc->mpi3mr_mtx); 3222d1d418eSSumit Saxena 3232d1d418eSSumit Saxena mpi3mr_startup(sc); 3247e02c707SSumit Saxena 3252d1d418eSSumit Saxena mtx_unlock(&sc->mpi3mr_mtx); 3262d1d418eSSumit Saxena 3277e02c707SSumit Saxena error = mpi3mr_kproc_create(mpi3mr_watchdog_thread, sc, 3287e02c707SSumit Saxena &sc->watchdog_thread, 0, 0, "mpi3mr_watchdog%d", 3297e02c707SSumit Saxena device_get_unit(sc->mpi3mr_dev)); 3307e02c707SSumit Saxena 3317e02c707SSumit Saxena if (error) 3327e02c707SSumit Saxena device_printf(sc->mpi3mr_dev, "Error %d starting OCR thread\n", error); 3337e02c707SSumit Saxena 3342d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "disestablish config intrhook\n"); 3352d1d418eSSumit Saxena config_intrhook_disestablish(&sc->mpi3mr_ich); 3362d1d418eSSumit Saxena sc->mpi3mr_ich.ich_arg = NULL; 3372d1d418eSSumit Saxena 3382d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "%s exit\n", __func__); 3392d1d418eSSumit Saxena } 3402d1d418eSSumit Saxena 3412d1d418eSSumit Saxena /** 3422d1d418eSSumit Saxena * mpi3mr_ctrl_security_status -Check controller secure status 3432d1d418eSSumit Saxena * @pdev: PCI device instance 3442d1d418eSSumit Saxena * 3452d1d418eSSumit Saxena * Read the Device Serial Number capability from PCI config 3462d1d418eSSumit Saxena * space and decide whether the controller is secure or not. 3472d1d418eSSumit Saxena * 3482d1d418eSSumit Saxena * Return: 0 on success, non-zero on failure. 3492d1d418eSSumit Saxena */ 3502d1d418eSSumit Saxena static int 3512d1d418eSSumit Saxena mpi3mr_ctrl_security_status(device_t dev) 3522d1d418eSSumit Saxena { 3532d1d418eSSumit Saxena int dev_serial_num, retval = 0; 3542d1d418eSSumit Saxena uint32_t cap_data, ctrl_status, debug_status; 3552d1d418eSSumit Saxena /* Check if Device serial number extended capability is supported */ 3562d1d418eSSumit Saxena if (pci_find_extcap(dev, PCIZ_SERNUM, &dev_serial_num) != 0) { 3572d1d418eSSumit Saxena device_printf(dev, 3582d1d418eSSumit Saxena "PCIZ_SERNUM is not supported\n"); 3592d1d418eSSumit Saxena return -1; 3602d1d418eSSumit Saxena } 3612d1d418eSSumit Saxena 3622d1d418eSSumit Saxena cap_data = pci_read_config(dev, dev_serial_num + 4, 4); 3632d1d418eSSumit Saxena 3642d1d418eSSumit Saxena debug_status = cap_data & MPI3MR_CTLR_SECURE_DBG_STATUS_MASK; 3652d1d418eSSumit Saxena ctrl_status = cap_data & MPI3MR_CTLR_SECURITY_STATUS_MASK; 3662d1d418eSSumit Saxena 3672d1d418eSSumit Saxena switch (ctrl_status) { 3682d1d418eSSumit Saxena case MPI3MR_INVALID_DEVICE: 3692d1d418eSSumit Saxena device_printf(dev, 3702d1d418eSSumit Saxena "Invalid (Non secure) controller is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n", 3712d1d418eSSumit Saxena pci_get_device(dev), pci_get_subvendor(dev), 3722d1d418eSSumit Saxena pci_get_subdevice(dev)); 3732d1d418eSSumit Saxena retval = -1; 3742d1d418eSSumit Saxena break; 3752d1d418eSSumit Saxena case MPI3MR_CONFIG_SECURE_DEVICE: 3762d1d418eSSumit Saxena if (!debug_status) 3772d1d418eSSumit Saxena device_printf(dev, "Config secure controller is detected\n"); 3782d1d418eSSumit Saxena break; 3792d1d418eSSumit Saxena case MPI3MR_HARD_SECURE_DEVICE: 3802d1d418eSSumit Saxena device_printf(dev, "Hard secure controller is detected\n"); 3812d1d418eSSumit Saxena break; 3822d1d418eSSumit Saxena case MPI3MR_TAMPERED_DEVICE: 3832d1d418eSSumit Saxena device_printf(dev, 3842d1d418eSSumit Saxena "Tampered (Non secure) controller is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n", 3852d1d418eSSumit Saxena pci_get_device(dev), pci_get_subvendor(dev), 3862d1d418eSSumit Saxena pci_get_subdevice(dev)); 3872d1d418eSSumit Saxena retval = -1; 3882d1d418eSSumit Saxena break; 3892d1d418eSSumit Saxena default: 3902d1d418eSSumit Saxena retval = -1; 3912d1d418eSSumit Saxena break; 3922d1d418eSSumit Saxena } 3932d1d418eSSumit Saxena 3942d1d418eSSumit Saxena if (!retval && debug_status) { 3952d1d418eSSumit Saxena device_printf(dev, 3962d1d418eSSumit Saxena "Secure Debug (Non secure) controller is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n", 3972d1d418eSSumit Saxena pci_get_device(dev), pci_get_subvendor(dev), 3982d1d418eSSumit Saxena pci_get_subdevice(dev)); 3992d1d418eSSumit Saxena retval = -1; 4002d1d418eSSumit Saxena } 4012d1d418eSSumit Saxena 4022d1d418eSSumit Saxena return retval; 4032d1d418eSSumit Saxena } 4042d1d418eSSumit Saxena /* 4052d1d418eSSumit Saxena * mpi3mr_pci_attach - PCI entry point 4062d1d418eSSumit Saxena * @dev: pointer to device struct 4072d1d418eSSumit Saxena * 4082d1d418eSSumit Saxena * This function does the setup of PCI and registers, allocates controller resources, 4092d1d418eSSumit Saxena * initializes mutexes, linked lists and registers interrupts, CAM and initializes 4102d1d418eSSumit Saxena * the controller. 4112d1d418eSSumit Saxena * 4122d1d418eSSumit Saxena * Return: 0 on success and proper error codes on failure 4132d1d418eSSumit Saxena */ 4142d1d418eSSumit Saxena static int 4152d1d418eSSumit Saxena mpi3mr_pci_attach(device_t dev) 4162d1d418eSSumit Saxena { 4172d1d418eSSumit Saxena struct mpi3mr_softc *sc; 4182d1d418eSSumit Saxena int error; 4192d1d418eSSumit Saxena 4202d1d418eSSumit Saxena sc = device_get_softc(dev); 4212d1d418eSSumit Saxena bzero(sc, sizeof(*sc)); 4222d1d418eSSumit Saxena sc->mpi3mr_dev = dev; 4232d1d418eSSumit Saxena 4242d1d418eSSumit Saxena /* Don't load driver for Non-Secure controllers */ 4252d1d418eSSumit Saxena if (mpi3mr_ctrl_security_status(dev)) { 4262d1d418eSSumit Saxena sc->secure_ctrl = false; 4272d1d418eSSumit Saxena return 0; 4282d1d418eSSumit Saxena } 4292d1d418eSSumit Saxena 4302d1d418eSSumit Saxena sc->secure_ctrl = true; 4312d1d418eSSumit Saxena 4322d1d418eSSumit Saxena if ((error = mpi3mr_setup_resources(sc)) != 0) 4332d1d418eSSumit Saxena goto load_failed; 4342d1d418eSSumit Saxena 4352d1d418eSSumit Saxena sc->id = sc_ids++; 4362d1d418eSSumit Saxena mpi3mr_atomic_set(&sc->fw_outstanding, 0); 4372d1d418eSSumit Saxena mpi3mr_atomic_set(&sc->pend_ioctls, 0); 4382d1d418eSSumit Saxena sc->admin_req = NULL; 4392d1d418eSSumit Saxena sc->admin_reply = NULL; 4402d1d418eSSumit Saxena sprintf(sc->driver_name, "%s", MPI3MR_DRIVER_NAME); 4412d1d418eSSumit Saxena sprintf(sc->name, "%s%d", sc->driver_name, sc->id); 4422d1d418eSSumit Saxena 4432d1d418eSSumit Saxena sc->mpi3mr_dev = dev; 4442d1d418eSSumit Saxena mpi3mr_get_tunables(sc); 4452d1d418eSSumit Saxena 4462d1d418eSSumit Saxena if ((error = mpi3mr_initialize_ioc(sc, MPI3MR_INIT_TYPE_INIT)) != 0) { 4472d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "FW initialization failed\n"); 4482d1d418eSSumit Saxena goto load_failed; 4492d1d418eSSumit Saxena } 4502d1d418eSSumit Saxena 4512d1d418eSSumit Saxena if ((error = mpi3mr_alloc_requests(sc)) != 0) { 4522d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "Command frames allocation failed\n"); 4532d1d418eSSumit Saxena goto load_failed; 4542d1d418eSSumit Saxena } 4552d1d418eSSumit Saxena 4562d1d418eSSumit Saxena if ((error = mpi3mr_cam_attach(sc)) != 0) { 4572d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "CAM attach failed\n"); 4582d1d418eSSumit Saxena goto load_failed; 4592d1d418eSSumit Saxena } 4602d1d418eSSumit Saxena 4612d1d418eSSumit Saxena sc->mpi3mr_ich.ich_func = mpi3mr_ich_startup; 4622d1d418eSSumit Saxena sc->mpi3mr_ich.ich_arg = sc; 4632d1d418eSSumit Saxena if (config_intrhook_establish(&sc->mpi3mr_ich) != 0) { 4642d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, 4652d1d418eSSumit Saxena "Cannot establish MPI3MR ICH config hook\n"); 4662d1d418eSSumit Saxena error = EINVAL; 4672d1d418eSSumit Saxena } 4682d1d418eSSumit Saxena 4692d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, "allocating ioctl dma buffers\n"); 4702d1d418eSSumit Saxena mpi3mr_alloc_ioctl_dma_memory(sc); 4712d1d418eSSumit Saxena 4722d1d418eSSumit Saxena if ((error = mpi3mr_app_attach(sc)) != 0) { 4732d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "APP/IOCTL attach failed\n"); 4742d1d418eSSumit Saxena goto load_failed; 4752d1d418eSSumit Saxena } 4762d1d418eSSumit Saxena 4772d1d418eSSumit Saxena mpi3mr_setup_sysctl(sc); 4782d1d418eSSumit Saxena 4792d1d418eSSumit Saxena return 0; 4802d1d418eSSumit Saxena 4812d1d418eSSumit Saxena load_failed: 4822d1d418eSSumit Saxena mpi3mr_cleanup_interrupts(sc); 4832d1d418eSSumit Saxena mpi3mr_free_mem(sc); 4842d1d418eSSumit Saxena mpi3mr_app_detach(sc); 4852d1d418eSSumit Saxena mpi3mr_cam_detach(sc); 4862d1d418eSSumit Saxena mpi3mr_destory_mtx(sc); 4872d1d418eSSumit Saxena mpi3mr_release_resources(sc); 4882d1d418eSSumit Saxena return error; 4892d1d418eSSumit Saxena } 4902d1d418eSSumit Saxena 4912d1d418eSSumit Saxena void mpi3mr_cleanup_interrupts(struct mpi3mr_softc *sc) 4922d1d418eSSumit Saxena { 4932d1d418eSSumit Saxena mpi3mr_disable_interrupts(sc); 4942d1d418eSSumit Saxena 4952d1d418eSSumit Saxena mpi3mr_teardown_irqs(sc); 4962d1d418eSSumit Saxena 4972d1d418eSSumit Saxena if (sc->irq_ctx) { 4982d1d418eSSumit Saxena free(sc->irq_ctx, M_MPI3MR); 4992d1d418eSSumit Saxena sc->irq_ctx = NULL; 5002d1d418eSSumit Saxena } 5012d1d418eSSumit Saxena 5022d1d418eSSumit Saxena if (sc->msix_enable) 5032d1d418eSSumit Saxena pci_release_msi(sc->mpi3mr_dev); 5042d1d418eSSumit Saxena 5052d1d418eSSumit Saxena sc->msix_count = 0; 5062d1d418eSSumit Saxena 5072d1d418eSSumit Saxena } 5082d1d418eSSumit Saxena 5092d1d418eSSumit Saxena int mpi3mr_setup_irqs(struct mpi3mr_softc *sc) 5102d1d418eSSumit Saxena { 5112d1d418eSSumit Saxena device_t dev; 5122d1d418eSSumit Saxena int error; 5132d1d418eSSumit Saxena int i, rid, initial_rid; 5142d1d418eSSumit Saxena struct mpi3mr_irq_context *irq_ctx; 5152d1d418eSSumit Saxena struct irq_info *irq_info; 5162d1d418eSSumit Saxena 5172d1d418eSSumit Saxena dev = sc->mpi3mr_dev; 5182d1d418eSSumit Saxena error = -1; 5192d1d418eSSumit Saxena 5202d1d418eSSumit Saxena if (sc->msix_enable) 5212d1d418eSSumit Saxena initial_rid = 1; 5222d1d418eSSumit Saxena else 5232d1d418eSSumit Saxena initial_rid = 0; 5242d1d418eSSumit Saxena 5252d1d418eSSumit Saxena for (i = 0; i < sc->msix_count; i++) { 5262d1d418eSSumit Saxena irq_ctx = &sc->irq_ctx[i]; 5272d1d418eSSumit Saxena irq_ctx->msix_index = i; 5282d1d418eSSumit Saxena irq_ctx->sc = sc; 5292d1d418eSSumit Saxena irq_info = &irq_ctx->irq_info; 5302d1d418eSSumit Saxena rid = i + initial_rid; 5312d1d418eSSumit Saxena irq_info->irq_rid = rid; 5322d1d418eSSumit Saxena irq_info->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 5332d1d418eSSumit Saxena &irq_info->irq_rid, RF_ACTIVE); 5342d1d418eSSumit Saxena if (irq_info->irq == NULL) { 5352d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, 5362d1d418eSSumit Saxena "Cannot allocate interrupt RID %d\n", rid); 5372d1d418eSSumit Saxena sc->msix_count = i; 5382d1d418eSSumit Saxena break; 5392d1d418eSSumit Saxena } 5402d1d418eSSumit Saxena error = bus_setup_intr(dev, irq_info->irq, 5412d1d418eSSumit Saxena INTR_MPSAFE | INTR_TYPE_CAM, NULL, mpi3mr_isr, 5422d1d418eSSumit Saxena irq_ctx, &irq_info->intrhand); 5432d1d418eSSumit Saxena if (error) { 5442d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, 5452d1d418eSSumit Saxena "Cannot setup interrupt RID %d\n", rid); 5462d1d418eSSumit Saxena sc->msix_count = i; 5472d1d418eSSumit Saxena break; 5482d1d418eSSumit Saxena } 5492d1d418eSSumit Saxena } 5502d1d418eSSumit Saxena 5512d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, "Set up %d MSI-x interrupts\n", sc->msix_count); 5522d1d418eSSumit Saxena 5532d1d418eSSumit Saxena return (error); 5542d1d418eSSumit Saxena 5552d1d418eSSumit Saxena } 5562d1d418eSSumit Saxena 5572d1d418eSSumit Saxena static void 5582d1d418eSSumit Saxena mpi3mr_teardown_irqs(struct mpi3mr_softc *sc) 5592d1d418eSSumit Saxena { 5602d1d418eSSumit Saxena struct irq_info *irq_info; 5612d1d418eSSumit Saxena int i; 5622d1d418eSSumit Saxena 5632d1d418eSSumit Saxena for (i = 0; i < sc->msix_count; i++) { 5642d1d418eSSumit Saxena irq_info = &sc->irq_ctx[i].irq_info; 5652d1d418eSSumit Saxena if (irq_info->irq != NULL) { 5662d1d418eSSumit Saxena bus_teardown_intr(sc->mpi3mr_dev, irq_info->irq, 5672d1d418eSSumit Saxena irq_info->intrhand); 5682d1d418eSSumit Saxena bus_release_resource(sc->mpi3mr_dev, SYS_RES_IRQ, 5692d1d418eSSumit Saxena irq_info->irq_rid, irq_info->irq); 5702d1d418eSSumit Saxena } 5712d1d418eSSumit Saxena } 5722d1d418eSSumit Saxena 5732d1d418eSSumit Saxena } 5742d1d418eSSumit Saxena 5752d1d418eSSumit Saxena /* 5762d1d418eSSumit Saxena * Allocate, but don't assign interrupts early. Doing it before requesting 5772d1d418eSSumit Saxena * the IOCFacts message informs the firmware that we want to do MSI-X 5782d1d418eSSumit Saxena * multiqueue. We might not use all of the available messages, but there's 5792d1d418eSSumit Saxena * no reason to re-alloc if we don't. 5802d1d418eSSumit Saxena */ 5812d1d418eSSumit Saxena int 5822d1d418eSSumit Saxena mpi3mr_alloc_interrupts(struct mpi3mr_softc *sc, U16 setup_one) 5832d1d418eSSumit Saxena { 5842d1d418eSSumit Saxena int error, msgs; 5852d1d418eSSumit Saxena U16 num_queues; 5862d1d418eSSumit Saxena 5872d1d418eSSumit Saxena error = 0; 5882d1d418eSSumit Saxena msgs = 0; 5892d1d418eSSumit Saxena 5902d1d418eSSumit Saxena mpi3mr_cleanup_interrupts(sc); 5912d1d418eSSumit Saxena 5922d1d418eSSumit Saxena if (setup_one) { 5932d1d418eSSumit Saxena msgs = 1; 5942d1d418eSSumit Saxena } else { 5952d1d418eSSumit Saxena msgs = min(sc->max_msix_vectors, sc->cpu_count); 5962d1d418eSSumit Saxena num_queues = min(sc->facts.max_op_reply_q, sc->facts.max_op_req_q); 5972d1d418eSSumit Saxena msgs = min(msgs, num_queues); 5982d1d418eSSumit Saxena 5992d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, "Supported MSI-x count: %d " 6002d1d418eSSumit Saxena " CPU count: %d Requested MSI-x count: %d\n", 6012d1d418eSSumit Saxena sc->max_msix_vectors, 6022d1d418eSSumit Saxena sc->cpu_count, msgs); 6032d1d418eSSumit Saxena } 6042d1d418eSSumit Saxena 6052d1d418eSSumit Saxena if (msgs != 0) { 6062d1d418eSSumit Saxena error = pci_alloc_msix(sc->mpi3mr_dev, &msgs); 6072d1d418eSSumit Saxena if (error) { 6082d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, 6092d1d418eSSumit Saxena "Could not allocate MSI-x interrupts Error: %x\n", error); 6102d1d418eSSumit Saxena goto out_failed; 6112d1d418eSSumit Saxena } else 6122d1d418eSSumit Saxena sc->msix_enable = 1; 6132d1d418eSSumit Saxena } 6142d1d418eSSumit Saxena 6152d1d418eSSumit Saxena sc->msix_count = msgs; 6162d1d418eSSumit Saxena sc->irq_ctx = malloc(sizeof(struct mpi3mr_irq_context) * msgs, 6172d1d418eSSumit Saxena M_MPI3MR, M_NOWAIT | M_ZERO); 6182d1d418eSSumit Saxena 6192d1d418eSSumit Saxena if (!sc->irq_ctx) { 6202d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot alloc memory for interrupt info\n"); 6212d1d418eSSumit Saxena error = -1; 6222d1d418eSSumit Saxena goto out_failed; 6232d1d418eSSumit Saxena } 6242d1d418eSSumit Saxena 6252d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "Allocated %d MSI-x interrupts\n", msgs); 6262d1d418eSSumit Saxena 6272d1d418eSSumit Saxena return error; 6282d1d418eSSumit Saxena out_failed: 6292d1d418eSSumit Saxena mpi3mr_cleanup_interrupts(sc); 6302d1d418eSSumit Saxena return (error); 6312d1d418eSSumit Saxena } 6322d1d418eSSumit Saxena 6332d1d418eSSumit Saxena static int 6342d1d418eSSumit Saxena mpi3mr_pci_detach(device_t dev) 6352d1d418eSSumit Saxena { 6362d1d418eSSumit Saxena struct mpi3mr_softc *sc; 6372d1d418eSSumit Saxena int i = 0; 6382d1d418eSSumit Saxena 6392d1d418eSSumit Saxena sc = device_get_softc(dev); 6402d1d418eSSumit Saxena 6412d1d418eSSumit Saxena if (!sc->secure_ctrl) 6422d1d418eSSumit Saxena return 0; 6432d1d418eSSumit Saxena 6442d1d418eSSumit Saxena 6452d1d418eSSumit Saxena if (sc->sysctl_tree != NULL) 6462d1d418eSSumit Saxena sysctl_ctx_free(&sc->sysctl_ctx); 6472d1d418eSSumit Saxena 6487c491309SWarner Losh mtx_lock(&sc->reset_mutex); 6497c491309SWarner Losh sc->mpi3mr_flags |= MPI3MR_FLAGS_SHUTDOWN; 6502d1d418eSSumit Saxena if (sc->watchdog_thread_active) 6512d1d418eSSumit Saxena wakeup(&sc->watchdog_chan); 6527c491309SWarner Losh mtx_unlock(&sc->reset_mutex); 6532d1d418eSSumit Saxena 6542d1d418eSSumit Saxena while (sc->reset_in_progress && (i < PEND_IOCTLS_COMP_WAIT_TIME)) { 6552d1d418eSSumit Saxena i++; 6562d1d418eSSumit Saxena if (!(i % 5)) { 6572d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 6582d1d418eSSumit Saxena "[%2d]waiting for reset to be finished from %s\n", i, __func__); 6592d1d418eSSumit Saxena } 6602d1d418eSSumit Saxena pause("mpi3mr_shutdown", hz); 6612d1d418eSSumit Saxena } 6622d1d418eSSumit Saxena 6632d1d418eSSumit Saxena i = 0; 6642d1d418eSSumit Saxena while (sc->watchdog_thread_active && (i < 180)) { 6652d1d418eSSumit Saxena i++; 6662d1d418eSSumit Saxena if (!(i % 5)) { 6672d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 6682d1d418eSSumit Saxena "[%2d]waiting for " 6692d1d418eSSumit Saxena "mpi3mr_reset thread to quit reset %d\n", i, 6702d1d418eSSumit Saxena sc->watchdog_thread_active); 6712d1d418eSSumit Saxena } 6722d1d418eSSumit Saxena pause("mpi3mr_shutdown", hz); 6732d1d418eSSumit Saxena } 6742d1d418eSSumit Saxena 6752d1d418eSSumit Saxena i = 0; 6762d1d418eSSumit Saxena while (mpi3mr_atomic_read(&sc->pend_ioctls) && (i < 180)) { 6772d1d418eSSumit Saxena i++; 6782d1d418eSSumit Saxena if (!(i % 5)) { 6792d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 6802d1d418eSSumit Saxena "[%2d]waiting for IOCTL to be finished from %s\n", i, __func__); 6812d1d418eSSumit Saxena } 6822d1d418eSSumit Saxena pause("mpi3mr_shutdown", hz); 6832d1d418eSSumit Saxena } 6842d1d418eSSumit Saxena 6852d1d418eSSumit Saxena mpi3mr_cleanup_ioc(sc); 6862d1d418eSSumit Saxena mpi3mr_cleanup_event_taskq(sc); 6872d1d418eSSumit Saxena mpi3mr_app_detach(sc); 6882d1d418eSSumit Saxena mpi3mr_cam_detach(sc); 6892d1d418eSSumit Saxena mpi3mr_cleanup_interrupts(sc); 6902d1d418eSSumit Saxena mpi3mr_destory_mtx(sc); 6912d1d418eSSumit Saxena mpi3mr_free_mem(sc); 6922d1d418eSSumit Saxena mpi3mr_release_resources(sc); 6932d1d418eSSumit Saxena sc_ids--; 6942d1d418eSSumit Saxena return (0); 6952d1d418eSSumit Saxena } 6962d1d418eSSumit Saxena 6972d1d418eSSumit Saxena static int 6982d1d418eSSumit Saxena mpi3mr_pci_suspend(device_t dev) 6992d1d418eSSumit Saxena { 7002d1d418eSSumit Saxena return (EINVAL); 7012d1d418eSSumit Saxena } 7022d1d418eSSumit Saxena 7032d1d418eSSumit Saxena static int 7042d1d418eSSumit Saxena mpi3mr_pci_resume(device_t dev) 7052d1d418eSSumit Saxena { 7062d1d418eSSumit Saxena return (EINVAL); 7072d1d418eSSumit Saxena } 708