12d1d418eSSumit Saxena /*
22d1d418eSSumit Saxena * SPDX-License-Identifier: BSD-2-Clause
32d1d418eSSumit Saxena *
4*945c3ce4SChandrakanth patil * Copyright (c) 2020-2024, 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" },
922f2da217SChuck Silvers { 0 }
932d1d418eSSumit Saxena };
942d1d418eSSumit Saxena
952d1d418eSSumit Saxena DRIVER_MODULE(mpi3mr, pci, mpi3mr_pci_driver, 0, 0);
962d1d418eSSumit Saxena MODULE_PNP_INFO("U16:vendor;U16:device;U16:subvendor;U16:subdevice;D:#", pci,
972d1d418eSSumit Saxena mpi3mr, mpi3mr_identifiers, nitems(mpi3mr_identifiers) - 1);
982d1d418eSSumit Saxena
992d1d418eSSumit Saxena MODULE_DEPEND(mpi3mr, cam, 1, 1, 1);
1002d1d418eSSumit Saxena
1012d1d418eSSumit Saxena /*
1022d1d418eSSumit Saxena * mpi3mr_setup_sysctl: setup sysctl values for mpi3mr
1032d1d418eSSumit Saxena * input: Adapter instance soft state
1042d1d418eSSumit Saxena *
1052d1d418eSSumit Saxena * Setup sysctl entries for mpi3mr driver.
1062d1d418eSSumit Saxena */
1072d1d418eSSumit Saxena static void
mpi3mr_setup_sysctl(struct mpi3mr_softc * sc)1082d1d418eSSumit Saxena mpi3mr_setup_sysctl(struct mpi3mr_softc *sc)
1092d1d418eSSumit Saxena {
1102d1d418eSSumit Saxena struct sysctl_ctx_list *sysctl_ctx = NULL;
1112d1d418eSSumit Saxena struct sysctl_oid *sysctl_tree = NULL;
1122d1d418eSSumit Saxena char tmpstr[80], tmpstr2[80];
1132d1d418eSSumit Saxena
1142d1d418eSSumit Saxena /*
1152d1d418eSSumit Saxena * Setup the sysctl variable so the user can change the debug level
1162d1d418eSSumit Saxena * on the fly.
1172d1d418eSSumit Saxena */
1182d1d418eSSumit Saxena snprintf(tmpstr, sizeof(tmpstr), "MPI3MR controller %d",
1192d1d418eSSumit Saxena device_get_unit(sc->mpi3mr_dev));
1202d1d418eSSumit Saxena snprintf(tmpstr2, sizeof(tmpstr2), "%d", device_get_unit(sc->mpi3mr_dev));
1212d1d418eSSumit Saxena
1222d1d418eSSumit Saxena sysctl_ctx = device_get_sysctl_ctx(sc->mpi3mr_dev);
1232d1d418eSSumit Saxena if (sysctl_ctx != NULL)
1242d1d418eSSumit Saxena sysctl_tree = device_get_sysctl_tree(sc->mpi3mr_dev);
1252d1d418eSSumit Saxena
1262d1d418eSSumit Saxena if (sysctl_tree == NULL) {
1272d1d418eSSumit Saxena sysctl_ctx_init(&sc->sysctl_ctx);
1282d1d418eSSumit Saxena sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
1292d1d418eSSumit Saxena SYSCTL_STATIC_CHILDREN(_hw_mpi3mr), OID_AUTO, tmpstr2,
1302d1d418eSSumit Saxena CTLFLAG_RD, 0, tmpstr);
1312d1d418eSSumit Saxena if (sc->sysctl_tree == NULL)
1322d1d418eSSumit Saxena return;
1332d1d418eSSumit Saxena sysctl_ctx = &sc->sysctl_ctx;
1342d1d418eSSumit Saxena sysctl_tree = sc->sysctl_tree;
1352d1d418eSSumit Saxena }
1362d1d418eSSumit Saxena
1372d1d418eSSumit Saxena SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
1382d1d418eSSumit Saxena OID_AUTO, "driver_version", CTLFLAG_RD, MPI3MR_DRIVER_VERSION,
1392d1d418eSSumit Saxena strlen(MPI3MR_DRIVER_VERSION), "driver version");
1402d1d418eSSumit Saxena
1412d1d418eSSumit Saxena SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
1422d1d418eSSumit Saxena OID_AUTO, "fw_outstanding", CTLFLAG_RD,
1432d1d418eSSumit Saxena &sc->fw_outstanding.val_rdonly, 0, "FW outstanding commands");
1442d1d418eSSumit Saxena
1452d1d418eSSumit Saxena SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
1462d1d418eSSumit Saxena OID_AUTO, "io_cmds_highwater", CTLFLAG_RD,
1472d1d418eSSumit Saxena &sc->io_cmds_highwater, 0, "Max FW outstanding commands");
1482d1d418eSSumit Saxena
14928a27434SWarner Losh SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
15028a27434SWarner Losh OID_AUTO, "firmware_version", CTLFLAG_RD, sc->fw_version,
15128a27434SWarner Losh strlen(sc->fw_version), "firmware version");
15228a27434SWarner Losh
1532d1d418eSSumit Saxena SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
1542d1d418eSSumit Saxena OID_AUTO, "mpi3mr_debug", CTLFLAG_RW, &sc->mpi3mr_debug, 0,
1552d1d418eSSumit Saxena "Driver debug level");
1562d1d418eSSumit Saxena SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
1572d1d418eSSumit Saxena OID_AUTO, "reset", CTLFLAG_RW, &sc->reset.type, 0,
1582d1d418eSSumit Saxena "Soft reset(1)/Diag reset(2)");
1592d1d418eSSumit Saxena SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
1602d1d418eSSumit Saxena OID_AUTO, "iot_enable", CTLFLAG_RW, &sc->iot_enable, 0,
1612d1d418eSSumit Saxena "IO throttling enable at driver level(for debug purpose)");
1622d1d418eSSumit Saxena }
1632d1d418eSSumit Saxena
1642d1d418eSSumit Saxena /*
1652d1d418eSSumit Saxena * mpi3mr_get_tunables: get tunable parameters.
1662d1d418eSSumit Saxena * input: Adapter instance soft state
1672d1d418eSSumit Saxena *
1682d1d418eSSumit Saxena * Get tunable parameters. This will help to debug driver at boot time.
1692d1d418eSSumit Saxena */
1702d1d418eSSumit Saxena static void
mpi3mr_get_tunables(struct mpi3mr_softc * sc)1712d1d418eSSumit Saxena mpi3mr_get_tunables(struct mpi3mr_softc *sc)
1722d1d418eSSumit Saxena {
1732d1d418eSSumit Saxena char tmpstr[80];
1742d1d418eSSumit Saxena
1752d1d418eSSumit Saxena sc->mpi3mr_debug =
1762d1d418eSSumit Saxena (MPI3MR_ERROR | MPI3MR_INFO | MPI3MR_FAULT);
1772d1d418eSSumit Saxena
1782d1d418eSSumit Saxena sc->reset_in_progress = 0;
1792d1d418eSSumit Saxena sc->reset.type = 0;
1802d1d418eSSumit Saxena sc->iot_enable = 1;
1812d1d418eSSumit Saxena /*
1822d1d418eSSumit Saxena * Grab the global variables.
1832d1d418eSSumit Saxena */
1842d1d418eSSumit Saxena TUNABLE_INT_FETCH("hw.mpi3mr.debug_level", &sc->mpi3mr_debug);
1852d1d418eSSumit Saxena TUNABLE_INT_FETCH("hw.mpi3mr.ctrl_reset", &sc->reset.type);
1862d1d418eSSumit Saxena TUNABLE_INT_FETCH("hw.mpi3mr.iot_enable", &sc->iot_enable);
1872d1d418eSSumit Saxena
1882d1d418eSSumit Saxena /* Grab the unit-instance variables */
1892d1d418eSSumit Saxena snprintf(tmpstr, sizeof(tmpstr), "dev.mpi3mr.%d.debug_level",
1902d1d418eSSumit Saxena device_get_unit(sc->mpi3mr_dev));
1912d1d418eSSumit Saxena TUNABLE_INT_FETCH(tmpstr, &sc->mpi3mr_debug);
1922d1d418eSSumit Saxena
1932d1d418eSSumit Saxena snprintf(tmpstr, sizeof(tmpstr), "dev.mpi3mr.%d.reset",
1942d1d418eSSumit Saxena device_get_unit(sc->mpi3mr_dev));
1952d1d418eSSumit Saxena TUNABLE_INT_FETCH(tmpstr, &sc->reset.type);
1962d1d418eSSumit Saxena
1972d1d418eSSumit Saxena snprintf(tmpstr, sizeof(tmpstr), "dev.mpi3mr.%d.iot_enable",
1982d1d418eSSumit Saxena device_get_unit(sc->mpi3mr_dev));
1992d1d418eSSumit Saxena TUNABLE_INT_FETCH(tmpstr, &sc->iot_enable);
2002d1d418eSSumit Saxena }
2012d1d418eSSumit Saxena
2022d1d418eSSumit Saxena static struct mpi3mr_ident *
mpi3mr_find_ident(device_t dev)2032d1d418eSSumit Saxena mpi3mr_find_ident(device_t dev)
2042d1d418eSSumit Saxena {
2052d1d418eSSumit Saxena struct mpi3mr_ident *m;
2062d1d418eSSumit Saxena
2072d1d418eSSumit Saxena for (m = mpi3mr_identifiers; m->vendor != 0; m++) {
2082d1d418eSSumit Saxena if (m->vendor != pci_get_vendor(dev))
2092d1d418eSSumit Saxena continue;
2102d1d418eSSumit Saxena if (m->device != pci_get_device(dev))
2112d1d418eSSumit Saxena continue;
2122d1d418eSSumit Saxena if ((m->subvendor != 0xffff) &&
2132d1d418eSSumit Saxena (m->subvendor != pci_get_subvendor(dev)))
2142d1d418eSSumit Saxena continue;
2152d1d418eSSumit Saxena if ((m->subdevice != 0xffff) &&
2162d1d418eSSumit Saxena (m->subdevice != pci_get_subdevice(dev)))
2172d1d418eSSumit Saxena continue;
2182d1d418eSSumit Saxena return (m);
2192d1d418eSSumit Saxena }
2202d1d418eSSumit Saxena
2212d1d418eSSumit Saxena return (NULL);
2222d1d418eSSumit Saxena }
2232d1d418eSSumit Saxena
2242d1d418eSSumit Saxena static int
mpi3mr_pci_probe(device_t dev)2252d1d418eSSumit Saxena mpi3mr_pci_probe(device_t dev)
2262d1d418eSSumit Saxena {
2272d1d418eSSumit Saxena static u_int8_t first_ctrl = 1;
2282d1d418eSSumit Saxena struct mpi3mr_ident *id;
2292d1d418eSSumit Saxena char raw_os_ver[16];
2302d1d418eSSumit Saxena
2312d1d418eSSumit Saxena if ((id = mpi3mr_find_ident(dev)) != NULL) {
2322d1d418eSSumit Saxena if (first_ctrl) {
2332d1d418eSSumit Saxena first_ctrl = 0;
2342d1d418eSSumit Saxena MPI3MR_OS_VERSION(raw_os_ver, fmt_os_ver);
2352d1d418eSSumit Saxena printf("mpi3mr: Loading Broadcom mpi3mr driver version: %s OS version: %s\n",
2362d1d418eSSumit Saxena MPI3MR_DRIVER_VERSION, fmt_os_ver);
2372d1d418eSSumit Saxena }
2382d1d418eSSumit Saxena device_set_desc(dev, id->desc);
2392d1d418eSSumit Saxena device_set_desc(dev, id->desc);
2402d1d418eSSumit Saxena return (BUS_PROBE_DEFAULT);
2412d1d418eSSumit Saxena }
2422d1d418eSSumit Saxena return (ENXIO);
2432d1d418eSSumit Saxena }
2442d1d418eSSumit Saxena
2452d1d418eSSumit Saxena static void
mpi3mr_release_resources(struct mpi3mr_softc * sc)2462d1d418eSSumit Saxena mpi3mr_release_resources(struct mpi3mr_softc *sc)
2472d1d418eSSumit Saxena {
2482d1d418eSSumit Saxena if (sc->mpi3mr_parent_dmat != NULL) {
2492d1d418eSSumit Saxena bus_dma_tag_destroy(sc->mpi3mr_parent_dmat);
2502d1d418eSSumit Saxena }
2512d1d418eSSumit Saxena
2522d1d418eSSumit Saxena if (sc->mpi3mr_regs_resource != NULL) {
2532d1d418eSSumit Saxena bus_release_resource(sc->mpi3mr_dev, SYS_RES_MEMORY,
2542d1d418eSSumit Saxena sc->mpi3mr_regs_rid, sc->mpi3mr_regs_resource);
2552d1d418eSSumit Saxena }
2562d1d418eSSumit Saxena }
2572d1d418eSSumit Saxena
mpi3mr_setup_resources(struct mpi3mr_softc * sc)2582d1d418eSSumit Saxena static int mpi3mr_setup_resources(struct mpi3mr_softc *sc)
2592d1d418eSSumit Saxena {
260489eee0dSAlexander Motin bus_dma_template_t t;
2612d1d418eSSumit Saxena int i;
2622d1d418eSSumit Saxena device_t dev = sc->mpi3mr_dev;
2632d1d418eSSumit Saxena
2642d1d418eSSumit Saxena pci_enable_busmaster(dev);
2652d1d418eSSumit Saxena
2662d1d418eSSumit Saxena for (i = 0; i < PCI_MAXMAPS_0; i++) {
2672d1d418eSSumit Saxena sc->mpi3mr_regs_rid = PCIR_BAR(i);
2682d1d418eSSumit Saxena
2692d1d418eSSumit Saxena if ((sc->mpi3mr_regs_resource = bus_alloc_resource_any(dev,
2702d1d418eSSumit Saxena SYS_RES_MEMORY, &sc->mpi3mr_regs_rid, RF_ACTIVE)) != NULL)
2712d1d418eSSumit Saxena break;
2722d1d418eSSumit Saxena }
2732d1d418eSSumit Saxena
2742d1d418eSSumit Saxena if (sc->mpi3mr_regs_resource == NULL) {
2752d1d418eSSumit Saxena mpi3mr_printf(sc, "Cannot allocate PCI registers\n");
2762d1d418eSSumit Saxena return (ENXIO);
2772d1d418eSSumit Saxena }
2782d1d418eSSumit Saxena
2792d1d418eSSumit Saxena sc->mpi3mr_btag = rman_get_bustag(sc->mpi3mr_regs_resource);
2802d1d418eSSumit Saxena sc->mpi3mr_bhandle = rman_get_bushandle(sc->mpi3mr_regs_resource);
2812d1d418eSSumit Saxena
28291d96135SWarner Losh /*
28391d96135SWarner Losh * XXX Perhaps we should move this to after we read iocfacts and use
28491d96135SWarner Losh * that to create the proper parent tag. However, to get the iocfacts
28591d96135SWarner Losh * we need to have a dmatag for both the admin queue and the iocfacts
28691d96135SWarner Losh * DMA transfer. So for now, we just create a 'no restriction' tag and
28791d96135SWarner Losh * use sc->dma_loaddr for all the other tag_create calls to get the
28891d96135SWarner Losh * right value. It would be nice if one could retroactively adjust a
28991d96135SWarner Losh * created tag. The Linux driver effectively does this by setting the
29091d96135SWarner Losh * dma_mask on the device.
29191d96135SWarner Losh */
2922d1d418eSSumit Saxena /* Allocate the parent DMA tag */
293489eee0dSAlexander Motin bus_dma_template_init(&t, bus_get_dma_tag(dev));
294489eee0dSAlexander Motin if (bus_dma_template_tag(&t, &sc->mpi3mr_parent_dmat)) {
2952d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate parent DMA tag\n");
2962d1d418eSSumit Saxena return (ENOMEM);
2972d1d418eSSumit Saxena }
2982d1d418eSSumit Saxena
2992d1d418eSSumit Saxena sc->max_msix_vectors = pci_msix_count(dev);
3002d1d418eSSumit Saxena
3012d1d418eSSumit Saxena return 0;
3022d1d418eSSumit Saxena }
3032d1d418eSSumit Saxena
3042d1d418eSSumit Saxena static int
mpi3mr_startup(struct mpi3mr_softc * sc)3052d1d418eSSumit Saxena mpi3mr_startup(struct mpi3mr_softc *sc)
3062d1d418eSSumit Saxena {
3072d1d418eSSumit Saxena sc->mpi3mr_flags &= ~MPI3MR_FLAGS_PORT_ENABLE_DONE;
3082d1d418eSSumit Saxena mpi3mr_issue_port_enable(sc, 1);
3092d1d418eSSumit Saxena return (0);
3102d1d418eSSumit Saxena }
3112d1d418eSSumit Saxena
3122d1d418eSSumit Saxena /* Run through any late-start handlers. */
3132d1d418eSSumit Saxena static void
mpi3mr_ich_startup(void * arg)3142d1d418eSSumit Saxena mpi3mr_ich_startup(void *arg)
3152d1d418eSSumit Saxena {
3162d1d418eSSumit Saxena struct mpi3mr_softc *sc;
3177e02c707SSumit Saxena int error;
3182d1d418eSSumit Saxena
3192d1d418eSSumit Saxena sc = (struct mpi3mr_softc *)arg;
3202d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "%s entry\n", __func__);
3212d1d418eSSumit Saxena
3222d1d418eSSumit Saxena mtx_lock(&sc->mpi3mr_mtx);
3232d1d418eSSumit Saxena
3242d1d418eSSumit Saxena mpi3mr_startup(sc);
3257e02c707SSumit Saxena
3262d1d418eSSumit Saxena mtx_unlock(&sc->mpi3mr_mtx);
3272d1d418eSSumit Saxena
3287e02c707SSumit Saxena error = mpi3mr_kproc_create(mpi3mr_watchdog_thread, sc,
3297e02c707SSumit Saxena &sc->watchdog_thread, 0, 0, "mpi3mr_watchdog%d",
3307e02c707SSumit Saxena device_get_unit(sc->mpi3mr_dev));
3317e02c707SSumit Saxena
3327e02c707SSumit Saxena if (error)
3337e02c707SSumit Saxena device_printf(sc->mpi3mr_dev, "Error %d starting OCR thread\n", error);
3347e02c707SSumit Saxena
3352d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "disestablish config intrhook\n");
3362d1d418eSSumit Saxena config_intrhook_disestablish(&sc->mpi3mr_ich);
3372d1d418eSSumit Saxena sc->mpi3mr_ich.ich_arg = NULL;
3382d1d418eSSumit Saxena
3392d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "%s exit\n", __func__);
3402d1d418eSSumit Saxena }
3412d1d418eSSumit Saxena
3422d1d418eSSumit Saxena /**
3432d1d418eSSumit Saxena * mpi3mr_ctrl_security_status -Check controller secure status
3442d1d418eSSumit Saxena * @pdev: PCI device instance
3452d1d418eSSumit Saxena *
3462d1d418eSSumit Saxena * Read the Device Serial Number capability from PCI config
3472d1d418eSSumit Saxena * space and decide whether the controller is secure or not.
3482d1d418eSSumit Saxena *
3492d1d418eSSumit Saxena * Return: 0 on success, non-zero on failure.
3502d1d418eSSumit Saxena */
3512d1d418eSSumit Saxena static int
mpi3mr_ctrl_security_status(device_t dev)3522d1d418eSSumit Saxena mpi3mr_ctrl_security_status(device_t dev)
3532d1d418eSSumit Saxena {
3542d1d418eSSumit Saxena int dev_serial_num, retval = 0;
3552d1d418eSSumit Saxena uint32_t cap_data, ctrl_status, debug_status;
3562d1d418eSSumit Saxena /* Check if Device serial number extended capability is supported */
3572d1d418eSSumit Saxena if (pci_find_extcap(dev, PCIZ_SERNUM, &dev_serial_num) != 0) {
3582d1d418eSSumit Saxena device_printf(dev,
3592d1d418eSSumit Saxena "PCIZ_SERNUM is not supported\n");
3602d1d418eSSumit Saxena return -1;
3612d1d418eSSumit Saxena }
3622d1d418eSSumit Saxena
3632d1d418eSSumit Saxena cap_data = pci_read_config(dev, dev_serial_num + 4, 4);
3642d1d418eSSumit Saxena
3652d1d418eSSumit Saxena debug_status = cap_data & MPI3MR_CTLR_SECURE_DBG_STATUS_MASK;
3662d1d418eSSumit Saxena ctrl_status = cap_data & MPI3MR_CTLR_SECURITY_STATUS_MASK;
3672d1d418eSSumit Saxena
3682d1d418eSSumit Saxena switch (ctrl_status) {
3692d1d418eSSumit Saxena case MPI3MR_INVALID_DEVICE:
3702d1d418eSSumit Saxena device_printf(dev,
3712d1d418eSSumit Saxena "Invalid (Non secure) controller is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",
3722d1d418eSSumit Saxena pci_get_device(dev), pci_get_subvendor(dev),
3732d1d418eSSumit Saxena pci_get_subdevice(dev));
3742d1d418eSSumit Saxena retval = -1;
3752d1d418eSSumit Saxena break;
3762d1d418eSSumit Saxena case MPI3MR_CONFIG_SECURE_DEVICE:
3772d1d418eSSumit Saxena if (!debug_status)
3782d1d418eSSumit Saxena device_printf(dev, "Config secure controller is detected\n");
3792d1d418eSSumit Saxena break;
3802d1d418eSSumit Saxena case MPI3MR_HARD_SECURE_DEVICE:
3812d1d418eSSumit Saxena device_printf(dev, "Hard secure controller is detected\n");
3822d1d418eSSumit Saxena break;
3832d1d418eSSumit Saxena case MPI3MR_TAMPERED_DEVICE:
3842d1d418eSSumit Saxena device_printf(dev,
3852d1d418eSSumit Saxena "Tampered (Non secure) controller is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",
3862d1d418eSSumit Saxena pci_get_device(dev), pci_get_subvendor(dev),
3872d1d418eSSumit Saxena pci_get_subdevice(dev));
3882d1d418eSSumit Saxena retval = -1;
3892d1d418eSSumit Saxena break;
3902d1d418eSSumit Saxena default:
3912d1d418eSSumit Saxena retval = -1;
3922d1d418eSSumit Saxena break;
3932d1d418eSSumit Saxena }
3942d1d418eSSumit Saxena
3952d1d418eSSumit Saxena if (!retval && debug_status) {
3962d1d418eSSumit Saxena device_printf(dev,
3972d1d418eSSumit Saxena "Secure Debug (Non secure) controller is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",
3982d1d418eSSumit Saxena pci_get_device(dev), pci_get_subvendor(dev),
3992d1d418eSSumit Saxena pci_get_subdevice(dev));
4002d1d418eSSumit Saxena retval = -1;
4012d1d418eSSumit Saxena }
4022d1d418eSSumit Saxena
4032d1d418eSSumit Saxena return retval;
4042d1d418eSSumit Saxena }
4052d1d418eSSumit Saxena /*
4062d1d418eSSumit Saxena * mpi3mr_pci_attach - PCI entry point
4072d1d418eSSumit Saxena * @dev: pointer to device struct
4082d1d418eSSumit Saxena *
4092d1d418eSSumit Saxena * This function does the setup of PCI and registers, allocates controller resources,
4102d1d418eSSumit Saxena * initializes mutexes, linked lists and registers interrupts, CAM and initializes
4112d1d418eSSumit Saxena * the controller.
4122d1d418eSSumit Saxena *
4132d1d418eSSumit Saxena * Return: 0 on success and proper error codes on failure
4142d1d418eSSumit Saxena */
4152d1d418eSSumit Saxena static int
mpi3mr_pci_attach(device_t dev)4162d1d418eSSumit Saxena mpi3mr_pci_attach(device_t dev)
4172d1d418eSSumit Saxena {
4182d1d418eSSumit Saxena struct mpi3mr_softc *sc;
4192d1d418eSSumit Saxena int error;
4202d1d418eSSumit Saxena
4212d1d418eSSumit Saxena sc = device_get_softc(dev);
4222d1d418eSSumit Saxena bzero(sc, sizeof(*sc));
4232d1d418eSSumit Saxena sc->mpi3mr_dev = dev;
4242d1d418eSSumit Saxena
4252d1d418eSSumit Saxena /* Don't load driver for Non-Secure controllers */
4262d1d418eSSumit Saxena if (mpi3mr_ctrl_security_status(dev)) {
4272d1d418eSSumit Saxena sc->secure_ctrl = false;
4282d1d418eSSumit Saxena return 0;
4292d1d418eSSumit Saxena }
4302d1d418eSSumit Saxena
4312d1d418eSSumit Saxena sc->secure_ctrl = true;
4322d1d418eSSumit Saxena
4332d1d418eSSumit Saxena if ((error = mpi3mr_setup_resources(sc)) != 0)
4342d1d418eSSumit Saxena goto load_failed;
4352d1d418eSSumit Saxena
4362d1d418eSSumit Saxena sc->id = sc_ids++;
4372d1d418eSSumit Saxena mpi3mr_atomic_set(&sc->fw_outstanding, 0);
4382d1d418eSSumit Saxena mpi3mr_atomic_set(&sc->pend_ioctls, 0);
4392d1d418eSSumit Saxena sc->admin_req = NULL;
4402d1d418eSSumit Saxena sc->admin_reply = NULL;
4412d1d418eSSumit Saxena sprintf(sc->driver_name, "%s", MPI3MR_DRIVER_NAME);
4422d1d418eSSumit Saxena sprintf(sc->name, "%s%d", sc->driver_name, sc->id);
4432d1d418eSSumit Saxena
4442d1d418eSSumit Saxena sc->mpi3mr_dev = dev;
4452d1d418eSSumit Saxena mpi3mr_get_tunables(sc);
4462d1d418eSSumit Saxena
4472d1d418eSSumit Saxena if ((error = mpi3mr_initialize_ioc(sc, MPI3MR_INIT_TYPE_INIT)) != 0) {
4482d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "FW initialization failed\n");
4492d1d418eSSumit Saxena goto load_failed;
4502d1d418eSSumit Saxena }
4512d1d418eSSumit Saxena
4522d1d418eSSumit Saxena if ((error = mpi3mr_alloc_requests(sc)) != 0) {
4532d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "Command frames allocation failed\n");
4542d1d418eSSumit Saxena goto load_failed;
4552d1d418eSSumit Saxena }
4562d1d418eSSumit Saxena
4572d1d418eSSumit Saxena if ((error = mpi3mr_cam_attach(sc)) != 0) {
4582d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "CAM attach failed\n");
4592d1d418eSSumit Saxena goto load_failed;
4602d1d418eSSumit Saxena }
4612d1d418eSSumit Saxena
4622d1d418eSSumit Saxena sc->mpi3mr_ich.ich_func = mpi3mr_ich_startup;
4632d1d418eSSumit Saxena sc->mpi3mr_ich.ich_arg = sc;
4642d1d418eSSumit Saxena if (config_intrhook_establish(&sc->mpi3mr_ich) != 0) {
4652d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR,
4662d1d418eSSumit Saxena "Cannot establish MPI3MR ICH config hook\n");
4672d1d418eSSumit Saxena error = EINVAL;
4682d1d418eSSumit Saxena }
4692d1d418eSSumit Saxena
4702d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, "allocating ioctl dma buffers\n");
4712d1d418eSSumit Saxena mpi3mr_alloc_ioctl_dma_memory(sc);
4722d1d418eSSumit Saxena
4732d1d418eSSumit Saxena if ((error = mpi3mr_app_attach(sc)) != 0) {
4742d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "APP/IOCTL attach failed\n");
4752d1d418eSSumit Saxena goto load_failed;
4762d1d418eSSumit Saxena }
4772d1d418eSSumit Saxena
4782d1d418eSSumit Saxena mpi3mr_setup_sysctl(sc);
4792d1d418eSSumit Saxena
4802d1d418eSSumit Saxena return 0;
4812d1d418eSSumit Saxena
4822d1d418eSSumit Saxena load_failed:
4832d1d418eSSumit Saxena mpi3mr_cleanup_interrupts(sc);
4842d1d418eSSumit Saxena mpi3mr_free_mem(sc);
4852d1d418eSSumit Saxena mpi3mr_app_detach(sc);
4862d1d418eSSumit Saxena mpi3mr_cam_detach(sc);
4872d1d418eSSumit Saxena mpi3mr_destory_mtx(sc);
4882d1d418eSSumit Saxena mpi3mr_release_resources(sc);
4892d1d418eSSumit Saxena return error;
4902d1d418eSSumit Saxena }
4912d1d418eSSumit Saxena
mpi3mr_cleanup_interrupts(struct mpi3mr_softc * sc)4922d1d418eSSumit Saxena void mpi3mr_cleanup_interrupts(struct mpi3mr_softc *sc)
4932d1d418eSSumit Saxena {
4942d1d418eSSumit Saxena mpi3mr_disable_interrupts(sc);
4952d1d418eSSumit Saxena
4962d1d418eSSumit Saxena mpi3mr_teardown_irqs(sc);
4972d1d418eSSumit Saxena
4982d1d418eSSumit Saxena if (sc->irq_ctx) {
4992d1d418eSSumit Saxena free(sc->irq_ctx, M_MPI3MR);
5002d1d418eSSumit Saxena sc->irq_ctx = NULL;
5012d1d418eSSumit Saxena }
5022d1d418eSSumit Saxena
5032d1d418eSSumit Saxena if (sc->msix_enable)
5042d1d418eSSumit Saxena pci_release_msi(sc->mpi3mr_dev);
5052d1d418eSSumit Saxena
5062d1d418eSSumit Saxena sc->msix_count = 0;
5072d1d418eSSumit Saxena
5082d1d418eSSumit Saxena }
5092d1d418eSSumit Saxena
mpi3mr_setup_irqs(struct mpi3mr_softc * sc)5102d1d418eSSumit Saxena int mpi3mr_setup_irqs(struct mpi3mr_softc *sc)
5112d1d418eSSumit Saxena {
5122d1d418eSSumit Saxena device_t dev;
5132d1d418eSSumit Saxena int error;
5142d1d418eSSumit Saxena int i, rid, initial_rid;
5152d1d418eSSumit Saxena struct mpi3mr_irq_context *irq_ctx;
5162d1d418eSSumit Saxena struct irq_info *irq_info;
5172d1d418eSSumit Saxena
5182d1d418eSSumit Saxena dev = sc->mpi3mr_dev;
5192d1d418eSSumit Saxena error = -1;
5202d1d418eSSumit Saxena
5212d1d418eSSumit Saxena if (sc->msix_enable)
5222d1d418eSSumit Saxena initial_rid = 1;
5232d1d418eSSumit Saxena else
5242d1d418eSSumit Saxena initial_rid = 0;
5252d1d418eSSumit Saxena
5262d1d418eSSumit Saxena for (i = 0; i < sc->msix_count; i++) {
5272d1d418eSSumit Saxena irq_ctx = &sc->irq_ctx[i];
5282d1d418eSSumit Saxena irq_ctx->msix_index = i;
5292d1d418eSSumit Saxena irq_ctx->sc = sc;
5302d1d418eSSumit Saxena irq_info = &irq_ctx->irq_info;
5312d1d418eSSumit Saxena rid = i + initial_rid;
5322d1d418eSSumit Saxena irq_info->irq_rid = rid;
5332d1d418eSSumit Saxena irq_info->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
5342d1d418eSSumit Saxena &irq_info->irq_rid, RF_ACTIVE);
5352d1d418eSSumit Saxena if (irq_info->irq == NULL) {
5362d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR,
5372d1d418eSSumit Saxena "Cannot allocate interrupt RID %d\n", rid);
5382d1d418eSSumit Saxena sc->msix_count = i;
5392d1d418eSSumit Saxena break;
5402d1d418eSSumit Saxena }
5412d1d418eSSumit Saxena error = bus_setup_intr(dev, irq_info->irq,
5422d1d418eSSumit Saxena INTR_MPSAFE | INTR_TYPE_CAM, NULL, mpi3mr_isr,
5432d1d418eSSumit Saxena irq_ctx, &irq_info->intrhand);
5442d1d418eSSumit Saxena if (error) {
5452d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR,
5462d1d418eSSumit Saxena "Cannot setup interrupt RID %d\n", rid);
5472d1d418eSSumit Saxena sc->msix_count = i;
5482d1d418eSSumit Saxena break;
5492d1d418eSSumit Saxena }
5502d1d418eSSumit Saxena }
5512d1d418eSSumit Saxena
5522d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, "Set up %d MSI-x interrupts\n", sc->msix_count);
5532d1d418eSSumit Saxena
5542d1d418eSSumit Saxena return (error);
5552d1d418eSSumit Saxena
5562d1d418eSSumit Saxena }
5572d1d418eSSumit Saxena
5582d1d418eSSumit Saxena static void
mpi3mr_teardown_irqs(struct mpi3mr_softc * sc)5592d1d418eSSumit Saxena mpi3mr_teardown_irqs(struct mpi3mr_softc *sc)
5602d1d418eSSumit Saxena {
5612d1d418eSSumit Saxena struct irq_info *irq_info;
5622d1d418eSSumit Saxena int i;
5632d1d418eSSumit Saxena
5642d1d418eSSumit Saxena for (i = 0; i < sc->msix_count; i++) {
5652d1d418eSSumit Saxena irq_info = &sc->irq_ctx[i].irq_info;
5662d1d418eSSumit Saxena if (irq_info->irq != NULL) {
5672d1d418eSSumit Saxena bus_teardown_intr(sc->mpi3mr_dev, irq_info->irq,
5682d1d418eSSumit Saxena irq_info->intrhand);
5692d1d418eSSumit Saxena bus_release_resource(sc->mpi3mr_dev, SYS_RES_IRQ,
5702d1d418eSSumit Saxena irq_info->irq_rid, irq_info->irq);
5712d1d418eSSumit Saxena }
5722d1d418eSSumit Saxena }
5732d1d418eSSumit Saxena
5742d1d418eSSumit Saxena }
5752d1d418eSSumit Saxena
5762d1d418eSSumit Saxena /*
5772d1d418eSSumit Saxena * Allocate, but don't assign interrupts early. Doing it before requesting
5782d1d418eSSumit Saxena * the IOCFacts message informs the firmware that we want to do MSI-X
5792d1d418eSSumit Saxena * multiqueue. We might not use all of the available messages, but there's
5802d1d418eSSumit Saxena * no reason to re-alloc if we don't.
5812d1d418eSSumit Saxena */
5822d1d418eSSumit Saxena int
mpi3mr_alloc_interrupts(struct mpi3mr_softc * sc,U16 setup_one)5832d1d418eSSumit Saxena mpi3mr_alloc_interrupts(struct mpi3mr_softc *sc, U16 setup_one)
5842d1d418eSSumit Saxena {
5852d1d418eSSumit Saxena int error, msgs;
5862d1d418eSSumit Saxena U16 num_queues;
5872d1d418eSSumit Saxena
5882d1d418eSSumit Saxena error = 0;
5892d1d418eSSumit Saxena msgs = 0;
5902d1d418eSSumit Saxena
5912d1d418eSSumit Saxena mpi3mr_cleanup_interrupts(sc);
5922d1d418eSSumit Saxena
5932d1d418eSSumit Saxena if (setup_one) {
5942d1d418eSSumit Saxena msgs = 1;
5952d1d418eSSumit Saxena } else {
5962d1d418eSSumit Saxena msgs = min(sc->max_msix_vectors, sc->cpu_count);
5972d1d418eSSumit Saxena num_queues = min(sc->facts.max_op_reply_q, sc->facts.max_op_req_q);
5982d1d418eSSumit Saxena msgs = min(msgs, num_queues);
5992d1d418eSSumit Saxena
6002d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, "Supported MSI-x count: %d "
6012d1d418eSSumit Saxena " CPU count: %d Requested MSI-x count: %d\n",
6022d1d418eSSumit Saxena sc->max_msix_vectors,
6032d1d418eSSumit Saxena sc->cpu_count, msgs);
6042d1d418eSSumit Saxena }
6052d1d418eSSumit Saxena
6062d1d418eSSumit Saxena if (msgs != 0) {
6072d1d418eSSumit Saxena error = pci_alloc_msix(sc->mpi3mr_dev, &msgs);
6082d1d418eSSumit Saxena if (error) {
6092d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR,
6102d1d418eSSumit Saxena "Could not allocate MSI-x interrupts Error: %x\n", error);
6112d1d418eSSumit Saxena goto out_failed;
6122d1d418eSSumit Saxena } else
6132d1d418eSSumit Saxena sc->msix_enable = 1;
6142d1d418eSSumit Saxena }
6152d1d418eSSumit Saxena
6162d1d418eSSumit Saxena sc->msix_count = msgs;
6172d1d418eSSumit Saxena sc->irq_ctx = malloc(sizeof(struct mpi3mr_irq_context) * msgs,
6182d1d418eSSumit Saxena M_MPI3MR, M_NOWAIT | M_ZERO);
6192d1d418eSSumit Saxena
6202d1d418eSSumit Saxena if (!sc->irq_ctx) {
6212d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot alloc memory for interrupt info\n");
6222d1d418eSSumit Saxena error = -1;
6232d1d418eSSumit Saxena goto out_failed;
6242d1d418eSSumit Saxena }
6252d1d418eSSumit Saxena
6262d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "Allocated %d MSI-x interrupts\n", msgs);
6272d1d418eSSumit Saxena
6282d1d418eSSumit Saxena return error;
6292d1d418eSSumit Saxena out_failed:
6302d1d418eSSumit Saxena mpi3mr_cleanup_interrupts(sc);
6312d1d418eSSumit Saxena return (error);
6322d1d418eSSumit Saxena }
6332d1d418eSSumit Saxena
6342d1d418eSSumit Saxena static int
mpi3mr_pci_detach(device_t dev)6352d1d418eSSumit Saxena mpi3mr_pci_detach(device_t dev)
6362d1d418eSSumit Saxena {
6372d1d418eSSumit Saxena struct mpi3mr_softc *sc;
6382d1d418eSSumit Saxena int i = 0;
6392d1d418eSSumit Saxena
6402d1d418eSSumit Saxena sc = device_get_softc(dev);
6412d1d418eSSumit Saxena
6422d1d418eSSumit Saxena if (!sc->secure_ctrl)
6432d1d418eSSumit Saxena return 0;
6442d1d418eSSumit Saxena
6452d1d418eSSumit Saxena
6462d1d418eSSumit Saxena if (sc->sysctl_tree != NULL)
6472d1d418eSSumit Saxena sysctl_ctx_free(&sc->sysctl_ctx);
6482d1d418eSSumit Saxena
6497c491309SWarner Losh mtx_lock(&sc->reset_mutex);
6507c491309SWarner Losh sc->mpi3mr_flags |= MPI3MR_FLAGS_SHUTDOWN;
6512d1d418eSSumit Saxena if (sc->watchdog_thread_active)
6522d1d418eSSumit Saxena wakeup(&sc->watchdog_chan);
6537c491309SWarner Losh mtx_unlock(&sc->reset_mutex);
6542d1d418eSSumit Saxena
6552d1d418eSSumit Saxena while (sc->reset_in_progress && (i < PEND_IOCTLS_COMP_WAIT_TIME)) {
6562d1d418eSSumit Saxena i++;
6572d1d418eSSumit Saxena if (!(i % 5)) {
6582d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO,
6592d1d418eSSumit Saxena "[%2d]waiting for reset to be finished from %s\n", i, __func__);
6602d1d418eSSumit Saxena }
6612d1d418eSSumit Saxena pause("mpi3mr_shutdown", hz);
6622d1d418eSSumit Saxena }
6632d1d418eSSumit Saxena
6642d1d418eSSumit Saxena i = 0;
6652d1d418eSSumit Saxena while (sc->watchdog_thread_active && (i < 180)) {
6662d1d418eSSumit Saxena i++;
6672d1d418eSSumit Saxena if (!(i % 5)) {
6682d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO,
6692d1d418eSSumit Saxena "[%2d]waiting for "
6702d1d418eSSumit Saxena "mpi3mr_reset thread to quit reset %d\n", i,
6712d1d418eSSumit Saxena sc->watchdog_thread_active);
6722d1d418eSSumit Saxena }
6732d1d418eSSumit Saxena pause("mpi3mr_shutdown", hz);
6742d1d418eSSumit Saxena }
6752d1d418eSSumit Saxena
6762d1d418eSSumit Saxena i = 0;
6772d1d418eSSumit Saxena while (mpi3mr_atomic_read(&sc->pend_ioctls) && (i < 180)) {
6782d1d418eSSumit Saxena i++;
6792d1d418eSSumit Saxena if (!(i % 5)) {
6802d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO,
6812d1d418eSSumit Saxena "[%2d]waiting for IOCTL to be finished from %s\n", i, __func__);
6822d1d418eSSumit Saxena }
6832d1d418eSSumit Saxena pause("mpi3mr_shutdown", hz);
6842d1d418eSSumit Saxena }
6852d1d418eSSumit Saxena
6862d1d418eSSumit Saxena mpi3mr_cleanup_ioc(sc);
6872d1d418eSSumit Saxena mpi3mr_cleanup_event_taskq(sc);
6882d1d418eSSumit Saxena mpi3mr_app_detach(sc);
6892d1d418eSSumit Saxena mpi3mr_cam_detach(sc);
6902d1d418eSSumit Saxena mpi3mr_cleanup_interrupts(sc);
6912d1d418eSSumit Saxena mpi3mr_destory_mtx(sc);
6922d1d418eSSumit Saxena mpi3mr_free_mem(sc);
6932d1d418eSSumit Saxena mpi3mr_release_resources(sc);
6942d1d418eSSumit Saxena sc_ids--;
6952d1d418eSSumit Saxena return (0);
6962d1d418eSSumit Saxena }
6972d1d418eSSumit Saxena
6982d1d418eSSumit Saxena static int
mpi3mr_pci_suspend(device_t dev)6992d1d418eSSumit Saxena mpi3mr_pci_suspend(device_t dev)
7002d1d418eSSumit Saxena {
7012d1d418eSSumit Saxena return (EINVAL);
7022d1d418eSSumit Saxena }
7032d1d418eSSumit Saxena
7042d1d418eSSumit Saxena static int
mpi3mr_pci_resume(device_t dev)7052d1d418eSSumit Saxena mpi3mr_pci_resume(device_t dev)
7062d1d418eSSumit Saxena {
7072d1d418eSSumit Saxena return (EINVAL);
7082d1d418eSSumit Saxena }
709