xref: /freebsd-src/sys/dev/mpi3mr/mpi3mr_pci.c (revision 945c3ce49ed127de6ccd6d55a944d8a58291c315)
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