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