xref: /freebsd/sys/dev/isp/isp_pci.c (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
1aad970f1SDavid E. O'Brien /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
41b760be4SAlexander Motin  * Copyright (c) 2009-2020 Alexander Motin <mav@FreeBSD.org>
52df76c16SMatt Jacob  * Copyright (c) 1997-2008 by Matthew Jacob
6e5265237SMatt Jacob  * All rights reserved.
765adb54cSMatt Jacob  *
865adb54cSMatt Jacob  * Redistribution and use in source and binary forms, with or without
965adb54cSMatt Jacob  * modification, are permitted provided that the following conditions
1065adb54cSMatt Jacob  * are met:
1165adb54cSMatt Jacob  * 1. Redistributions of source code must retain the above copyright
1265adb54cSMatt Jacob  *    notice immediately at the beginning of the file, without modification,
1365adb54cSMatt Jacob  *    this list of conditions, and the following disclaimer.
14aa57fd6fSMatt Jacob  * 2. The name of the author may not be used to endorse or promote products
15aa57fd6fSMatt Jacob  *    derived from this software without specific prior written permission.
1665adb54cSMatt Jacob  *
1765adb54cSMatt Jacob  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1865adb54cSMatt Jacob  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1965adb54cSMatt Jacob  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2065adb54cSMatt Jacob  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2165adb54cSMatt Jacob  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2265adb54cSMatt Jacob  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2365adb54cSMatt Jacob  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2465adb54cSMatt Jacob  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2565adb54cSMatt Jacob  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2665adb54cSMatt Jacob  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2765adb54cSMatt Jacob  * SUCH DAMAGE.
2865adb54cSMatt Jacob  */
29799881e0SMatt Jacob /*
30799881e0SMatt Jacob  * PCI specific probe and attach routines for Qlogic ISP SCSI adapters.
31799881e0SMatt Jacob  * FreeBSD Version.
32799881e0SMatt Jacob  */
33aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
34aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
35aad970f1SDavid E. O'Brien 
36960f6939SMatt Jacob #include <sys/param.h>
37960f6939SMatt Jacob #include <sys/systm.h>
38960f6939SMatt Jacob #include <sys/kernel.h>
39960f6939SMatt Jacob #include <sys/module.h>
409a5af410SMatt Jacob #include <sys/linker.h>
419a5af410SMatt Jacob #include <sys/firmware.h>
42960f6939SMatt Jacob #include <sys/bus.h>
4374a96f43SJohn Baldwin #include <sys/stdint.h>
4477e6a3b2SWarner Losh #include <dev/pci/pcireg.h>
4577e6a3b2SWarner Losh #include <dev/pci/pcivar.h>
46d720e6d5SJustin T. Gibbs #include <machine/bus.h>
47960f6939SMatt Jacob #include <machine/resource.h>
48960f6939SMatt Jacob #include <sys/rman.h>
49960f6939SMatt Jacob #include <sys/malloc.h>
502df76c16SMatt Jacob #include <sys/uio.h>
51960f6939SMatt Jacob #include <dev/isp/isp_freebsd.h>
52d59bd469SMatt Jacob 
5310365e5aSMatt Jacob static uint32_t isp_pci_rd_reg_2400(ispsoftc_t *, int);
5410365e5aSMatt Jacob static void isp_pci_wr_reg_2400(ispsoftc_t *, int, uint32_t);
55cd201b7bSAlexander Motin static uint32_t isp_pci_rd_reg_2600(ispsoftc_t *, int);
56cd201b7bSAlexander Motin static void isp_pci_wr_reg_2600(ispsoftc_t *, int, uint32_t);
570e6bc811SAlexander Motin static void isp_pci_run_isr_2400(ispsoftc_t *);
589cd7268eSMatt Jacob static int isp_pci_mbxdma(ispsoftc_t *);
59a1fa0267SAlexander Motin static void isp_pci_mbxdmafree(ispsoftc_t *);
60a1fa0267SAlexander Motin static int isp_pci_irqsetup(ispsoftc_t *);
61d951bbcaSMatt Jacob 
6210365e5aSMatt Jacob static struct ispmdvec mdvec_2400 = {
630e6bc811SAlexander Motin 	isp_pci_run_isr_2400,
6410365e5aSMatt Jacob 	isp_pci_rd_reg_2400,
6510365e5aSMatt Jacob 	isp_pci_wr_reg_2400,
6610365e5aSMatt Jacob 	isp_pci_mbxdma,
67f6854a0cSAlexander Motin 	isp_send_cmd,
68a1fa0267SAlexander Motin 	isp_pci_irqsetup,
6910365e5aSMatt Jacob 	NULL
7010365e5aSMatt Jacob };
7110365e5aSMatt Jacob 
722df76c16SMatt Jacob static struct ispmdvec mdvec_2500 = {
730e6bc811SAlexander Motin 	isp_pci_run_isr_2400,
742df76c16SMatt Jacob 	isp_pci_rd_reg_2400,
752df76c16SMatt Jacob 	isp_pci_wr_reg_2400,
762df76c16SMatt Jacob 	isp_pci_mbxdma,
77f6854a0cSAlexander Motin 	isp_send_cmd,
78a1fa0267SAlexander Motin 	isp_pci_irqsetup,
792df76c16SMatt Jacob 	NULL
802df76c16SMatt Jacob };
812df76c16SMatt Jacob 
82218be0b2SAlexander Motin static struct ispmdvec mdvec_2600 = {
830e6bc811SAlexander Motin 	isp_pci_run_isr_2400,
84cd201b7bSAlexander Motin 	isp_pci_rd_reg_2600,
85cd201b7bSAlexander Motin 	isp_pci_wr_reg_2600,
86218be0b2SAlexander Motin 	isp_pci_mbxdma,
87f6854a0cSAlexander Motin 	isp_send_cmd,
88a1fa0267SAlexander Motin 	isp_pci_irqsetup,
89218be0b2SAlexander Motin 	NULL
90218be0b2SAlexander Motin };
91218be0b2SAlexander Motin 
9214e084adSAlexander Motin static struct ispmdvec mdvec_2700 = {
9314e084adSAlexander Motin 	isp_pci_run_isr_2400,
9414e084adSAlexander Motin 	isp_pci_rd_reg_2600,
9514e084adSAlexander Motin 	isp_pci_wr_reg_2600,
9614e084adSAlexander Motin 	isp_pci_mbxdma,
97f6854a0cSAlexander Motin 	isp_send_cmd,
9814e084adSAlexander Motin 	isp_pci_irqsetup,
9914e084adSAlexander Motin 	NULL
10014e084adSAlexander Motin };
10114e084adSAlexander Motin 
10265adb54cSMatt Jacob #ifndef	PCIM_CMD_INVEN
10365adb54cSMatt Jacob #define	PCIM_CMD_INVEN			0x10
10465adb54cSMatt Jacob #endif
10565adb54cSMatt Jacob #ifndef	PCIM_CMD_BUSMASTEREN
10665adb54cSMatt Jacob #define	PCIM_CMD_BUSMASTEREN		0x0004
10765adb54cSMatt Jacob #endif
108d951bbcaSMatt Jacob #ifndef	PCIM_CMD_PERRESPEN
109d951bbcaSMatt Jacob #define	PCIM_CMD_PERRESPEN		0x0040
110d951bbcaSMatt Jacob #endif
111d951bbcaSMatt Jacob #ifndef	PCIM_CMD_SEREN
112d951bbcaSMatt Jacob #define	PCIM_CMD_SEREN			0x0100
113d951bbcaSMatt Jacob #endif
1148a97c03aSMatt Jacob #ifndef	PCIM_CMD_INTX_DISABLE
1158a97c03aSMatt Jacob #define	PCIM_CMD_INTX_DISABLE		0x0400
1168a97c03aSMatt Jacob #endif
117d951bbcaSMatt Jacob 
118d951bbcaSMatt Jacob #ifndef	PCIR_COMMAND
119d951bbcaSMatt Jacob #define	PCIR_COMMAND			0x04
120d951bbcaSMatt Jacob #endif
121d951bbcaSMatt Jacob 
122d951bbcaSMatt Jacob #ifndef	PCIR_CACHELNSZ
123d951bbcaSMatt Jacob #define	PCIR_CACHELNSZ			0x0c
124d951bbcaSMatt Jacob #endif
125d951bbcaSMatt Jacob 
126d951bbcaSMatt Jacob #ifndef	PCIR_LATTIMER
127d951bbcaSMatt Jacob #define	PCIR_LATTIMER			0x0d
128d951bbcaSMatt Jacob #endif
129d951bbcaSMatt Jacob 
130ab6d0040SMatt Jacob #ifndef	PCIR_ROMADDR
131ab6d0040SMatt Jacob #define	PCIR_ROMADDR			0x30
132ab6d0040SMatt Jacob #endif
133ab6d0040SMatt Jacob 
13465adb54cSMatt Jacob #define	PCI_VENDOR_QLOGIC		0x1077
13565adb54cSMatt Jacob 
1368872e3d7SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2422	0x2422
13741675df0SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2432	0x2432
1382df76c16SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2532	0x2532
139a959d921SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP5432	0x5432
140218be0b2SAlexander Motin #define	PCI_PRODUCT_QLOGIC_ISP2031	0x2031
14167eeadd2SAlexander Motin #define	PCI_PRODUCT_QLOGIC_ISP8031	0x8031
14214e084adSAlexander Motin #define	PCI_PRODUCT_QLOGIC_ISP2684	0x2171
14314e084adSAlexander Motin #define	PCI_PRODUCT_QLOGIC_ISP2692	0x2b61
14414e084adSAlexander Motin #define	PCI_PRODUCT_QLOGIC_ISP2714	0x2071
14514e084adSAlexander Motin #define	PCI_PRODUCT_QLOGIC_ISP2722	0x2261
1469a5af410SMatt Jacob 
1476c426685SMatt Jacob #define	PCI_QLOGIC_ISP2422	\
1486c426685SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2422 << 16) | PCI_VENDOR_QLOGIC)
14941675df0SMatt Jacob #define	PCI_QLOGIC_ISP2432	\
15041675df0SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2432 << 16) | PCI_VENDOR_QLOGIC)
1512df76c16SMatt Jacob #define	PCI_QLOGIC_ISP2532	\
1522df76c16SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2532 << 16) | PCI_VENDOR_QLOGIC)
15314e084adSAlexander Motin #define	PCI_QLOGIC_ISP5432	\
15414e084adSAlexander Motin 	((PCI_PRODUCT_QLOGIC_ISP5432 << 16) | PCI_VENDOR_QLOGIC)
155218be0b2SAlexander Motin #define	PCI_QLOGIC_ISP2031	\
156218be0b2SAlexander Motin 	((PCI_PRODUCT_QLOGIC_ISP2031 << 16) | PCI_VENDOR_QLOGIC)
15767eeadd2SAlexander Motin #define	PCI_QLOGIC_ISP8031	\
15867eeadd2SAlexander Motin 	((PCI_PRODUCT_QLOGIC_ISP8031 << 16) | PCI_VENDOR_QLOGIC)
15914e084adSAlexander Motin #define	PCI_QLOGIC_ISP2684	\
16014e084adSAlexander Motin 	((PCI_PRODUCT_QLOGIC_ISP2684 << 16) | PCI_VENDOR_QLOGIC)
16114e084adSAlexander Motin #define	PCI_QLOGIC_ISP2692	\
16214e084adSAlexander Motin 	((PCI_PRODUCT_QLOGIC_ISP2692 << 16) | PCI_VENDOR_QLOGIC)
16314e084adSAlexander Motin #define	PCI_QLOGIC_ISP2714	\
16414e084adSAlexander Motin 	((PCI_PRODUCT_QLOGIC_ISP2714 << 16) | PCI_VENDOR_QLOGIC)
16514e084adSAlexander Motin #define	PCI_QLOGIC_ISP2722	\
16614e084adSAlexander Motin 	((PCI_PRODUCT_QLOGIC_ISP2722 << 16) | PCI_VENDOR_QLOGIC)
16767eeadd2SAlexander Motin 
168d951bbcaSMatt Jacob #define	PCI_DFLT_LTNCY	0x40
169d951bbcaSMatt Jacob #define	PCI_DFLT_LNSZ	0x10
17065adb54cSMatt Jacob 
171960f6939SMatt Jacob static int isp_pci_probe (device_t);
172960f6939SMatt Jacob static int isp_pci_attach (device_t);
17310365e5aSMatt Jacob static int isp_pci_detach (device_t);
17465adb54cSMatt Jacob 
1751923f739SMatt Jacob 
17665adb54cSMatt Jacob struct isp_pcisoftc {
1779cd7268eSMatt Jacob 	ispsoftc_t			pci_isp;
178e95725cbSMatt Jacob 	struct resource *		regs;
179d876d6c3SAlexander Motin 	struct resource *		regs1;
180cd201b7bSAlexander Motin 	struct resource *		regs2;
18108826086SAlexander Motin 	struct {
182e95725cbSMatt Jacob 		int				iqd;
18308826086SAlexander Motin 		struct resource *		irq;
18408826086SAlexander Motin 		void *				ih;
18508826086SAlexander Motin 	} irq[ISP_MAX_IRQS];
186e95725cbSMatt Jacob 	int				rtp;
187e95725cbSMatt Jacob 	int				rgd;
188d876d6c3SAlexander Motin 	int				rtp1;
189d876d6c3SAlexander Motin 	int				rgd1;
190cd201b7bSAlexander Motin 	int				rtp2;
191cd201b7bSAlexander Motin 	int				rgd2;
1921923f739SMatt Jacob 	bus_dma_tag_t			dmat;
1930a70657fSMatt Jacob 	int				msicount;
19465adb54cSMatt Jacob };
19565adb54cSMatt Jacob 
19610365e5aSMatt Jacob 
197960f6939SMatt Jacob static device_method_t isp_pci_methods[] = {
198960f6939SMatt Jacob 	/* Device interface */
199960f6939SMatt Jacob 	DEVMETHOD(device_probe,		isp_pci_probe),
200960f6939SMatt Jacob 	DEVMETHOD(device_attach,	isp_pci_attach),
20110365e5aSMatt Jacob 	DEVMETHOD(device_detach,	isp_pci_detach),
202960f6939SMatt Jacob 	{ 0, 0 }
20365adb54cSMatt Jacob };
20465adb54cSMatt Jacob 
205960f6939SMatt Jacob static driver_t isp_pci_driver = {
206960f6939SMatt Jacob 	"isp", isp_pci_methods, sizeof (struct isp_pcisoftc)
207960f6939SMatt Jacob };
208d1a9e9b9SJohn Baldwin 
209d1a9e9b9SJohn Baldwin DRIVER_MODULE(isp, pci, isp_pci_driver, 0, 0);
210d45ce511SEitan Adler MODULE_DEPEND(isp, cam, 1, 1, 1);
211d45ce511SEitan Adler MODULE_DEPEND(isp, firmware, 1, 1, 1);
2129e7d423dSMatt Jacob static int isp_nvports = 0;
21365adb54cSMatt Jacob 
214960f6939SMatt Jacob static int
215960f6939SMatt Jacob isp_pci_probe(device_t dev)
21665adb54cSMatt Jacob {
217960f6939SMatt Jacob 	switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) {
2188872e3d7SMatt Jacob 	case PCI_QLOGIC_ISP2422:
2198872e3d7SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2422 PCI FC-AL Adapter");
2208872e3d7SMatt Jacob 		break;
22141675df0SMatt Jacob 	case PCI_QLOGIC_ISP2432:
22241675df0SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2432 PCI FC-AL Adapter");
22341675df0SMatt Jacob 		break;
2242df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2532:
2252df76c16SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2532 PCI FC-AL Adapter");
2262df76c16SMatt Jacob 		break;
227a959d921SMatt Jacob 	case PCI_QLOGIC_ISP5432:
228a959d921SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 5432 PCI FC-AL Adapter");
229a959d921SMatt Jacob 		break;
230218be0b2SAlexander Motin 	case PCI_QLOGIC_ISP2031:
231218be0b2SAlexander Motin 		device_set_desc(dev, "Qlogic ISP 2031 PCI FC-AL Adapter");
232218be0b2SAlexander Motin 		break;
23367eeadd2SAlexander Motin 	case PCI_QLOGIC_ISP8031:
23467eeadd2SAlexander Motin 		device_set_desc(dev, "Qlogic ISP 8031 PCI FCoE Adapter");
23567eeadd2SAlexander Motin 		break;
23614e084adSAlexander Motin 	case PCI_QLOGIC_ISP2684:
23714e084adSAlexander Motin 		device_set_desc(dev, "Qlogic ISP 2684 PCI FC Adapter");
23814e084adSAlexander Motin 		break;
23914e084adSAlexander Motin 	case PCI_QLOGIC_ISP2692:
24014e084adSAlexander Motin 		device_set_desc(dev, "Qlogic ISP 2692 PCI FC Adapter");
24114e084adSAlexander Motin 		break;
24214e084adSAlexander Motin 	case PCI_QLOGIC_ISP2714:
24314e084adSAlexander Motin 		device_set_desc(dev, "Qlogic ISP 2714 PCI FC Adapter");
24414e084adSAlexander Motin 		break;
24514e084adSAlexander Motin 	case PCI_QLOGIC_ISP2722:
24614e084adSAlexander Motin 		device_set_desc(dev, "Qlogic ISP 2722 PCI FC Adapter");
24714e084adSAlexander Motin 		break;
24865adb54cSMatt Jacob 	default:
249960f6939SMatt Jacob 		return (ENXIO);
25065adb54cSMatt Jacob 	}
25173030e03SMatt Jacob 	if (isp_announced == 0 && bootverbose) {
252d02373f1SMatt Jacob 		printf("Qlogic ISP Driver, FreeBSD Version %d.%d, "
253a95ae193SMatt Jacob 		    "Core Version %d.%d\n",
254d720e6d5SJustin T. Gibbs 		    ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR,
255d720e6d5SJustin T. Gibbs 		    ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR);
25673030e03SMatt Jacob 		isp_announced++;
25765adb54cSMatt Jacob 	}
25856aef503SMatt Jacob 	/*
25956aef503SMatt Jacob 	 * XXXX: Here is where we might load the f/w module
26056aef503SMatt Jacob 	 * XXXX: (or increase a reference count to it).
26156aef503SMatt Jacob 	 */
262b77e575eSWarner Losh 	return (BUS_PROBE_DEFAULT);
26365adb54cSMatt Jacob }
26465adb54cSMatt Jacob 
2659cd7268eSMatt Jacob static void
2669e7d423dSMatt Jacob isp_get_generic_options(device_t dev, ispsoftc_t *isp)
2679cd7268eSMatt Jacob {
2689cd7268eSMatt Jacob 	int tval;
269f7c631bcSMatt Jacob 
2709cd7268eSMatt Jacob 	tval = 0;
2712df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "fwload_disable", &tval) == 0 && tval != 0) {
2729cd7268eSMatt Jacob 		isp->isp_confopts |= ISP_CFG_NORELOAD;
2739cd7268eSMatt Jacob 	}
2749cd7268eSMatt Jacob 	tval = 0;
2752df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "ignore_nvram", &tval) == 0 && tval != 0) {
2769cd7268eSMatt Jacob 		isp->isp_confopts |= ISP_CFG_NONVRAM;
2779cd7268eSMatt Jacob 	}
278336b5612SMatt Jacob 	tval = 0;
2792df76c16SMatt Jacob 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev), "debug", &tval);
280336b5612SMatt Jacob 	if (tval) {
281336b5612SMatt Jacob 		isp->isp_dblev = tval;
282336b5612SMatt Jacob 	} else {
283336b5612SMatt Jacob 		isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR;
284336b5612SMatt Jacob 	}
285336b5612SMatt Jacob 	if (bootverbose) {
286336b5612SMatt Jacob 		isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO;
287336b5612SMatt Jacob 	}
2889e7d423dSMatt Jacob 	tval = -1;
2892df76c16SMatt Jacob 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev), "vports", &tval);
290ffe6ea05SAlexander Motin 	if (tval > 0 && tval <= 254) {
2919e7d423dSMatt Jacob 		isp_nvports = tval;
2922df76c16SMatt Jacob 	}
2932df76c16SMatt Jacob 	tval = 7;
2942df76c16SMatt Jacob 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev), "quickboot_time", &tval);
2952df76c16SMatt Jacob 	isp_quickboot_time = tval;
296336b5612SMatt Jacob }
297336b5612SMatt Jacob 
298336b5612SMatt Jacob static void
2992df76c16SMatt Jacob isp_get_specific_options(device_t dev, int chan, ispsoftc_t *isp)
300336b5612SMatt Jacob {
301336b5612SMatt Jacob 	const char *sptr;
3029e7d423dSMatt Jacob 	int tval = 0;
30307f56f1cSAlexander Motin 	char prefix[12], name[16];
304336b5612SMatt Jacob 
30507f56f1cSAlexander Motin 	if (chan == 0)
30607f56f1cSAlexander Motin 		prefix[0] = 0;
30707f56f1cSAlexander Motin 	else
30807f56f1cSAlexander Motin 		snprintf(prefix, sizeof(prefix), "chan%d.", chan);
30907f56f1cSAlexander Motin 	snprintf(name, sizeof(name), "%siid", prefix);
31007f56f1cSAlexander Motin 	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
31107f56f1cSAlexander Motin 	    name, &tval)) {
3122df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->default_id = 109 - chan;
3132df76c16SMatt Jacob 	} else {
3142df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->default_id = tval - chan;
315336b5612SMatt Jacob 		isp->isp_confopts |= ISP_CFG_OWNLOOPID;
316336b5612SMatt Jacob 	}
3172df76c16SMatt Jacob 
3182df76c16SMatt Jacob 	tval = -1;
31907f56f1cSAlexander Motin 	snprintf(name, sizeof(name), "%srole", prefix);
32007f56f1cSAlexander Motin 	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
32107f56f1cSAlexander Motin 	    name, &tval) == 0) {
3222df76c16SMatt Jacob 		switch (tval) {
3232df76c16SMatt Jacob 		case ISP_ROLE_NONE:
3242df76c16SMatt Jacob 		case ISP_ROLE_INITIATOR:
3252df76c16SMatt Jacob 		case ISP_ROLE_TARGET:
32607f56f1cSAlexander Motin 		case ISP_ROLE_BOTH:
32707f56f1cSAlexander Motin 			device_printf(dev, "Chan %d setting role to 0x%x\n", chan, tval);
3282df76c16SMatt Jacob 			break;
3292df76c16SMatt Jacob 		default:
3302df76c16SMatt Jacob 			tval = -1;
3312df76c16SMatt Jacob 			break;
332336b5612SMatt Jacob 		}
333336b5612SMatt Jacob 	}
3342df76c16SMatt Jacob 	if (tval == -1) {
3352df76c16SMatt Jacob 		tval = ISP_DEFAULT_ROLES;
3362df76c16SMatt Jacob 	}
3374ecb1d4aSMatt Jacob 	ISP_FC_PC(isp, chan)->def_role = tval;
338336b5612SMatt Jacob 
3399cd7268eSMatt Jacob 	tval = 0;
34007f56f1cSAlexander Motin 	snprintf(name, sizeof(name), "%sfullduplex", prefix);
34107f56f1cSAlexander Motin 	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
34207f56f1cSAlexander Motin 	    name, &tval) == 0 && tval != 0) {
3439cd7268eSMatt Jacob 		isp->isp_confopts |= ISP_CFG_FULL_DUPLEX;
3449cd7268eSMatt Jacob 	}
3454d24901aSPedro F. Giffuni 	sptr = NULL;
34607f56f1cSAlexander Motin 	snprintf(name, sizeof(name), "%stopology", prefix);
34707f56f1cSAlexander Motin 	if (resource_string_value(device_get_name(dev), device_get_unit(dev),
3484d24901aSPedro F. Giffuni 	    name, (const char **) &sptr) == 0 && sptr != NULL) {
3499cd7268eSMatt Jacob 		if (strcmp(sptr, "lport") == 0) {
3509cd7268eSMatt Jacob 			isp->isp_confopts |= ISP_CFG_LPORT;
3519cd7268eSMatt Jacob 		} else if (strcmp(sptr, "nport") == 0) {
3529cd7268eSMatt Jacob 			isp->isp_confopts |= ISP_CFG_NPORT;
3539cd7268eSMatt Jacob 		} else if (strcmp(sptr, "lport-only") == 0) {
3549cd7268eSMatt Jacob 			isp->isp_confopts |= ISP_CFG_LPORT_ONLY;
3559cd7268eSMatt Jacob 		} else if (strcmp(sptr, "nport-only") == 0) {
3569cd7268eSMatt Jacob 			isp->isp_confopts |= ISP_CFG_NPORT_ONLY;
3579cd7268eSMatt Jacob 		}
358960f6939SMatt Jacob 	}
359960f6939SMatt Jacob 
36008167db8SKenneth D. Merry #ifdef ISP_FCTAPE_OFF
36108167db8SKenneth D. Merry 	isp->isp_confopts |= ISP_CFG_NOFCTAPE;
36208167db8SKenneth D. Merry #else
36308167db8SKenneth D. Merry 	isp->isp_confopts |= ISP_CFG_FCTAPE;
36408167db8SKenneth D. Merry #endif
36508167db8SKenneth D. Merry 
366387d8239SMatt Jacob 	tval = 0;
36707f56f1cSAlexander Motin 	snprintf(name, sizeof(name), "%snofctape", prefix);
36807f56f1cSAlexander Motin 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
36907f56f1cSAlexander Motin 	    name, &tval);
370387d8239SMatt Jacob 	if (tval) {
37108167db8SKenneth D. Merry 		isp->isp_confopts &= ~ISP_CFG_FCTAPE;
372387d8239SMatt Jacob 		isp->isp_confopts |= ISP_CFG_NOFCTAPE;
373387d8239SMatt Jacob 	}
374387d8239SMatt Jacob 
375387d8239SMatt Jacob 	tval = 0;
37607f56f1cSAlexander Motin 	snprintf(name, sizeof(name), "%sfctape", prefix);
37707f56f1cSAlexander Motin 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
37807f56f1cSAlexander Motin 	    name, &tval);
379387d8239SMatt Jacob 	if (tval) {
380387d8239SMatt Jacob 		isp->isp_confopts &= ~ISP_CFG_NOFCTAPE;
381387d8239SMatt Jacob 		isp->isp_confopts |= ISP_CFG_FCTAPE;
382387d8239SMatt Jacob 	}
383387d8239SMatt Jacob 
384387d8239SMatt Jacob 
3859ba86737SMatt Jacob 	/*
3869cd7268eSMatt Jacob 	 * Because the resource_*_value functions can neither return
3879cd7268eSMatt Jacob 	 * 64 bit integer values, nor can they be directly coerced
3889cd7268eSMatt Jacob 	 * to interpret the right hand side of the assignment as
3899cd7268eSMatt Jacob 	 * you want them to interpret it, we have to force WWN
3909cd7268eSMatt Jacob 	 * hint replacement to specify WWN strings with a leading
3919cd7268eSMatt Jacob 	 * 'w' (e..g w50000000aaaa0001). Sigh.
3929cd7268eSMatt Jacob 	 */
3934d24901aSPedro F. Giffuni 	sptr = NULL;
39407f56f1cSAlexander Motin 	snprintf(name, sizeof(name), "%sportwwn", prefix);
39507f56f1cSAlexander Motin 	tval = resource_string_value(device_get_name(dev), device_get_unit(dev),
39607f56f1cSAlexander Motin 	    name, (const char **) &sptr);
3974d24901aSPedro F. Giffuni 	if (tval == 0 && sptr != NULL && *sptr++ == 'w') {
3984d24901aSPedro F. Giffuni 		char *eptr = NULL;
3992df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->def_wwpn = strtouq(sptr, &eptr, 16);
4002df76c16SMatt Jacob 		if (eptr < sptr + 16 || ISP_FC_PC(isp, chan)->def_wwpn == -1) {
4019cd7268eSMatt Jacob 			device_printf(dev, "mangled portwwn hint '%s'\n", sptr);
4022df76c16SMatt Jacob 			ISP_FC_PC(isp, chan)->def_wwpn = 0;
4039cd7268eSMatt Jacob 		}
4049cd7268eSMatt Jacob 	}
4059cd7268eSMatt Jacob 
4064d24901aSPedro F. Giffuni 	sptr = NULL;
40707f56f1cSAlexander Motin 	snprintf(name, sizeof(name), "%snodewwn", prefix);
40807f56f1cSAlexander Motin 	tval = resource_string_value(device_get_name(dev), device_get_unit(dev),
40907f56f1cSAlexander Motin 	    name, (const char **) &sptr);
4104d24901aSPedro F. Giffuni 	if (tval == 0 && sptr != NULL && *sptr++ == 'w') {
4114d24901aSPedro F. Giffuni 		char *eptr = NULL;
4122df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->def_wwnn = strtouq(sptr, &eptr, 16);
4132df76c16SMatt Jacob 		if (eptr < sptr + 16 || ISP_FC_PC(isp, chan)->def_wwnn == 0) {
4149cd7268eSMatt Jacob 			device_printf(dev, "mangled nodewwn hint '%s'\n", sptr);
4152df76c16SMatt Jacob 			ISP_FC_PC(isp, chan)->def_wwnn = 0;
4169cd7268eSMatt Jacob 		}
4179cd7268eSMatt Jacob 	}
4189cd7268eSMatt Jacob 
419f7c631bcSMatt Jacob 	tval = -1;
42007f56f1cSAlexander Motin 	snprintf(name, sizeof(name), "%sloop_down_limit", prefix);
42107f56f1cSAlexander Motin 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
42207f56f1cSAlexander Motin 	    name, &tval);
42310365e5aSMatt Jacob 	if (tval >= 0 && tval < 0xffff) {
4242df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->loop_down_limit = tval;
42510365e5aSMatt Jacob 	} else {
4262df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->loop_down_limit = isp_loop_down_limit;
42710365e5aSMatt Jacob 	}
42810365e5aSMatt Jacob 
429f7c631bcSMatt Jacob 	tval = -1;
43007f56f1cSAlexander Motin 	snprintf(name, sizeof(name), "%sgone_device_time", prefix);
43107f56f1cSAlexander Motin 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
43207f56f1cSAlexander Motin 	    name, &tval);
433f7c631bcSMatt Jacob 	if (tval >= 0 && tval < 0xffff) {
4342df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->gone_device_time = tval;
435f7c631bcSMatt Jacob 	} else {
4362df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->gone_device_time = isp_gone_device_time;
437f7c631bcSMatt Jacob 	}
4389cd7268eSMatt Jacob }
4399cd7268eSMatt Jacob 
4409cd7268eSMatt Jacob static int
4419cd7268eSMatt Jacob isp_pci_attach(device_t dev)
4429cd7268eSMatt Jacob {
443a1fa0267SAlexander Motin 	struct isp_pcisoftc *pcs = device_get_softc(dev);
444a1fa0267SAlexander Motin 	ispsoftc_t *isp = &pcs->pci_isp;
445a1fa0267SAlexander Motin 	int i;
4462df76c16SMatt Jacob 	uint32_t data, cmd, linesz, did;
4472df76c16SMatt Jacob 	size_t psize, xsize;
4482df76c16SMatt Jacob 	char fwname[32];
4499cd7268eSMatt Jacob 
4502df76c16SMatt Jacob 	isp->isp_dev = dev;
4512df76c16SMatt Jacob 	isp->isp_nchan = 1;
45213d9c921SAlexander Motin 	mtx_init(&isp->isp_lock, "isp", NULL, MTX_DEF);
4539cd7268eSMatt Jacob 
4549cd7268eSMatt Jacob 	/*
455336b5612SMatt Jacob 	 * Get Generic Options
4569cd7268eSMatt Jacob 	 */
4579e7d423dSMatt Jacob 	isp_nvports = 0;
4589e7d423dSMatt Jacob 	isp_get_generic_options(dev, isp);
4599cd7268eSMatt Jacob 
460ab6d0040SMatt Jacob 	linesz = PCI_DFLT_LNSZ;
46108826086SAlexander Motin 	pcs->regs = pcs->regs2 = NULL;
46208826086SAlexander Motin 	pcs->rgd = pcs->rtp = 0;
463960f6939SMatt Jacob 
4641b760be4SAlexander Motin 	isp->isp_nchan += isp_nvports;
4652df76c16SMatt Jacob 	switch (pci_get_devid(dev)) {
4662df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2422:
4672df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2432:
4682df76c16SMatt Jacob 		did = 0x2400;
4692df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_2400;
4702df76c16SMatt Jacob 		isp->isp_type = ISP_HA_FC_2400;
4712df76c16SMatt Jacob 		break;
4722df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2532:
4732df76c16SMatt Jacob 		did = 0x2500;
4742df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_2500;
4752df76c16SMatt Jacob 		isp->isp_type = ISP_HA_FC_2500;
4762df76c16SMatt Jacob 		break;
477a959d921SMatt Jacob 	case PCI_QLOGIC_ISP5432:
478a959d921SMatt Jacob 		did = 0x2500;
479a959d921SMatt Jacob 		isp->isp_mdvec = &mdvec_2500;
480a959d921SMatt Jacob 		isp->isp_type = ISP_HA_FC_2500;
481a959d921SMatt Jacob 		break;
482218be0b2SAlexander Motin 	case PCI_QLOGIC_ISP2031:
48367eeadd2SAlexander Motin 	case PCI_QLOGIC_ISP8031:
484218be0b2SAlexander Motin 		did = 0x2600;
485218be0b2SAlexander Motin 		isp->isp_mdvec = &mdvec_2600;
486218be0b2SAlexander Motin 		isp->isp_type = ISP_HA_FC_2600;
487218be0b2SAlexander Motin 		break;
48814e084adSAlexander Motin 	case PCI_QLOGIC_ISP2684:
48914e084adSAlexander Motin 	case PCI_QLOGIC_ISP2692:
49014e084adSAlexander Motin 	case PCI_QLOGIC_ISP2714:
49114e084adSAlexander Motin 	case PCI_QLOGIC_ISP2722:
49214e084adSAlexander Motin 		did = 0x2700;
49314e084adSAlexander Motin 		isp->isp_mdvec = &mdvec_2700;
49414e084adSAlexander Motin 		isp->isp_type = ISP_HA_FC_2700;
49514e084adSAlexander Motin 		break;
4962df76c16SMatt Jacob 	default:
4972df76c16SMatt Jacob 		device_printf(dev, "unknown device type\n");
4982df76c16SMatt Jacob 		goto bad;
4992df76c16SMatt Jacob 		break;
50065adb54cSMatt Jacob 	}
5012df76c16SMatt Jacob 	isp->isp_revision = pci_get_revid(dev);
5022df76c16SMatt Jacob 
503218be0b2SAlexander Motin 	if (IS_26XX(isp)) {
504218be0b2SAlexander Motin 		pcs->rtp = SYS_RES_MEMORY;
505218be0b2SAlexander Motin 		pcs->rgd = PCIR_BAR(0);
506218be0b2SAlexander Motin 		pcs->regs = bus_alloc_resource_any(dev, pcs->rtp, &pcs->rgd,
507218be0b2SAlexander Motin 		    RF_ACTIVE);
508d876d6c3SAlexander Motin 		pcs->rtp1 = SYS_RES_MEMORY;
509d876d6c3SAlexander Motin 		pcs->rgd1 = PCIR_BAR(2);
510d876d6c3SAlexander Motin 		pcs->regs1 = bus_alloc_resource_any(dev, pcs->rtp1, &pcs->rgd1,
511d876d6c3SAlexander Motin 		    RF_ACTIVE);
512cd201b7bSAlexander Motin 		pcs->rtp2 = SYS_RES_MEMORY;
513cd201b7bSAlexander Motin 		pcs->rgd2 = PCIR_BAR(4);
514cd201b7bSAlexander Motin 		pcs->regs2 = bus_alloc_resource_any(dev, pcs->rtp2, &pcs->rgd2,
515cd201b7bSAlexander Motin 		    RF_ACTIVE);
516218be0b2SAlexander Motin 	} else {
517218be0b2SAlexander Motin 		pcs->rtp = SYS_RES_MEMORY;
518218be0b2SAlexander Motin 		pcs->rgd = PCIR_BAR(1);
519218be0b2SAlexander Motin 		pcs->regs = bus_alloc_resource_any(dev, pcs->rtp, &pcs->rgd,
520218be0b2SAlexander Motin 		    RF_ACTIVE);
521218be0b2SAlexander Motin 		if (pcs->regs == NULL) {
522218be0b2SAlexander Motin 			pcs->rtp = SYS_RES_IOPORT;
523218be0b2SAlexander Motin 			pcs->rgd = PCIR_BAR(0);
524218be0b2SAlexander Motin 			pcs->regs = bus_alloc_resource_any(dev, pcs->rtp,
525218be0b2SAlexander Motin 			    &pcs->rgd, RF_ACTIVE);
526218be0b2SAlexander Motin 		}
527218be0b2SAlexander Motin 	}
528218be0b2SAlexander Motin 	if (pcs->regs == NULL) {
529218be0b2SAlexander Motin 		device_printf(dev, "Unable to map any ports\n");
530218be0b2SAlexander Motin 		goto bad;
531218be0b2SAlexander Motin 	}
532218be0b2SAlexander Motin 	if (bootverbose) {
533218be0b2SAlexander Motin 		device_printf(dev, "Using %s space register mapping\n",
534218be0b2SAlexander Motin 		    (pcs->rtp == SYS_RES_IOPORT)? "I/O" : "Memory");
535218be0b2SAlexander Motin 	}
536cd201b7bSAlexander Motin 	isp->isp_regs = pcs->regs;
537cd201b7bSAlexander Motin 	isp->isp_regs2 = pcs->regs2;
538218be0b2SAlexander Motin 
5391b760be4SAlexander Motin 	psize = sizeof(fcparam) * isp->isp_nchan;
5401b760be4SAlexander Motin 	xsize = sizeof(struct isp_fc) * isp->isp_nchan;
5417cc0979fSDavid Malone 	isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT | M_ZERO);
542c6608df3SMatt Jacob 	if (isp->isp_param == NULL) {
543960f6939SMatt Jacob 		device_printf(dev, "cannot allocate parameter data\n");
544960f6939SMatt Jacob 		goto bad;
545c6608df3SMatt Jacob 	}
546a6222dd7SAlexander Motin 	isp->isp_osinfo.fc = malloc(xsize, M_DEVBUF, M_NOWAIT | M_ZERO);
547a6222dd7SAlexander Motin 	if (isp->isp_osinfo.fc == NULL) {
5482df76c16SMatt Jacob 		device_printf(dev, "cannot allocate parameter data\n");
5492df76c16SMatt Jacob 		goto bad;
5502df76c16SMatt Jacob 	}
55165adb54cSMatt Jacob 
552336b5612SMatt Jacob 	/*
553336b5612SMatt Jacob 	 * Now that we know who we are (roughly) get/set specific options
554336b5612SMatt Jacob 	 */
5552df76c16SMatt Jacob 	for (i = 0; i < isp->isp_nchan; i++) {
5562df76c16SMatt Jacob 		isp_get_specific_options(dev, i, isp);
5579a5af410SMatt Jacob 	}
5589a5af410SMatt Jacob 
5599a5af410SMatt Jacob 	isp->isp_osinfo.fw = NULL;
5609a5af410SMatt Jacob 	if (isp->isp_osinfo.fw == NULL) {
5619a5af410SMatt Jacob 		snprintf(fwname, sizeof (fwname), "isp_%04x", did);
5629a5af410SMatt Jacob 		isp->isp_osinfo.fw = firmware_get(fwname);
5639a5af410SMatt Jacob 	}
5649a5af410SMatt Jacob 	if (isp->isp_osinfo.fw != NULL) {
565ad0ab753SMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, "loaded firmware %s", fwname);
5665f634111SMatt Jacob 		isp->isp_mdvec->dv_ispfw = isp->isp_osinfo.fw->data;
5679a5af410SMatt Jacob 	}
56856aef503SMatt Jacob 
56956aef503SMatt Jacob 	/*
570ad0ab753SMatt Jacob 	 * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER are set.
571d951bbcaSMatt Jacob 	 */
572c68534f1SScott Long 	cmd = pci_read_config(dev, PCIR_COMMAND, 2);
5739e7d423dSMatt Jacob 	cmd |= PCIM_CMD_SEREN | PCIM_CMD_PERRESPEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_INVEN;
5748a97c03aSMatt Jacob 	cmd &= ~PCIM_CMD_INTX_DISABLE;
575b49c4674SMatt Jacob 	pci_write_config(dev, PCIR_COMMAND, cmd, 2);
576ab6d0040SMatt Jacob 
577d951bbcaSMatt Jacob 	/*
578222bb542SMatt Jacob 	 * Make sure the Cache Line Size register is set sensibly.
579d951bbcaSMatt Jacob 	 */
580960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_CACHELNSZ, 1);
5816a7d12e1SMatt Jacob 	if (data == 0 || (linesz != PCI_DFLT_LNSZ && data != linesz)) {
582ad0ab753SMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0, "set PCI line size to %d from %d", linesz, data);
5836a7d12e1SMatt Jacob 		data = linesz;
584960f6939SMatt Jacob 		pci_write_config(dev, PCIR_CACHELNSZ, data, 1);
585d951bbcaSMatt Jacob 	}
586ab6d0040SMatt Jacob 
587d951bbcaSMatt Jacob 	/*
588d951bbcaSMatt Jacob 	 * Make sure the Latency Timer is sane.
589d951bbcaSMatt Jacob 	 */
590960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_LATTIMER, 1);
591d951bbcaSMatt Jacob 	if (data < PCI_DFLT_LTNCY) {
592d951bbcaSMatt Jacob 		data = PCI_DFLT_LTNCY;
593ad0ab753SMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0, "set PCI latency to %d", data);
594960f6939SMatt Jacob 		pci_write_config(dev, PCIR_LATTIMER, data, 1);
595d951bbcaSMatt Jacob 	}
596ab6d0040SMatt Jacob 
597ab6d0040SMatt Jacob 	/*
598ab6d0040SMatt Jacob 	 * Make sure we've disabled the ROM.
599ab6d0040SMatt Jacob 	 */
600960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_ROMADDR, 4);
601ab6d0040SMatt Jacob 	data &= ~1;
602960f6939SMatt Jacob 	pci_write_config(dev, PCIR_ROMADDR, data, 4);
6032df76c16SMatt Jacob 
60405fbcbb0SMatt Jacob 	/*
60575c1e828SMatt Jacob 	 * Last minute checks...
60675c1e828SMatt Jacob 	 */
60775c1e828SMatt Jacob 	isp->isp_port = pci_get_function(dev);
60875c1e828SMatt Jacob 
60975c1e828SMatt Jacob 	/*
61005fbcbb0SMatt Jacob 	 * Make sure we're in reset state.
61105fbcbb0SMatt Jacob 	 */
6123395b056SMatt Jacob 	ISP_LOCK(isp);
613dfd24649SAlexander Motin 	if (isp_reinit(isp, 1) != 0) {
6143395b056SMatt Jacob 		ISP_UNLOCK(isp);
615960f6939SMatt Jacob 		goto bad;
61665adb54cSMatt Jacob 	}
6172df76c16SMatt Jacob 	ISP_UNLOCK(isp);
6182df76c16SMatt Jacob 	if (isp_attach(isp)) {
6192df76c16SMatt Jacob 		ISP_LOCK(isp);
620a1fa0267SAlexander Motin 		isp_shutdown(isp);
6213395b056SMatt Jacob 		ISP_UNLOCK(isp);
622960f6939SMatt Jacob 		goto bad;
623d59bd469SMatt Jacob 	}
624960f6939SMatt Jacob 	return (0);
625960f6939SMatt Jacob 
626960f6939SMatt Jacob bad:
627e52fba21SEdward Tomasz Napierala 	if (isp->isp_osinfo.fw == NULL && !IS_26XX(isp)) {
628e52fba21SEdward Tomasz Napierala 		/*
629e52fba21SEdward Tomasz Napierala 		 * Failure to attach at boot time might have been caused
630bafe4ceeSGordon Bergling 		 * by a missing ispfw(4).  Except for 16Gb adapters,
631e52fba21SEdward Tomasz Napierala 		 * there's no loadable firmware for them.
632e52fba21SEdward Tomasz Napierala 		 */
633e52fba21SEdward Tomasz Napierala 		isp_prt(isp, ISP_LOGWARN, "See the ispfw(4) man page on "
634e52fba21SEdward Tomasz Napierala 		    "how to load known good firmware at boot time");
635e52fba21SEdward Tomasz Napierala 	}
63608826086SAlexander Motin 	for (i = 0; i < isp->isp_nirq; i++) {
63708826086SAlexander Motin 		(void) bus_teardown_intr(dev, pcs->irq[i].irq, pcs->irq[i].ih);
63808826086SAlexander Motin 		(void) bus_release_resource(dev, SYS_RES_IRQ, pcs->irq[i].iqd,
63908826086SAlexander Motin 		    pcs->irq[0].irq);
640960f6939SMatt Jacob 	}
641a035b0afSMatt Jacob 	if (pcs->msicount) {
6420a70657fSMatt Jacob 		pci_release_msi(dev);
6430a70657fSMatt Jacob 	}
644cd201b7bSAlexander Motin 	if (pcs->regs)
645e95725cbSMatt Jacob 		(void) bus_release_resource(dev, pcs->rtp, pcs->rgd, pcs->regs);
646d876d6c3SAlexander Motin 	if (pcs->regs1)
647d876d6c3SAlexander Motin 		(void) bus_release_resource(dev, pcs->rtp1, pcs->rgd1, pcs->regs1);
648cd201b7bSAlexander Motin 	if (pcs->regs2)
649cd201b7bSAlexander Motin 		(void) bus_release_resource(dev, pcs->rtp2, pcs->rgd2, pcs->regs2);
6509cd7268eSMatt Jacob 	if (pcs->pci_isp.isp_param) {
651960f6939SMatt Jacob 		free(pcs->pci_isp.isp_param, M_DEVBUF);
6522df76c16SMatt Jacob 		pcs->pci_isp.isp_param = NULL;
6532df76c16SMatt Jacob 	}
654a6222dd7SAlexander Motin 	if (pcs->pci_isp.isp_osinfo.fc) {
655a6222dd7SAlexander Motin 		free(pcs->pci_isp.isp_osinfo.fc, M_DEVBUF);
656a6222dd7SAlexander Motin 		pcs->pci_isp.isp_osinfo.fc = NULL;
6579cd7268eSMatt Jacob 	}
65813d9c921SAlexander Motin 	mtx_destroy(&isp->isp_lock);
659960f6939SMatt Jacob 	return (ENXIO);
66065adb54cSMatt Jacob }
66165adb54cSMatt Jacob 
66210365e5aSMatt Jacob static int
66310365e5aSMatt Jacob isp_pci_detach(device_t dev)
66410365e5aSMatt Jacob {
665a1fa0267SAlexander Motin 	struct isp_pcisoftc *pcs = device_get_softc(dev);
666a1fa0267SAlexander Motin 	ispsoftc_t *isp = &pcs->pci_isp;
66708826086SAlexander Motin 	int i, status;
66810365e5aSMatt Jacob 
669e95725cbSMatt Jacob 	status = isp_detach(isp);
670e95725cbSMatt Jacob 	if (status)
671e95725cbSMatt Jacob 		return (status);
672e95725cbSMatt Jacob 	ISP_LOCK(isp);
673a1fa0267SAlexander Motin 	isp_shutdown(isp);
674e95725cbSMatt Jacob 	ISP_UNLOCK(isp);
67508826086SAlexander Motin 	for (i = 0; i < isp->isp_nirq; i++) {
67608826086SAlexander Motin 		(void) bus_teardown_intr(dev, pcs->irq[i].irq, pcs->irq[i].ih);
67708826086SAlexander Motin 		(void) bus_release_resource(dev, SYS_RES_IRQ, pcs->irq[i].iqd,
67808826086SAlexander Motin 		    pcs->irq[i].irq);
67908826086SAlexander Motin 	}
680a1fa0267SAlexander Motin 	if (pcs->msicount)
681e95725cbSMatt Jacob 		pci_release_msi(dev);
682e95725cbSMatt Jacob 	(void) bus_release_resource(dev, pcs->rtp, pcs->rgd, pcs->regs);
683d876d6c3SAlexander Motin 	if (pcs->regs1)
684d876d6c3SAlexander Motin 		(void) bus_release_resource(dev, pcs->rtp1, pcs->rgd1, pcs->regs1);
685cd201b7bSAlexander Motin 	if (pcs->regs2)
686cd201b7bSAlexander Motin 		(void) bus_release_resource(dev, pcs->rtp2, pcs->rgd2, pcs->regs2);
687a1fa0267SAlexander Motin 	isp_pci_mbxdmafree(isp);
688e95725cbSMatt Jacob 	if (pcs->pci_isp.isp_param) {
689e95725cbSMatt Jacob 		free(pcs->pci_isp.isp_param, M_DEVBUF);
690e95725cbSMatt Jacob 		pcs->pci_isp.isp_param = NULL;
691e95725cbSMatt Jacob 	}
692a6222dd7SAlexander Motin 	if (pcs->pci_isp.isp_osinfo.fc) {
693a6222dd7SAlexander Motin 		free(pcs->pci_isp.isp_osinfo.fc, M_DEVBUF);
694a6222dd7SAlexander Motin 		pcs->pci_isp.isp_osinfo.fc = NULL;
695e95725cbSMatt Jacob 	}
69613d9c921SAlexander Motin 	mtx_destroy(&isp->isp_lock);
69710365e5aSMatt Jacob 	return (0);
69810365e5aSMatt Jacob }
69910365e5aSMatt Jacob 
700cd201b7bSAlexander Motin #define	BXR2(isp, off)		bus_read_2((isp)->isp_regs, (off))
701cd201b7bSAlexander Motin #define	BXW2(isp, off, v)	bus_write_2((isp)->isp_regs, (off), (v))
702cd201b7bSAlexander Motin #define	BXR4(isp, off)		bus_read_4((isp)->isp_regs, (off))
703cd201b7bSAlexander Motin #define	BXW4(isp, off, v)	bus_write_4((isp)->isp_regs, (off), (v))
704cd201b7bSAlexander Motin #define	B2R4(isp, off)		bus_read_4((isp)->isp_regs2, (off))
705cd201b7bSAlexander Motin #define	B2W4(isp, off, v)	bus_write_4((isp)->isp_regs2, (off), (v))
706126ec864SMatt Jacob 
7070e6bc811SAlexander Motin static void
7080e6bc811SAlexander Motin isp_pci_run_isr_2400(ispsoftc_t *isp)
70910365e5aSMatt Jacob {
71010365e5aSMatt Jacob 	uint32_t r2hisr;
7110e6bc811SAlexander Motin 	uint16_t isr, info;
71210365e5aSMatt Jacob 
7131b760be4SAlexander Motin 	r2hisr = BXR4(isp, BIU2400_R2HSTS);
71410365e5aSMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG3, "RISC2HOST ISR 0x%x", r2hisr);
7150e6bc811SAlexander Motin 	if ((r2hisr & BIU_R2HST_INTR) == 0)
7160e6bc811SAlexander Motin 		return;
7170e6bc811SAlexander Motin 	isr = r2hisr & BIU_R2HST_ISTAT_MASK;
7180e6bc811SAlexander Motin 	info = (r2hisr >> 16);
7190e6bc811SAlexander Motin 	switch (isr) {
7206ce548a1SAlexander Motin 	case ISPR2HST_ROM_MBX_OK:
7216ce548a1SAlexander Motin 	case ISPR2HST_ROM_MBX_FAIL:
7226ce548a1SAlexander Motin 	case ISPR2HST_MBX_OK:
7236ce548a1SAlexander Motin 	case ISPR2HST_MBX_FAIL:
7240e6bc811SAlexander Motin 		isp_intr_mbox(isp, info);
7250e6bc811SAlexander Motin 		break;
7266ce548a1SAlexander Motin 	case ISPR2HST_ASYNC_EVENT:
7270e6bc811SAlexander Motin 		isp_intr_async(isp, info);
7286ce548a1SAlexander Motin 		break;
7296ce548a1SAlexander Motin 	case ISPR2HST_RSPQ_UPDATE:
7300e6bc811SAlexander Motin 		isp_intr_respq(isp);
7310e6bc811SAlexander Motin 		break;
7326ce548a1SAlexander Motin 	case ISPR2HST_RSPQ_UPDATE2:
7330e6bc811SAlexander Motin #ifdef	ISP_TARGET_MODE
7346ce548a1SAlexander Motin 	case ISPR2HST_ATIO_RSPQ_UPDATE:
7350e6bc811SAlexander Motin #endif
7360e6bc811SAlexander Motin 		isp_intr_respq(isp);
7370e6bc811SAlexander Motin 		/* FALLTHROUGH */
7380e6bc811SAlexander Motin #ifdef	ISP_TARGET_MODE
7390e6bc811SAlexander Motin 	case ISPR2HST_ATIO_UPDATE:
7406ce548a1SAlexander Motin 	case ISPR2HST_ATIO_UPDATE2:
7410e6bc811SAlexander Motin 		isp_intr_atioq(isp);
7420e6bc811SAlexander Motin #endif
7436ce548a1SAlexander Motin 		break;
74410365e5aSMatt Jacob 	default:
74510365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGERR, "unknown interrupt 0x%x\n", r2hisr);
74610365e5aSMatt Jacob 	}
7470e6bc811SAlexander Motin 	ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_RISC_INT);
74810365e5aSMatt Jacob }
74910365e5aSMatt Jacob 
75010365e5aSMatt Jacob static uint32_t
75110365e5aSMatt Jacob isp_pci_rd_reg_2400(ispsoftc_t *isp, int regoff)
75210365e5aSMatt Jacob {
75310365e5aSMatt Jacob 	int block = regoff & _BLK_REG_MASK;
75410365e5aSMatt Jacob 
75510365e5aSMatt Jacob 	switch (block) {
75610365e5aSMatt Jacob 	case BIU_BLOCK:
7571b760be4SAlexander Motin 		return (BXR4(isp, regoff));
75810365e5aSMatt Jacob 	case MBOX_BLOCK:
7591b760be4SAlexander Motin 		return (BXR2(isp, regoff));
7601b760be4SAlexander Motin 	}
761cd201b7bSAlexander Motin 	isp_prt(isp, ISP_LOGERR, "unknown block read at 0x%x", regoff);
76210365e5aSMatt Jacob 	return (0xffffffff);
76310365e5aSMatt Jacob }
76410365e5aSMatt Jacob 
76510365e5aSMatt Jacob static void
76610365e5aSMatt Jacob isp_pci_wr_reg_2400(ispsoftc_t *isp, int regoff, uint32_t val)
76710365e5aSMatt Jacob {
76810365e5aSMatt Jacob 	int block = regoff & _BLK_REG_MASK;
76910365e5aSMatt Jacob 
77010365e5aSMatt Jacob 	switch (block) {
77110365e5aSMatt Jacob 	case BIU_BLOCK:
7721b760be4SAlexander Motin 		BXW4(isp, regoff, val);
77307d925faSAlexander Motin #ifdef MEMORYBARRIERW
77407d925faSAlexander Motin 		if (regoff == BIU2400_REQINP ||
77507d925faSAlexander Motin 		    regoff == BIU2400_RSPOUTP ||
77607d925faSAlexander Motin 		    regoff == BIU2400_PRI_REQINP ||
77707d925faSAlexander Motin 		    regoff == BIU2400_ATIO_RSPOUTP)
7781b760be4SAlexander Motin 			MEMORYBARRIERW(isp, SYNC_REG, regoff, 4, -1)
77907d925faSAlexander Motin 		else
78007d925faSAlexander Motin #endif
7811b760be4SAlexander Motin 		MEMORYBARRIER(isp, SYNC_REG, regoff, 4, -1);
7821b760be4SAlexander Motin 		return;
7831b760be4SAlexander Motin 	case MBOX_BLOCK:
7841b760be4SAlexander Motin 		BXW2(isp, regoff, val);
7851b760be4SAlexander Motin 		MEMORYBARRIER(isp, SYNC_REG, regoff, 2, -1);
7861b760be4SAlexander Motin 		return;
787d59bd469SMatt Jacob 	}
7881b760be4SAlexander Motin 	isp_prt(isp, ISP_LOGERR, "unknown block write at 0x%x", regoff);
789d59bd469SMatt Jacob }
790d59bd469SMatt Jacob 
791cd201b7bSAlexander Motin static uint32_t
792cd201b7bSAlexander Motin isp_pci_rd_reg_2600(ispsoftc_t *isp, int regoff)
793cd201b7bSAlexander Motin {
794cd201b7bSAlexander Motin 	uint32_t rv;
795cd201b7bSAlexander Motin 
796cd201b7bSAlexander Motin 	switch (regoff) {
797cd201b7bSAlexander Motin 	case BIU2400_PRI_REQINP:
798cd201b7bSAlexander Motin 	case BIU2400_PRI_REQOUTP:
799cd201b7bSAlexander Motin 		isp_prt(isp, ISP_LOGERR, "unknown register read at 0x%x",
800cd201b7bSAlexander Motin 		    regoff);
801cd201b7bSAlexander Motin 		rv = 0xffffffff;
802cd201b7bSAlexander Motin 		break;
803cd201b7bSAlexander Motin 	case BIU2400_REQINP:
804cd201b7bSAlexander Motin 		rv = B2R4(isp, 0x00);
805cd201b7bSAlexander Motin 		break;
806cd201b7bSAlexander Motin 	case BIU2400_REQOUTP:
807cd201b7bSAlexander Motin 		rv = B2R4(isp, 0x04);
808cd201b7bSAlexander Motin 		break;
809cd201b7bSAlexander Motin 	case BIU2400_RSPINP:
810cd201b7bSAlexander Motin 		rv = B2R4(isp, 0x08);
811cd201b7bSAlexander Motin 		break;
812cd201b7bSAlexander Motin 	case BIU2400_RSPOUTP:
813cd201b7bSAlexander Motin 		rv = B2R4(isp, 0x0c);
814cd201b7bSAlexander Motin 		break;
815cd201b7bSAlexander Motin 	case BIU2400_ATIO_RSPINP:
816cd201b7bSAlexander Motin 		rv = B2R4(isp, 0x10);
817cd201b7bSAlexander Motin 		break;
818cd201b7bSAlexander Motin 	case BIU2400_ATIO_RSPOUTP:
819cd201b7bSAlexander Motin 		rv = B2R4(isp, 0x14);
820cd201b7bSAlexander Motin 		break;
821cd201b7bSAlexander Motin 	default:
822cd201b7bSAlexander Motin 		rv = isp_pci_rd_reg_2400(isp, regoff);
823cd201b7bSAlexander Motin 		break;
824cd201b7bSAlexander Motin 	}
825cd201b7bSAlexander Motin 	return (rv);
826cd201b7bSAlexander Motin }
827cd201b7bSAlexander Motin 
828cd201b7bSAlexander Motin static void
829cd201b7bSAlexander Motin isp_pci_wr_reg_2600(ispsoftc_t *isp, int regoff, uint32_t val)
830cd201b7bSAlexander Motin {
831cd201b7bSAlexander Motin 	int off;
832cd201b7bSAlexander Motin 
833cd201b7bSAlexander Motin 	switch (regoff) {
834cd201b7bSAlexander Motin 	case BIU2400_PRI_REQINP:
835cd201b7bSAlexander Motin 	case BIU2400_PRI_REQOUTP:
836cd201b7bSAlexander Motin 		isp_prt(isp, ISP_LOGERR, "unknown register write at 0x%x",
837cd201b7bSAlexander Motin 		    regoff);
838cd201b7bSAlexander Motin 		return;
839cd201b7bSAlexander Motin 	case BIU2400_REQINP:
840cd201b7bSAlexander Motin 		off = 0x00;
841cd201b7bSAlexander Motin 		break;
842cd201b7bSAlexander Motin 	case BIU2400_REQOUTP:
843cd201b7bSAlexander Motin 		off = 0x04;
844cd201b7bSAlexander Motin 		break;
845cd201b7bSAlexander Motin 	case BIU2400_RSPINP:
846cd201b7bSAlexander Motin 		off = 0x08;
847cd201b7bSAlexander Motin 		break;
848cd201b7bSAlexander Motin 	case BIU2400_RSPOUTP:
849cd201b7bSAlexander Motin 		off = 0x0c;
850cd201b7bSAlexander Motin 		break;
851cd201b7bSAlexander Motin 	case BIU2400_ATIO_RSPINP:
852cd201b7bSAlexander Motin 		off = 0x10;
853cd201b7bSAlexander Motin 		break;
854cd201b7bSAlexander Motin 	case BIU2400_ATIO_RSPOUTP:
855cd201b7bSAlexander Motin 		off = 0x14;
856cd201b7bSAlexander Motin 		break;
857cd201b7bSAlexander Motin 	default:
858cd201b7bSAlexander Motin 		isp_pci_wr_reg_2400(isp, regoff, val);
859cd201b7bSAlexander Motin 		return;
860cd201b7bSAlexander Motin 	}
861cd201b7bSAlexander Motin 	B2W4(isp, off, val);
862cd201b7bSAlexander Motin }
863cd201b7bSAlexander Motin 
864d720e6d5SJustin T. Gibbs 
865222bb542SMatt Jacob struct imush {
86614849e2cSAlexander Motin 	bus_addr_t maddr;
867222bb542SMatt Jacob 	int error;
868222bb542SMatt Jacob };
869222bb542SMatt Jacob 
870d720e6d5SJustin T. Gibbs static void
8711923f739SMatt Jacob imc(void *arg, bus_dma_segment_t *segs, int nseg, int error)
872d720e6d5SJustin T. Gibbs {
873222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
8742df76c16SMatt Jacob 
87514849e2cSAlexander Motin 	if (!(imushp->error = error))
87614849e2cSAlexander Motin 		imushp->maddr = segs[0].ds_addr;
877d720e6d5SJustin T. Gibbs }
878d720e6d5SJustin T. Gibbs 
879d720e6d5SJustin T. Gibbs static int
8809cd7268eSMatt Jacob isp_pci_mbxdma(ispsoftc_t *isp)
881d720e6d5SJustin T. Gibbs {
882254c652bSAlexander Motin 	bus_dma_tag_t ptag;
883d720e6d5SJustin T. Gibbs 	caddr_t base;
8841b760be4SAlexander Motin 	uint32_t len;
885254c652bSAlexander Motin 	int i, error, cmap;
88653af7d22SMatt Jacob 	bus_size_t slim;	/* segment size */
887222bb542SMatt Jacob 	struct imush im;
888dae0ba75SAlexander Motin #ifdef	ISP_TARGET_MODE
8891b760be4SAlexander Motin 	isp_ecmd_t *ecmd;
890dae0ba75SAlexander Motin #endif
891222bb542SMatt Jacob 
892a1fa0267SAlexander Motin 	/* Already been here? If so, leave... */
893a1fa0267SAlexander Motin 	if (isp->isp_xflist != NULL)
894a95ae193SMatt Jacob 		return (0);
895a1fa0267SAlexander Motin 	if (isp->isp_rquest != NULL && isp->isp_maxcmds == 0)
896a1fa0267SAlexander Motin 		return (0);
8970a70657fSMatt Jacob 	ISP_UNLOCK(isp);
89810365e5aSMatt Jacob 
899254c652bSAlexander Motin 	ptag = bus_get_dma_tag(isp->isp_osinfo.dev);
900a1fa0267SAlexander Motin 	if (sizeof (bus_size_t) > 4)
90153af7d22SMatt Jacob 		slim = (bus_size_t) (1ULL << 32);
902a1fa0267SAlexander Motin 	else
9039b434edeSMatt Jacob 		slim = (bus_size_t) (1UL << 31);
904254c652bSAlexander Motin 
905254c652bSAlexander Motin 	if (isp->isp_rquest != NULL)
906254c652bSAlexander Motin 		goto gotmaxcmds;
9071923f739SMatt Jacob 
908d720e6d5SJustin T. Gibbs 	/*
909cf770ba3SAlexander Motin 	 * Allocate and map the request queue.
910d720e6d5SJustin T. Gibbs 	 */
911d02373f1SMatt Jacob 	len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
912254c652bSAlexander Motin 	if (bus_dma_tag_create(ptag, QENTRY_LEN, slim,
9131b760be4SAlexander Motin 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
9149cca0e7eSAlexander Motin 	    len, 1, len, 0, NULL, NULL, &isp->isp_osinfo.reqdmat)) {
91514849e2cSAlexander Motin 		isp_prt(isp, ISP_LOGERR, "cannot create request DMA tag");
916a1fa0267SAlexander Motin 		goto bad;
91714849e2cSAlexander Motin 	}
91814849e2cSAlexander Motin 	if (bus_dmamem_alloc(isp->isp_osinfo.reqdmat, (void **)&base,
91914849e2cSAlexander Motin 	    BUS_DMA_COHERENT, &isp->isp_osinfo.reqmap) != 0) {
92014849e2cSAlexander Motin 		isp_prt(isp, ISP_LOGERR, "cannot allocate request DMA memory");
92114849e2cSAlexander Motin 		bus_dma_tag_destroy(isp->isp_osinfo.reqdmat);
922a1fa0267SAlexander Motin 		goto bad;
92314849e2cSAlexander Motin 	}
92414849e2cSAlexander Motin 	isp->isp_rquest = base;
92514849e2cSAlexander Motin 	im.error = 0;
92614849e2cSAlexander Motin 	if (bus_dmamap_load(isp->isp_osinfo.reqdmat, isp->isp_osinfo.reqmap,
9279cca0e7eSAlexander Motin 	    base, len, imc, &im, BUS_DMA_NOWAIT) || im.error) {
92814849e2cSAlexander Motin 		isp_prt(isp, ISP_LOGERR, "error loading request DMA map %d", im.error);
929a1fa0267SAlexander Motin 		goto bad;
93014849e2cSAlexander Motin 	}
93114849e2cSAlexander Motin 	isp_prt(isp, ISP_LOGDEBUG0, "request area @ 0x%jx/0x%jx",
93214849e2cSAlexander Motin 	    (uintmax_t)im.maddr, (uintmax_t)len);
93314849e2cSAlexander Motin 	isp->isp_rquest_dma = im.maddr;
934cf770ba3SAlexander Motin 
935cf770ba3SAlexander Motin #ifdef	ISP_TARGET_MODE
936cf770ba3SAlexander Motin 	/*
937cf770ba3SAlexander Motin 	 * Allocate region for external DMA addressable command/status structures.
938cf770ba3SAlexander Motin 	 */
939cf770ba3SAlexander Motin 	len = N_XCMDS * XCMD_SIZE;
940254c652bSAlexander Motin 	if (bus_dma_tag_create(ptag, XCMD_SIZE, slim,
9411b760be4SAlexander Motin 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
942cf770ba3SAlexander Motin 	    len, 1, len, 0, NULL, NULL, &isp->isp_osinfo.ecmd_dmat)) {
943cf770ba3SAlexander Motin 		isp_prt(isp, ISP_LOGERR, "cannot create ECMD DMA tag");
944cf770ba3SAlexander Motin 		goto bad;
945cf770ba3SAlexander Motin 	}
946cf770ba3SAlexander Motin 	if (bus_dmamem_alloc(isp->isp_osinfo.ecmd_dmat, (void **)&base,
947cf770ba3SAlexander Motin 	    BUS_DMA_COHERENT, &isp->isp_osinfo.ecmd_map) != 0) {
948cf770ba3SAlexander Motin 		isp_prt(isp, ISP_LOGERR, "cannot allocate ECMD DMA memory");
949254c652bSAlexander Motin 		bus_dma_tag_destroy(isp->isp_osinfo.ecmd_dmat);
950cf770ba3SAlexander Motin 		goto bad;
951cf770ba3SAlexander Motin 	}
952cf770ba3SAlexander Motin 	isp->isp_osinfo.ecmd_base = (isp_ecmd_t *)base;
953cf770ba3SAlexander Motin 	im.error = 0;
954cf770ba3SAlexander Motin 	if (bus_dmamap_load(isp->isp_osinfo.ecmd_dmat, isp->isp_osinfo.ecmd_map,
955cf770ba3SAlexander Motin 	    base, len, imc, &im, BUS_DMA_NOWAIT) || im.error) {
956cf770ba3SAlexander Motin 		isp_prt(isp, ISP_LOGERR, "error loading ECMD DMA map %d", im.error);
957cf770ba3SAlexander Motin 		goto bad;
958cf770ba3SAlexander Motin 	}
959cf770ba3SAlexander Motin 	isp_prt(isp, ISP_LOGDEBUG0, "ecmd area @ 0x%jx/0x%jx",
960cf770ba3SAlexander Motin 	    (uintmax_t)im.maddr, (uintmax_t)len);
961cf770ba3SAlexander Motin 
96214849e2cSAlexander Motin 	isp->isp_osinfo.ecmd_dma = im.maddr;
96314849e2cSAlexander Motin 	isp->isp_osinfo.ecmd_free = (isp_ecmd_t *)base;
96414849e2cSAlexander Motin 	for (ecmd = isp->isp_osinfo.ecmd_free;
96514849e2cSAlexander Motin 	    ecmd < &isp->isp_osinfo.ecmd_free[N_XCMDS]; ecmd++) {
96614849e2cSAlexander Motin 		if (ecmd == &isp->isp_osinfo.ecmd_free[N_XCMDS - 1])
96714849e2cSAlexander Motin 			ecmd->next = NULL;
96814849e2cSAlexander Motin 		else
96914849e2cSAlexander Motin 			ecmd->next = ecmd + 1;
97014849e2cSAlexander Motin 	}
971cf770ba3SAlexander Motin #endif
9722df76c16SMatt Jacob 
97353af7d22SMatt Jacob 	/*
97414849e2cSAlexander Motin 	 * Allocate and map the result queue.
97553af7d22SMatt Jacob 	 */
97614849e2cSAlexander Motin 	len = ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
977254c652bSAlexander Motin 	if (bus_dma_tag_create(ptag, QENTRY_LEN, slim,
9781b760be4SAlexander Motin 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
9799cca0e7eSAlexander Motin 	    len, 1, len, 0, NULL, NULL, &isp->isp_osinfo.respdmat)) {
98014849e2cSAlexander Motin 		isp_prt(isp, ISP_LOGERR, "cannot create response DMA tag");
981a1fa0267SAlexander Motin 		goto bad;
982d720e6d5SJustin T. Gibbs 	}
98314849e2cSAlexander Motin 	if (bus_dmamem_alloc(isp->isp_osinfo.respdmat, (void **)&base,
98414849e2cSAlexander Motin 	    BUS_DMA_COHERENT, &isp->isp_osinfo.respmap) != 0) {
98514849e2cSAlexander Motin 		isp_prt(isp, ISP_LOGERR, "cannot allocate response DMA memory");
98614849e2cSAlexander Motin 		bus_dma_tag_destroy(isp->isp_osinfo.respdmat);
987a1fa0267SAlexander Motin 		goto bad;
988222bb542SMatt Jacob 	}
98914849e2cSAlexander Motin 	isp->isp_result = base;
9902df76c16SMatt Jacob 	im.error = 0;
99114849e2cSAlexander Motin 	if (bus_dmamap_load(isp->isp_osinfo.respdmat, isp->isp_osinfo.respmap,
9929cca0e7eSAlexander Motin 	    base, len, imc, &im, BUS_DMA_NOWAIT) || im.error) {
99314849e2cSAlexander Motin 		isp_prt(isp, ISP_LOGERR, "error loading response DMA map %d", im.error);
994a1fa0267SAlexander Motin 		goto bad;
99514849e2cSAlexander Motin 	}
99614849e2cSAlexander Motin 	isp_prt(isp, ISP_LOGDEBUG0, "response area @ 0x%jx/0x%jx",
99714849e2cSAlexander Motin 	    (uintmax_t)im.maddr, (uintmax_t)len);
99814849e2cSAlexander Motin 	isp->isp_result_dma = im.maddr;
9992df76c16SMatt Jacob 
100014849e2cSAlexander Motin #ifdef	ISP_TARGET_MODE
100114849e2cSAlexander Motin 	/*
1002b8e2395eSAlexander Motin 	 * Allocate and map ATIO queue.
100314849e2cSAlexander Motin 	 */
1004b8e2395eSAlexander Motin 	len = ISP_QUEUE_SIZE(ATIO_QUEUE_LEN(isp));
1005254c652bSAlexander Motin 	if (bus_dma_tag_create(ptag, QENTRY_LEN, slim,
10061b760be4SAlexander Motin 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
10079cca0e7eSAlexander Motin 	    len, 1, len, 0, NULL, NULL, &isp->isp_osinfo.atiodmat)) {
100814849e2cSAlexander Motin 		isp_prt(isp, ISP_LOGERR, "cannot create ATIO DMA tag");
1009a1fa0267SAlexander Motin 		goto bad;
101014849e2cSAlexander Motin 	}
101114849e2cSAlexander Motin 	if (bus_dmamem_alloc(isp->isp_osinfo.atiodmat, (void **)&base,
101214849e2cSAlexander Motin 	    BUS_DMA_COHERENT, &isp->isp_osinfo.atiomap) != 0) {
101314849e2cSAlexander Motin 		isp_prt(isp, ISP_LOGERR, "cannot allocate ATIO DMA memory");
101414849e2cSAlexander Motin 		bus_dma_tag_destroy(isp->isp_osinfo.atiodmat);
1015a1fa0267SAlexander Motin 		goto bad;
101614849e2cSAlexander Motin 	}
101714849e2cSAlexander Motin 	isp->isp_atioq = base;
101814849e2cSAlexander Motin 	im.error = 0;
101914849e2cSAlexander Motin 	if (bus_dmamap_load(isp->isp_osinfo.atiodmat, isp->isp_osinfo.atiomap,
10209cca0e7eSAlexander Motin 	    base, len, imc, &im, BUS_DMA_NOWAIT) || im.error) {
102114849e2cSAlexander Motin 		isp_prt(isp, ISP_LOGERR, "error loading ATIO DMA map %d", im.error);
10222df76c16SMatt Jacob 		goto bad;
10232df76c16SMatt Jacob 	}
102414849e2cSAlexander Motin 	isp_prt(isp, ISP_LOGDEBUG0, "ATIO area @ 0x%jx/0x%jx",
102514849e2cSAlexander Motin 	    (uintmax_t)im.maddr, (uintmax_t)len);
102614849e2cSAlexander Motin 	isp->isp_atioq_dma = im.maddr;
102714849e2cSAlexander Motin #endif
10282df76c16SMatt Jacob 
1029254c652bSAlexander Motin 	if (bus_dma_tag_create(ptag, 64, slim,
10307d191fdbSAlexander Motin 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
10319cca0e7eSAlexander Motin 	    2*QENTRY_LEN, 1, 2*QENTRY_LEN, 0, NULL, NULL,
10329cca0e7eSAlexander Motin 	    &isp->isp_osinfo.iocbdmat)) {
10332df76c16SMatt Jacob 		goto bad;
10342df76c16SMatt Jacob 	}
10354ff970c4SAlexander Motin 	if (bus_dmamem_alloc(isp->isp_osinfo.iocbdmat,
10364ff970c4SAlexander Motin 	    (void **)&base, BUS_DMA_COHERENT, &isp->isp_osinfo.iocbmap) != 0)
10374ff970c4SAlexander Motin 		goto bad;
10384ff970c4SAlexander Motin 	isp->isp_iocb = base;
10394ff970c4SAlexander Motin 	im.error = 0;
10404ff970c4SAlexander Motin 	if (bus_dmamap_load(isp->isp_osinfo.iocbdmat, isp->isp_osinfo.iocbmap,
10419cca0e7eSAlexander Motin 	    base, 2*QENTRY_LEN, imc, &im, BUS_DMA_NOWAIT) || im.error)
10424ff970c4SAlexander Motin 		goto bad;
10434ff970c4SAlexander Motin 	isp->isp_iocb_dma = im.maddr;
10444ff970c4SAlexander Motin 
1045254c652bSAlexander Motin 	if (bus_dma_tag_create(ptag, 64, slim,
10464ff970c4SAlexander Motin 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
10479cca0e7eSAlexander Motin 	    ISP_FC_SCRLEN, 1, ISP_FC_SCRLEN, 0, NULL, NULL,
10489cca0e7eSAlexander Motin 	    &isp->isp_osinfo.scdmat))
10494ff970c4SAlexander Motin 		goto bad;
10507d191fdbSAlexander Motin 	for (cmap = 0; cmap < isp->isp_nchan; cmap++) {
10517d191fdbSAlexander Motin 		struct isp_fc *fc = ISP_FC_PC(isp, cmap);
10527d191fdbSAlexander Motin 		if (bus_dmamem_alloc(isp->isp_osinfo.scdmat,
105314849e2cSAlexander Motin 		    (void **)&base, BUS_DMA_COHERENT, &fc->scmap) != 0)
10542df76c16SMatt Jacob 			goto bad;
105514849e2cSAlexander Motin 		FCPARAM(isp, cmap)->isp_scratch = base;
10562df76c16SMatt Jacob 		im.error = 0;
105714849e2cSAlexander Motin 		if (bus_dmamap_load(isp->isp_osinfo.scdmat, fc->scmap,
10589cca0e7eSAlexander Motin 		    base, ISP_FC_SCRLEN, imc, &im, BUS_DMA_NOWAIT) ||
10599cca0e7eSAlexander Motin 		    im.error) {
10607d191fdbSAlexander Motin 			bus_dmamem_free(isp->isp_osinfo.scdmat,
10617d191fdbSAlexander Motin 			    base, fc->scmap);
1062a1fa0267SAlexander Motin 			FCPARAM(isp, cmap)->isp_scratch = NULL;
10632df76c16SMatt Jacob 			goto bad;
10642df76c16SMatt Jacob 		}
106514849e2cSAlexander Motin 		FCPARAM(isp, cmap)->isp_scdma = im.maddr;
1066387d8239SMatt Jacob 		for (i = 0; i < INITIAL_NEXUS_COUNT; i++) {
1067387d8239SMatt Jacob 			struct isp_nexus *n = malloc(sizeof (struct isp_nexus), M_DEVBUF, M_NOWAIT | M_ZERO);
1068387d8239SMatt Jacob 			if (n == NULL) {
1069387d8239SMatt Jacob 				while (fc->nexus_free_list) {
1070387d8239SMatt Jacob 					n = fc->nexus_free_list;
1071387d8239SMatt Jacob 					fc->nexus_free_list = n->next;
1072387d8239SMatt Jacob 					free(n, M_DEVBUF);
1073387d8239SMatt Jacob 				}
1074387d8239SMatt Jacob 				goto bad;
1075387d8239SMatt Jacob 			}
1076387d8239SMatt Jacob 			n->next = fc->nexus_free_list;
1077387d8239SMatt Jacob 			fc->nexus_free_list = n;
1078387d8239SMatt Jacob 		}
10792df76c16SMatt Jacob 	}
10802df76c16SMatt Jacob 
1081a1fa0267SAlexander Motin 	if (isp->isp_maxcmds == 0) {
1082a1fa0267SAlexander Motin 		ISP_LOCK(isp);
1083a1fa0267SAlexander Motin 		return (0);
1084a1fa0267SAlexander Motin 	}
1085a1fa0267SAlexander Motin 
1086a1fa0267SAlexander Motin gotmaxcmds:
1087254c652bSAlexander Motin 	if (bus_dma_tag_create(ptag, 1, slim,
1088254c652bSAlexander Motin 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
1089254c652bSAlexander Motin 	    (ISP_NSEG64_MAX - 1) * PAGE_SIZE, ISP_NSEG64_MAX,
1090254c652bSAlexander Motin 	    (ISP_NSEG64_MAX - 1) * PAGE_SIZE, 0,
1091254c652bSAlexander Motin 	    busdma_lock_mutex, &isp->isp_lock, &isp->isp_osinfo.dmat))
1092254c652bSAlexander Motin 		goto bad;
1093a1fa0267SAlexander Motin 	len = isp->isp_maxcmds * sizeof (struct isp_pcmd);
1094a1fa0267SAlexander Motin 	isp->isp_osinfo.pcmd_pool = (struct isp_pcmd *)
1095a1fa0267SAlexander Motin 	    malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
1096a95ae193SMatt Jacob 	for (i = 0; i < isp->isp_maxcmds; i++) {
10970a70657fSMatt Jacob 		struct isp_pcmd *pcmd = &isp->isp_osinfo.pcmd_pool[i];
10980a70657fSMatt Jacob 		error = bus_dmamap_create(isp->isp_osinfo.dmat, 0, &pcmd->dmap);
1099d720e6d5SJustin T. Gibbs 		if (error) {
11002df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "error %d creating per-cmd DMA maps", error);
11011923f739SMatt Jacob 			while (--i >= 0) {
1102a1fa0267SAlexander Motin 				bus_dmamap_destroy(isp->isp_osinfo.dmat,
1103a1fa0267SAlexander Motin 				    isp->isp_osinfo.pcmd_pool[i].dmap);
11041923f739SMatt Jacob 			}
11051923f739SMatt Jacob 			goto bad;
1106d720e6d5SJustin T. Gibbs 		}
110713d9c921SAlexander Motin 		callout_init_mtx(&pcmd->wdog, &isp->isp_lock, 0);
1108a1fa0267SAlexander Motin 		if (i == isp->isp_maxcmds-1)
11090a70657fSMatt Jacob 			pcmd->next = NULL;
1110a1fa0267SAlexander Motin 		else
11110a70657fSMatt Jacob 			pcmd->next = &isp->isp_osinfo.pcmd_pool[i+1];
1112d720e6d5SJustin T. Gibbs 	}
11130a70657fSMatt Jacob 	isp->isp_osinfo.pcmd_free = &isp->isp_osinfo.pcmd_pool[0];
1114a1fa0267SAlexander Motin 
11150b19f90aSAlexander Motin 	len = sizeof(isp_hdl_t) * ISP_HANDLE_NUM(isp);
1116a1fa0267SAlexander Motin 	isp->isp_xflist = (isp_hdl_t *) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
11170b19f90aSAlexander Motin 	for (len = 0; len < ISP_HANDLE_NUM(isp) - 1; len++)
1118a1fa0267SAlexander Motin 		isp->isp_xflist[len].cmd = &isp->isp_xflist[len+1];
1119a1fa0267SAlexander Motin 	isp->isp_xffree = isp->isp_xflist;
1120a1fa0267SAlexander Motin 
112172429e49SMatt Jacob 	ISP_LOCK(isp);
1122d720e6d5SJustin T. Gibbs 	return (0);
11231923f739SMatt Jacob 
11241923f739SMatt Jacob bad:
1125a1fa0267SAlexander Motin 	isp_pci_mbxdmafree(isp);
1126a1fa0267SAlexander Motin 	ISP_LOCK(isp);
1127a1fa0267SAlexander Motin 	return (1);
1128a1fa0267SAlexander Motin }
1129a1fa0267SAlexander Motin 
1130a1fa0267SAlexander Motin static void
1131a1fa0267SAlexander Motin isp_pci_mbxdmafree(ispsoftc_t *isp)
1132a1fa0267SAlexander Motin {
1133a1fa0267SAlexander Motin 	int i;
1134a1fa0267SAlexander Motin 
1135a1fa0267SAlexander Motin 	if (isp->isp_xflist != NULL) {
1136a1fa0267SAlexander Motin 		free(isp->isp_xflist, M_DEVBUF);
1137a1fa0267SAlexander Motin 		isp->isp_xflist = NULL;
1138a1fa0267SAlexander Motin 	}
1139a1fa0267SAlexander Motin 	if (isp->isp_osinfo.pcmd_pool != NULL) {
1140a1fa0267SAlexander Motin 		for (i = 0; i < isp->isp_maxcmds; i++) {
1141a1fa0267SAlexander Motin 			bus_dmamap_destroy(isp->isp_osinfo.dmat,
1142a1fa0267SAlexander Motin 			    isp->isp_osinfo.pcmd_pool[i].dmap);
1143a1fa0267SAlexander Motin 		}
1144a1fa0267SAlexander Motin 		free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
1145a1fa0267SAlexander Motin 		isp->isp_osinfo.pcmd_pool = NULL;
1146a1fa0267SAlexander Motin 	}
1147254c652bSAlexander Motin 	if (isp->isp_osinfo.dmat) {
1148254c652bSAlexander Motin 		bus_dma_tag_destroy(isp->isp_osinfo.dmat);
1149254c652bSAlexander Motin 		isp->isp_osinfo.dmat = NULL;
1150254c652bSAlexander Motin 	}
1151a1fa0267SAlexander Motin 	for (i = 0; i < isp->isp_nchan; i++) {
1152a1fa0267SAlexander Motin 		struct isp_fc *fc = ISP_FC_PC(isp, i);
1153a1fa0267SAlexander Motin 		if (FCPARAM(isp, i)->isp_scdma != 0) {
1154a1fa0267SAlexander Motin 			bus_dmamap_unload(isp->isp_osinfo.scdmat,
1155a1fa0267SAlexander Motin 			    fc->scmap);
1156a1fa0267SAlexander Motin 			FCPARAM(isp, i)->isp_scdma = 0;
1157a1fa0267SAlexander Motin 		}
1158a1fa0267SAlexander Motin 		if (FCPARAM(isp, i)->isp_scratch != NULL) {
11594ff970c4SAlexander Motin 			bus_dmamem_free(isp->isp_osinfo.scdmat,
1160a1fa0267SAlexander Motin 			    FCPARAM(isp, i)->isp_scratch, fc->scmap);
1161a1fa0267SAlexander Motin 			FCPARAM(isp, i)->isp_scratch = NULL;
1162a1fa0267SAlexander Motin 		}
1163387d8239SMatt Jacob 		while (fc->nexus_free_list) {
1164387d8239SMatt Jacob 			struct isp_nexus *n = fc->nexus_free_list;
1165387d8239SMatt Jacob 			fc->nexus_free_list = n->next;
1166387d8239SMatt Jacob 			free(n, M_DEVBUF);
1167387d8239SMatt Jacob 		}
11682df76c16SMatt Jacob 	}
1169254c652bSAlexander Motin 	if (isp->isp_osinfo.scdmat) {
11707d191fdbSAlexander Motin 		bus_dma_tag_destroy(isp->isp_osinfo.scdmat);
1171254c652bSAlexander Motin 		isp->isp_osinfo.scdmat = NULL;
1172254c652bSAlexander Motin 	}
1173254c652bSAlexander Motin 	if (isp->isp_iocb_dma != 0) {
1174a1fa0267SAlexander Motin 		bus_dmamap_unload(isp->isp_osinfo.iocbdmat,
11754ff970c4SAlexander Motin 		    isp->isp_osinfo.iocbmap);
1176a1fa0267SAlexander Motin 		isp->isp_iocb_dma = 0;
1177a1fa0267SAlexander Motin 	}
1178a1fa0267SAlexander Motin 	if (isp->isp_iocb != NULL) {
1179a1fa0267SAlexander Motin 		bus_dmamem_free(isp->isp_osinfo.iocbdmat,
1180a1fa0267SAlexander Motin 		    isp->isp_iocb, isp->isp_osinfo.iocbmap);
11814ff970c4SAlexander Motin 		bus_dma_tag_destroy(isp->isp_osinfo.iocbdmat);
11827d191fdbSAlexander Motin 	}
118314849e2cSAlexander Motin #ifdef	ISP_TARGET_MODE
118414849e2cSAlexander Motin 	if (isp->isp_atioq_dma != 0) {
118514849e2cSAlexander Motin 		bus_dmamap_unload(isp->isp_osinfo.atiodmat,
118614849e2cSAlexander Motin 		    isp->isp_osinfo.atiomap);
1187a1fa0267SAlexander Motin 		isp->isp_atioq_dma = 0;
118814849e2cSAlexander Motin 	}
118914849e2cSAlexander Motin 	if (isp->isp_atioq != NULL) {
1190a1fa0267SAlexander Motin 		bus_dmamem_free(isp->isp_osinfo.atiodmat, isp->isp_atioq,
119114849e2cSAlexander Motin 		    isp->isp_osinfo.atiomap);
119214849e2cSAlexander Motin 		bus_dma_tag_destroy(isp->isp_osinfo.atiodmat);
1193a1fa0267SAlexander Motin 		isp->isp_atioq = NULL;
119414849e2cSAlexander Motin 	}
119514849e2cSAlexander Motin #endif
1196a1fa0267SAlexander Motin 	if (isp->isp_result_dma != 0) {
1197a1fa0267SAlexander Motin 		bus_dmamap_unload(isp->isp_osinfo.respdmat,
1198a1fa0267SAlexander Motin 		    isp->isp_osinfo.respmap);
1199a1fa0267SAlexander Motin 		isp->isp_result_dma = 0;
1200a1fa0267SAlexander Motin 	}
1201a1fa0267SAlexander Motin 	if (isp->isp_result != NULL) {
1202a1fa0267SAlexander Motin 		bus_dmamem_free(isp->isp_osinfo.respdmat, isp->isp_result,
1203a1fa0267SAlexander Motin 		    isp->isp_osinfo.respmap);
1204a1fa0267SAlexander Motin 		bus_dma_tag_destroy(isp->isp_osinfo.respdmat);
1205a1fa0267SAlexander Motin 		isp->isp_result = NULL;
1206a1fa0267SAlexander Motin 	}
1207cf770ba3SAlexander Motin #ifdef	ISP_TARGET_MODE
1208cf770ba3SAlexander Motin 	if (isp->isp_osinfo.ecmd_dma != 0) {
1209cf770ba3SAlexander Motin 		bus_dmamap_unload(isp->isp_osinfo.ecmd_dmat,
1210cf770ba3SAlexander Motin 		    isp->isp_osinfo.ecmd_map);
1211cf770ba3SAlexander Motin 		isp->isp_osinfo.ecmd_dma = 0;
1212cf770ba3SAlexander Motin 	}
1213cf770ba3SAlexander Motin 	if (isp->isp_osinfo.ecmd_base != NULL) {
1214cf770ba3SAlexander Motin 		bus_dmamem_free(isp->isp_osinfo.ecmd_dmat, isp->isp_osinfo.ecmd_base,
1215cf770ba3SAlexander Motin 		    isp->isp_osinfo.ecmd_map);
1216cf770ba3SAlexander Motin 		bus_dma_tag_destroy(isp->isp_osinfo.ecmd_dmat);
1217cf770ba3SAlexander Motin 		isp->isp_osinfo.ecmd_base = NULL;
1218cf770ba3SAlexander Motin 	}
1219cf770ba3SAlexander Motin #endif
1220a1fa0267SAlexander Motin 	if (isp->isp_rquest_dma != 0) {
1221a1fa0267SAlexander Motin 		bus_dmamap_unload(isp->isp_osinfo.reqdmat,
1222a1fa0267SAlexander Motin 		    isp->isp_osinfo.reqmap);
1223a1fa0267SAlexander Motin 		isp->isp_rquest_dma = 0;
1224a1fa0267SAlexander Motin 	}
1225a1fa0267SAlexander Motin 	if (isp->isp_rquest != NULL) {
1226a1fa0267SAlexander Motin 		bus_dmamem_free(isp->isp_osinfo.reqdmat, isp->isp_rquest,
1227a1fa0267SAlexander Motin 		    isp->isp_osinfo.reqmap);
1228a1fa0267SAlexander Motin 		bus_dma_tag_destroy(isp->isp_osinfo.reqdmat);
12291923f739SMatt Jacob 		isp->isp_rquest = NULL;
1230a1fa0267SAlexander Motin 	}
1231d720e6d5SJustin T. Gibbs }
1232d720e6d5SJustin T. Gibbs 
1233a1fa0267SAlexander Motin static int
1234a1fa0267SAlexander Motin isp_pci_irqsetup(ispsoftc_t *isp)
12353bda7a83SMatt Jacob {
123608826086SAlexander Motin 	device_t dev = isp->isp_osinfo.dev;
123708826086SAlexander Motin 	struct isp_pcisoftc *pcs = device_get_softc(dev);
123808826086SAlexander Motin 	driver_intr_t *f;
123908826086SAlexander Motin 	int i, max_irq;
12403bda7a83SMatt Jacob 
124108826086SAlexander Motin 	/* Allocate IRQs only once. */
124208826086SAlexander Motin 	if (isp->isp_nirq > 0)
1243a1fa0267SAlexander Motin 		return (0);
124408826086SAlexander Motin 
1245abdc2e31SAlexander Motin 	ISP_UNLOCK(isp);
124608826086SAlexander Motin 	if (ISP_CAP_MSIX(isp)) {
12471f8c4546SAlexander Motin 		max_irq = IS_26XX(isp) ? 3 : (IS_25XX(isp) ? 2 : 0);
124817ec7746SAlexander Motin 		resource_int_value(device_get_name(dev),
124917ec7746SAlexander Motin 		    device_get_unit(dev), "msix", &max_irq);
125017ec7746SAlexander Motin 		max_irq = imin(ISP_MAX_IRQS, max_irq);
125108826086SAlexander Motin 		pcs->msicount = imin(pci_msix_count(dev), max_irq);
125208826086SAlexander Motin 		if (pcs->msicount > 0 &&
125308826086SAlexander Motin 		    pci_alloc_msix(dev, &pcs->msicount) != 0)
125408826086SAlexander Motin 			pcs->msicount = 0;
125508826086SAlexander Motin 	}
125608826086SAlexander Motin 	if (pcs->msicount == 0) {
125717ec7746SAlexander Motin 		max_irq = 1;
125817ec7746SAlexander Motin 		resource_int_value(device_get_name(dev),
125917ec7746SAlexander Motin 		    device_get_unit(dev), "msi", &max_irq);
126017ec7746SAlexander Motin 		max_irq = imin(1, max_irq);
126117ec7746SAlexander Motin 		pcs->msicount = imin(pci_msi_count(dev), max_irq);
126208826086SAlexander Motin 		if (pcs->msicount > 0 &&
126308826086SAlexander Motin 		    pci_alloc_msi(dev, &pcs->msicount) != 0)
126408826086SAlexander Motin 			pcs->msicount = 0;
126508826086SAlexander Motin 	}
126608826086SAlexander Motin 	for (i = 0; i < MAX(1, pcs->msicount); i++) {
126708826086SAlexander Motin 		pcs->irq[i].iqd = i + (pcs->msicount > 0);
126808826086SAlexander Motin 		pcs->irq[i].irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
126908826086SAlexander Motin 		    &pcs->irq[i].iqd, RF_ACTIVE | RF_SHAREABLE);
127008826086SAlexander Motin 		if (pcs->irq[i].irq == NULL) {
127108826086SAlexander Motin 			device_printf(dev, "could not allocate interrupt\n");
127208826086SAlexander Motin 			break;
127308826086SAlexander Motin 		}
127408826086SAlexander Motin 		if (i == 0)
127508826086SAlexander Motin 			f = isp_platform_intr;
127608826086SAlexander Motin 		else if (i == 1)
127708826086SAlexander Motin 			f = isp_platform_intr_resp;
127808826086SAlexander Motin 		else
127908826086SAlexander Motin 			f = isp_platform_intr_atio;
128008826086SAlexander Motin 		if (bus_setup_intr(dev, pcs->irq[i].irq, ISP_IFLAGS, NULL,
128108826086SAlexander Motin 		    f, isp, &pcs->irq[i].ih)) {
128208826086SAlexander Motin 			device_printf(dev, "could not setup interrupt\n");
128308826086SAlexander Motin 			(void) bus_release_resource(dev, SYS_RES_IRQ,
128408826086SAlexander Motin 			    pcs->irq[i].iqd, pcs->irq[i].irq);
128508826086SAlexander Motin 			break;
128608826086SAlexander Motin 		}
128708826086SAlexander Motin 		if (pcs->msicount > 1) {
128808826086SAlexander Motin 			bus_describe_intr(dev, pcs->irq[i].irq, pcs->irq[i].ih,
128908826086SAlexander Motin 			    "%d", i);
129008826086SAlexander Motin 		}
129108826086SAlexander Motin 		isp->isp_nirq = i + 1;
129208826086SAlexander Motin 	}
1293abdc2e31SAlexander Motin 	ISP_LOCK(isp);
129408826086SAlexander Motin 
129508826086SAlexander Motin 	return (isp->isp_nirq == 0);
129665adb54cSMatt Jacob }
1297