xref: /freebsd-src/sys/dev/mfi/mfi_pci.c (revision d174ffca3a79171069cb041f81c2680a6e4809ed)
12e21a3efSScott Long /*-
2eebd9d53SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
42e21a3efSScott Long  * Copyright (c) 2006 IronPort Systems
52e21a3efSScott Long  * All rights reserved.
62e21a3efSScott Long  *
72e21a3efSScott Long  * Redistribution and use in source and binary forms, with or without
82e21a3efSScott Long  * modification, are permitted provided that the following conditions
92e21a3efSScott Long  * are met:
102e21a3efSScott Long  * 1. Redistributions of source code must retain the above copyright
112e21a3efSScott Long  *    notice, this list of conditions and the following disclaimer.
122e21a3efSScott Long  * 2. Redistributions in binary form must reproduce the above copyright
132e21a3efSScott Long  *    notice, this list of conditions and the following disclaimer in the
142e21a3efSScott Long  *    documentation and/or other materials provided with the distribution.
152e21a3efSScott Long  *
162e21a3efSScott Long  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
172e21a3efSScott Long  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
182e21a3efSScott Long  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
192e21a3efSScott Long  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
202e21a3efSScott Long  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
212e21a3efSScott Long  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
222e21a3efSScott Long  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
232e21a3efSScott Long  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
242e21a3efSScott Long  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
252e21a3efSScott Long  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
262e21a3efSScott Long  * SUCH DAMAGE.
272e21a3efSScott Long  */
28610f2ef3SScott Long /*-
29610f2ef3SScott Long  * Copyright (c) 2007 LSI Corp.
30610f2ef3SScott Long  * Copyright (c) 2007 Rajesh Prabhakaran.
31610f2ef3SScott Long  * All rights reserved.
32610f2ef3SScott Long  *
33610f2ef3SScott Long  * Redistribution and use in source and binary forms, with or without
34610f2ef3SScott Long  * modification, are permitted provided that the following conditions
35610f2ef3SScott Long  * are met:
36610f2ef3SScott Long  * 1. Redistributions of source code must retain the above copyright
37610f2ef3SScott Long  *    notice, this list of conditions and the following disclaimer.
38610f2ef3SScott Long  * 2. Redistributions in binary form must reproduce the above copyright
39610f2ef3SScott Long  *    notice, this list of conditions and the following disclaimer in the
40610f2ef3SScott Long  *    documentation and/or other materials provided with the distribution.
41610f2ef3SScott Long  *
42610f2ef3SScott Long  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
43610f2ef3SScott Long  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44610f2ef3SScott Long  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45610f2ef3SScott Long  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
46610f2ef3SScott Long  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47610f2ef3SScott Long  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48610f2ef3SScott Long  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49610f2ef3SScott Long  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50610f2ef3SScott Long  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51610f2ef3SScott Long  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52610f2ef3SScott Long  * SUCH DAMAGE.
53610f2ef3SScott Long  */
542e21a3efSScott Long 
552e21a3efSScott Long #include <sys/cdefs.h>
562e21a3efSScott Long /* PCI/PCI-X/PCIe bus interface for the LSI MegaSAS controllers */
572e21a3efSScott Long 
582e21a3efSScott Long #include "opt_mfi.h"
592e21a3efSScott Long 
602e21a3efSScott Long #include <sys/param.h>
61e2e050c8SConrad Meyer #include <sys/bio.h>
622e21a3efSScott Long #include <sys/bus.h>
632e21a3efSScott Long #include <sys/conf.h>
64e2e050c8SConrad Meyer #include <sys/eventhandler.h>
65e2e050c8SConrad Meyer #include <sys/kernel.h>
66e2e050c8SConrad Meyer #include <sys/lock.h>
67e2e050c8SConrad Meyer #include <sys/module.h>
682e21a3efSScott Long #include <sys/malloc.h>
69e2e050c8SConrad Meyer #include <sys/mutex.h>
70e2e050c8SConrad Meyer #include <sys/selinfo.h>
71d1c5fc76SJohn Baldwin #include <sys/sysctl.h>
72e2e050c8SConrad Meyer #include <sys/systm.h>
73741367d5SDoug Ambrisko #include <sys/uio.h>
742e21a3efSScott Long 
752e21a3efSScott Long #include <machine/bus.h>
762e21a3efSScott Long #include <machine/resource.h>
772e21a3efSScott Long #include <sys/rman.h>
782e21a3efSScott Long 
792e21a3efSScott Long #include <dev/pci/pcireg.h>
802e21a3efSScott Long #include <dev/pci/pcivar.h>
812e21a3efSScott Long 
822e21a3efSScott Long #include <dev/mfi/mfireg.h>
832e21a3efSScott Long #include <dev/mfi/mfi_ioctl.h>
842e21a3efSScott Long #include <dev/mfi/mfivar.h>
852e21a3efSScott Long 
862e21a3efSScott Long static int	mfi_pci_probe(device_t);
872e21a3efSScott Long static int	mfi_pci_attach(device_t);
882e21a3efSScott Long static int	mfi_pci_detach(device_t);
892e21a3efSScott Long static int	mfi_pci_suspend(device_t);
902e21a3efSScott Long static int	mfi_pci_resume(device_t);
912e21a3efSScott Long static void	mfi_pci_free(struct mfi_softc *);
922e21a3efSScott Long 
932e21a3efSScott Long static device_method_t mfi_methods[] = {
942e21a3efSScott Long 	DEVMETHOD(device_probe,		mfi_pci_probe),
952e21a3efSScott Long 	DEVMETHOD(device_attach,	mfi_pci_attach),
962e21a3efSScott Long 	DEVMETHOD(device_detach,	mfi_pci_detach),
972e21a3efSScott Long 	DEVMETHOD(device_suspend,	mfi_pci_suspend),
982e21a3efSScott Long 	DEVMETHOD(device_resume,	mfi_pci_resume),
994b7ec270SMarius Strobl 
1004b7ec270SMarius Strobl 	DEVMETHOD_END
1012e21a3efSScott Long };
1022e21a3efSScott Long 
1032e21a3efSScott Long static driver_t mfi_pci_driver = {
1042e21a3efSScott Long 	"mfi",
1052e21a3efSScott Long 	mfi_methods,
1062e21a3efSScott Long 	sizeof(struct mfi_softc)
1072e21a3efSScott Long };
1082e21a3efSScott Long 
109a6ba0fd6SDoug Ambrisko static int	mfi_msi = 1;
110d1c5fc76SJohn Baldwin SYSCTL_INT(_hw_mfi, OID_AUTO, msi, CTLFLAG_RDTUN, &mfi_msi, 0,
111d1c5fc76SJohn Baldwin     "Enable use of MSI interrupts");
112d1c5fc76SJohn Baldwin 
113af3b2549SHans Petter Selasky static int	mfi_mrsas_enable;
11496f9425fSDoug Ambrisko SYSCTL_INT(_hw_mfi, OID_AUTO, mrsas_enable, CTLFLAG_RDTUN, &mfi_mrsas_enable,
115e0dcb9b6SEd Maste      0, "Allow mrsas to take newer cards");
11696f9425fSDoug Ambrisko 
1172e21a3efSScott Long struct mfi_ident {
1182e21a3efSScott Long 	uint16_t	vendor;
1192e21a3efSScott Long 	uint16_t	device;
1202e21a3efSScott Long 	uint16_t	subvendor;
1212e21a3efSScott Long 	uint16_t	subdevice;
1222e21a3efSScott Long 	int		flags;
1232e21a3efSScott Long 	const char	*desc;
1242e21a3efSScott Long } mfi_identifiers[] = {
1256ad638acSWojciech Macek 	{0x1000, 0x005b, 0x1028, 0x1fc9, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT| MFI_FLAGS_MRSAS, "Dell PERC H840 Adapter"},
12696f9425fSDoug Ambrisko 	{0x1000, 0x005b, 0x1028, 0x1f2d, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT| MFI_FLAGS_MRSAS, "Dell PERC H810 Adapter"},
12796f9425fSDoug Ambrisko 	{0x1000, 0x005b, 0x1028, 0x1f30, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT| MFI_FLAGS_MRSAS, "Dell PERC H710 Embedded"},
12896f9425fSDoug Ambrisko 	{0x1000, 0x005b, 0x1028, 0x1f31, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT| MFI_FLAGS_MRSAS, "Dell PERC H710P Adapter"},
12996f9425fSDoug Ambrisko 	{0x1000, 0x005b, 0x1028, 0x1f33, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT| MFI_FLAGS_MRSAS, "Dell PERC H710P Mini (blades)"},
13096f9425fSDoug Ambrisko 	{0x1000, 0x005b, 0x1028, 0x1f34, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT| MFI_FLAGS_MRSAS, "Dell PERC H710P Mini (monolithics)"},
13196f9425fSDoug Ambrisko 	{0x1000, 0x005b, 0x1028, 0x1f35, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT| MFI_FLAGS_MRSAS, "Dell PERC H710 Adapter"},
13296f9425fSDoug Ambrisko 	{0x1000, 0x005b, 0x1028, 0x1f37, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT| MFI_FLAGS_MRSAS, "Dell PERC H710 Mini (blades)"},
13396f9425fSDoug Ambrisko 	{0x1000, 0x005b, 0x1028, 0x1f38, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT| MFI_FLAGS_MRSAS, "Dell PERC H710 Mini (monolithics)"},
13496f9425fSDoug Ambrisko 	{0x1000, 0x005b, 0x8086, 0x9265, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT| MFI_FLAGS_MRSAS, "Intel (R) RAID Controller RS25DB080"},
13596f9425fSDoug Ambrisko 	{0x1000, 0x005b, 0x8086, 0x9285, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT| MFI_FLAGS_MRSAS, "Intel (R) RAID Controller RS25NB008"},
13696f9425fSDoug Ambrisko 	{0x1000, 0x005b, 0xffff, 0xffff, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT| MFI_FLAGS_MRSAS, "ThunderBolt"},
1373b8ad66eSMark Johnston 	{0x1000, 0x005d, 0xffff, 0xffff, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT| MFI_FLAGS_MRSAS| MFI_FLAGS_INVADER, "Invader"},
1383b8ad66eSMark Johnston 	{0x1000, 0x005f, 0xffff, 0xffff, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT| MFI_FLAGS_MRSAS| MFI_FLAGS_FURY, "Fury"},
1394844f5c0SDoug Ambrisko 	{0x1000, 0x0060, 0x1028, 0xffff, MFI_FLAGS_1078,  "Dell PERC 6"},
140610f2ef3SScott Long 	{0x1000, 0x0060, 0xffff, 0xffff, MFI_FLAGS_1078,  "LSI MegaSAS 1078"},
1410d9a4ef3SDoug Ambrisko 	{0x1000, 0x0071, 0xffff, 0xffff, MFI_FLAGS_SKINNY, "Drake Skinny"},
1420d9a4ef3SDoug Ambrisko 	{0x1000, 0x0073, 0xffff, 0xffff, MFI_FLAGS_SKINNY, "Drake Skinny"},
1432997859fSDoug Ambrisko 	{0x1000, 0x0078, 0xffff, 0xffff, MFI_FLAGS_GEN2,  "LSI MegaSAS Gen2"},
144d205405cSDoug Ambrisko 	{0x1000, 0x0079, 0x1028, 0x1f15, MFI_FLAGS_GEN2,  "Dell PERC H800 Adapter"},
145d205405cSDoug Ambrisko 	{0x1000, 0x0079, 0x1028, 0x1f16, MFI_FLAGS_GEN2,  "Dell PERC H700 Adapter"},
146d205405cSDoug Ambrisko 	{0x1000, 0x0079, 0x1028, 0x1f17, MFI_FLAGS_GEN2,  "Dell PERC H700 Integrated"},
147d205405cSDoug Ambrisko 	{0x1000, 0x0079, 0x1028, 0x1f18, MFI_FLAGS_GEN2,  "Dell PERC H700 Modular"},
148bd97b1f4SDoug Ambrisko 	{0x1000, 0x0079, 0x1028, 0x1f19, MFI_FLAGS_GEN2,  "Dell PERC H700"},
1490d9a4ef3SDoug Ambrisko 	{0x1000, 0x0079, 0x1028, 0x1f1a, MFI_FLAGS_GEN2,  "Dell PERC H800 Proto Adapter"},
150bd97b1f4SDoug Ambrisko 	{0x1000, 0x0079, 0x1028, 0x1f1b, MFI_FLAGS_GEN2,  "Dell PERC H800"},
151216d58bbSDoug Ambrisko 	{0x1000, 0x0079, 0x1028, 0xffff, MFI_FLAGS_GEN2,  "Dell PERC Gen2"},
152fa1e6ef4SDoug Ambrisko 	{0x1000, 0x0079, 0xffff, 0xffff, MFI_FLAGS_GEN2,  "LSI MegaSAS Gen2"},
153fa1e6ef4SDoug Ambrisko 	{0x1000, 0x007c, 0xffff, 0xffff, MFI_FLAGS_1078,  "LSI MegaSAS 1078"},
1542997859fSDoug Ambrisko 	{0x1000, 0x0411, 0xffff, 0xffff, MFI_FLAGS_1064R, "LSI MegaSAS 1064R"}, /* Brocton IOP */
1552997859fSDoug Ambrisko 	{0x1000, 0x0413, 0xffff, 0xffff, MFI_FLAGS_1064R, "LSI MegaSAS 1064R"}, /* Verde ZCR */
1562997859fSDoug Ambrisko 	{0x1028, 0x0015, 0xffff, 0xffff, MFI_FLAGS_1064R, "Dell PERC 5/i"},
1572e21a3efSScott Long 	{0, 0, 0, 0, 0, NULL}
1582e21a3efSScott Long };
1592e21a3efSScott Long 
160354f6c1cSJohn Baldwin DRIVER_MODULE(mfi, pci, mfi_pci_driver, 0, 0);
1610dc34160SWarner Losh MODULE_PNP_INFO("U16:vendor;U16:device;U16:subvendor;U16:subdevice", pci, mfi,
1620dc34160SWarner Losh     mfi_identifiers, nitems(mfi_identifiers) - 1);
1630dc34160SWarner Losh MODULE_VERSION(mfi, 1);
1640dc34160SWarner Losh 
1652e21a3efSScott Long static struct mfi_ident *
1662e21a3efSScott Long mfi_find_ident(device_t dev)
1672e21a3efSScott Long {
1682e21a3efSScott Long 	struct mfi_ident *m;
1692e21a3efSScott Long 
1702e21a3efSScott Long 	for (m = mfi_identifiers; m->vendor != 0; m++) {
1712e21a3efSScott Long 		if ((m->vendor == pci_get_vendor(dev)) &&
1722e21a3efSScott Long 		    (m->device == pci_get_device(dev)) &&
1732e21a3efSScott Long 		    ((m->subvendor == pci_get_subvendor(dev)) ||
1742e21a3efSScott Long 		    (m->subvendor == 0xffff)) &&
1752e21a3efSScott Long 		    ((m->subdevice == pci_get_subdevice(dev)) ||
1762e21a3efSScott Long 		    (m->subdevice == 0xffff)))
1772e21a3efSScott Long 			return (m);
1782e21a3efSScott Long 	}
1792e21a3efSScott Long 
1802e21a3efSScott Long 	return (NULL);
1812e21a3efSScott Long }
1822e21a3efSScott Long 
1832e21a3efSScott Long static int
1842e21a3efSScott Long mfi_pci_probe(device_t dev)
1852e21a3efSScott Long {
1862e21a3efSScott Long 	struct mfi_ident *id;
1872e21a3efSScott Long 
1882e21a3efSScott Long 	if ((id = mfi_find_ident(dev)) != NULL) {
1892e21a3efSScott Long 		device_set_desc(dev, id->desc);
19096f9425fSDoug Ambrisko 
19196f9425fSDoug Ambrisko 		/* give priority to mrsas if tunable set */
19296f9425fSDoug Ambrisko 		if ((id->flags & MFI_FLAGS_MRSAS) && mfi_mrsas_enable)
19396f9425fSDoug Ambrisko 			return (BUS_PROBE_LOW_PRIORITY);
19496f9425fSDoug Ambrisko 		else
1952e21a3efSScott Long 			return (BUS_PROBE_DEFAULT);
1962e21a3efSScott Long 	}
1972e21a3efSScott Long 	return (ENXIO);
1982e21a3efSScott Long }
1992e21a3efSScott Long 
2002e21a3efSScott Long static int
2012e21a3efSScott Long mfi_pci_attach(device_t dev)
2022e21a3efSScott Long {
2032e21a3efSScott Long 	struct mfi_softc *sc;
2042e21a3efSScott Long 	struct mfi_ident *m;
205d1c5fc76SJohn Baldwin 	int count, error;
2062e21a3efSScott Long 
2072e21a3efSScott Long 	sc = device_get_softc(dev);
2082e21a3efSScott Long 	bzero(sc, sizeof(*sc));
2092e21a3efSScott Long 	sc->mfi_dev = dev;
210fa1e6ef4SDoug Ambrisko 	m = mfi_find_ident(dev);
211fa1e6ef4SDoug Ambrisko 	sc->mfi_flags = m->flags;
2122e21a3efSScott Long 
213c68534f1SScott Long 	/* Ensure busmastering is enabled */
214c68534f1SScott Long 	pci_enable_busmaster(dev);
2152e21a3efSScott Long 
2162e21a3efSScott Long 	/* Allocate PCI registers */
217fa1e6ef4SDoug Ambrisko 	if ((sc->mfi_flags & MFI_FLAGS_1064R) ||
218fa1e6ef4SDoug Ambrisko 	    (sc->mfi_flags & MFI_FLAGS_1078)) {
219fa1e6ef4SDoug Ambrisko 		/* 1068/1078: Memory mapped BAR is at offset 0x10 */
2202e21a3efSScott Long 		sc->mfi_regs_rid = PCIR_BAR(0);
2210d9a4ef3SDoug Ambrisko 	}
2220d9a4ef3SDoug Ambrisko 	else if ((sc->mfi_flags & MFI_FLAGS_GEN2) ||
2230d9a4ef3SDoug Ambrisko 		 (sc->mfi_flags & MFI_FLAGS_SKINNY) ||
2240d9a4ef3SDoug Ambrisko 		(sc->mfi_flags & MFI_FLAGS_TBOLT)) {
2250d9a4ef3SDoug Ambrisko 		/* Gen2/Skinny: Memory mapped BAR is at offset 0x14 */
226fa1e6ef4SDoug Ambrisko 		sc->mfi_regs_rid = PCIR_BAR(1);
227fa1e6ef4SDoug Ambrisko 	}
2282e21a3efSScott Long 	if ((sc->mfi_regs_resource = bus_alloc_resource_any(sc->mfi_dev,
2292e21a3efSScott Long 	    SYS_RES_MEMORY, &sc->mfi_regs_rid, RF_ACTIVE)) == NULL) {
2302e21a3efSScott Long 		device_printf(dev, "Cannot allocate PCI registers\n");
2312e21a3efSScott Long 		return (ENXIO);
2322e21a3efSScott Long 	}
2332e21a3efSScott Long 	sc->mfi_btag = rman_get_bustag(sc->mfi_regs_resource);
2342e21a3efSScott Long 	sc->mfi_bhandle = rman_get_bushandle(sc->mfi_regs_resource);
2352e21a3efSScott Long 
2362e21a3efSScott Long 	error = ENOMEM;
2372e21a3efSScott Long 
2382e21a3efSScott Long 	/* Allocate parent DMA tag */
239b6f97155SScott Long 	if (bus_dma_tag_create(	bus_get_dma_tag(dev),	/* PCI parent */
2402e21a3efSScott Long 				1, 0,			/* algnmnt, boundary */
2412e21a3efSScott Long 				BUS_SPACE_MAXADDR,	/* lowaddr */
2422e21a3efSScott Long 				BUS_SPACE_MAXADDR,	/* highaddr */
2432e21a3efSScott Long 				NULL, NULL,		/* filter, filterarg */
2442e21a3efSScott Long 				BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
2452e21a3efSScott Long 				BUS_SPACE_UNRESTRICTED,	/* nsegments */
2462e21a3efSScott Long 				BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
2472e21a3efSScott Long 				0,			/* flags */
2482e21a3efSScott Long 				NULL, NULL,		/* lockfunc, lockarg */
2492e21a3efSScott Long 				&sc->mfi_parent_dmat)) {
2502e21a3efSScott Long 		device_printf(dev, "Cannot allocate parent DMA tag\n");
2512e21a3efSScott Long 		goto out;
2522e21a3efSScott Long 	}
2532e21a3efSScott Long 
254d1c5fc76SJohn Baldwin 	/* Allocate IRQ resource. */
255d1c5fc76SJohn Baldwin 	sc->mfi_irq_rid = 0;
256d1c5fc76SJohn Baldwin 	count = 1;
257d1c5fc76SJohn Baldwin 	if (mfi_msi && pci_alloc_msi(sc->mfi_dev, &count) == 0) {
258d1c5fc76SJohn Baldwin 		device_printf(sc->mfi_dev, "Using MSI\n");
259d1c5fc76SJohn Baldwin 		sc->mfi_irq_rid = 1;
260d1c5fc76SJohn Baldwin 	}
261d1c5fc76SJohn Baldwin 	if ((sc->mfi_irq = bus_alloc_resource_any(sc->mfi_dev, SYS_RES_IRQ,
262d1c5fc76SJohn Baldwin 	    &sc->mfi_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
263d1c5fc76SJohn Baldwin 		device_printf(sc->mfi_dev, "Cannot allocate interrupt\n");
264d1c5fc76SJohn Baldwin 		error = EINVAL;
265d1c5fc76SJohn Baldwin 		goto out;
266d1c5fc76SJohn Baldwin 	}
267d1c5fc76SJohn Baldwin 
2682e21a3efSScott Long 	error = mfi_attach(sc);
2692e21a3efSScott Long out:
2702e21a3efSScott Long 	if (error) {
2712e21a3efSScott Long 		mfi_free(sc);
2722e21a3efSScott Long 		mfi_pci_free(sc);
2732e21a3efSScott Long 	}
2742e21a3efSScott Long 
2752e21a3efSScott Long 	return (error);
2762e21a3efSScott Long }
2772e21a3efSScott Long 
2782e21a3efSScott Long static int
2792e21a3efSScott Long mfi_pci_detach(device_t dev)
2802e21a3efSScott Long {
2812e21a3efSScott Long 	struct mfi_softc *sc;
282*d174ffcaSJohn Baldwin 	int error;
2832e21a3efSScott Long 
2842e21a3efSScott Long 	sc = device_get_softc(dev);
2852e21a3efSScott Long 
2868ec5c98bSJohn Baldwin 	sx_xlock(&sc->mfi_config_lock);
287ddfae47bSScott Long 	mtx_lock(&sc->mfi_io_lock);
288ddfae47bSScott Long 	if ((sc->mfi_flags & MFI_FLAGS_OPEN) != 0) {
289ddfae47bSScott Long 		mtx_unlock(&sc->mfi_io_lock);
290cde586a7SJohn Baldwin 		sx_xunlock(&sc->mfi_config_lock);
2912e21a3efSScott Long 		return (EBUSY);
292ddfae47bSScott Long 	}
2938ec5c98bSJohn Baldwin 	sc->mfi_detaching = 1;
2948ec5c98bSJohn Baldwin 	mtx_unlock(&sc->mfi_io_lock);
2952e21a3efSScott Long 
296*d174ffcaSJohn Baldwin 	error = bus_generic_detach(sc->mfi_dev);
297*d174ffcaSJohn Baldwin 	if (error != 0) {
2988ec5c98bSJohn Baldwin 		sx_xunlock(&sc->mfi_config_lock);
2990d9a4ef3SDoug Ambrisko 		return error;
300ddfae47bSScott Long 	}
3018ec5c98bSJohn Baldwin 	sx_xunlock(&sc->mfi_config_lock);
3022e21a3efSScott Long 
3032e21a3efSScott Long 	EVENTHANDLER_DEREGISTER(shutdown_final, sc->mfi_eh);
3042e21a3efSScott Long 
3052e21a3efSScott Long 	mfi_shutdown(sc);
3062e21a3efSScott Long 	mfi_free(sc);
3072e21a3efSScott Long 	mfi_pci_free(sc);
3082e21a3efSScott Long 	return (0);
3092e21a3efSScott Long }
3102e21a3efSScott Long 
3112e21a3efSScott Long static void
3122e21a3efSScott Long mfi_pci_free(struct mfi_softc *sc)
3132e21a3efSScott Long {
3142e21a3efSScott Long 
3152e21a3efSScott Long 	if (sc->mfi_regs_resource != NULL) {
3162e21a3efSScott Long 		bus_release_resource(sc->mfi_dev, SYS_RES_MEMORY,
3172e21a3efSScott Long 		    sc->mfi_regs_rid, sc->mfi_regs_resource);
3182e21a3efSScott Long 	}
319d1c5fc76SJohn Baldwin 	if (sc->mfi_irq_rid != 0)
320d1c5fc76SJohn Baldwin 		pci_release_msi(sc->mfi_dev);
3212e21a3efSScott Long 
3222e21a3efSScott Long 	return;
3232e21a3efSScott Long }
3242e21a3efSScott Long 
3252e21a3efSScott Long static int
3262e21a3efSScott Long mfi_pci_suspend(device_t dev)
3272e21a3efSScott Long {
3282e21a3efSScott Long 
3292e21a3efSScott Long 	return (EINVAL);
3302e21a3efSScott Long }
3312e21a3efSScott Long 
3322e21a3efSScott Long static int
3332e21a3efSScott Long mfi_pci_resume(device_t dev)
3342e21a3efSScott Long {
3352e21a3efSScott Long 
3362e21a3efSScott Long 	return (EINVAL);
3372e21a3efSScott Long }
338