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