xref: /freebsd/sys/dev/isp/isp_pci.c (revision 17bc427d0b1ebb2c0686f8133982541c034f0e10)
1aad970f1SDavid E. O'Brien /*-
22df76c16SMatt Jacob  * Copyright (c) 1997-2008 by Matthew Jacob
3e5265237SMatt Jacob  * All rights reserved.
465adb54cSMatt Jacob  *
565adb54cSMatt Jacob  * Redistribution and use in source and binary forms, with or without
665adb54cSMatt Jacob  * modification, are permitted provided that the following conditions
765adb54cSMatt Jacob  * are met:
865adb54cSMatt Jacob  * 1. Redistributions of source code must retain the above copyright
965adb54cSMatt Jacob  *    notice immediately at the beginning of the file, without modification,
1065adb54cSMatt Jacob  *    this list of conditions, and the following disclaimer.
11aa57fd6fSMatt Jacob  * 2. The name of the author may not be used to endorse or promote products
12aa57fd6fSMatt Jacob  *    derived from this software without specific prior written permission.
1365adb54cSMatt Jacob  *
1465adb54cSMatt Jacob  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1565adb54cSMatt Jacob  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1665adb54cSMatt Jacob  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1765adb54cSMatt Jacob  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
1865adb54cSMatt Jacob  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1965adb54cSMatt Jacob  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2065adb54cSMatt Jacob  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2165adb54cSMatt Jacob  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2265adb54cSMatt Jacob  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2365adb54cSMatt Jacob  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2465adb54cSMatt Jacob  * SUCH DAMAGE.
2565adb54cSMatt Jacob  */
26799881e0SMatt Jacob /*
27799881e0SMatt Jacob  * PCI specific probe and attach routines for Qlogic ISP SCSI adapters.
28799881e0SMatt Jacob  * FreeBSD Version.
29799881e0SMatt Jacob  */
30aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
31aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
32aad970f1SDavid E. O'Brien 
33960f6939SMatt Jacob #include <sys/param.h>
34960f6939SMatt Jacob #include <sys/systm.h>
35960f6939SMatt Jacob #include <sys/kernel.h>
36960f6939SMatt Jacob #include <sys/module.h>
379a5af410SMatt Jacob #include <sys/linker.h>
389a5af410SMatt Jacob #include <sys/firmware.h>
39960f6939SMatt Jacob #include <sys/bus.h>
4074a96f43SJohn Baldwin #include <sys/stdint.h>
4177e6a3b2SWarner Losh #include <dev/pci/pcireg.h>
4277e6a3b2SWarner Losh #include <dev/pci/pcivar.h>
43d720e6d5SJustin T. Gibbs #include <machine/bus.h>
44960f6939SMatt Jacob #include <machine/resource.h>
45960f6939SMatt Jacob #include <sys/rman.h>
46960f6939SMatt Jacob #include <sys/malloc.h>
472df76c16SMatt Jacob #include <sys/uio.h>
48960f6939SMatt Jacob 
49*17bc427dSMarius Strobl #ifdef __sparc64__
50*17bc427dSMarius Strobl #include <dev/ofw/openfirm.h>
51*17bc427dSMarius Strobl #include <machine/ofw_machdep.h>
52*17bc427dSMarius Strobl #endif
53*17bc427dSMarius Strobl 
54960f6939SMatt Jacob #include <dev/isp/isp_freebsd.h>
55d59bd469SMatt Jacob 
5610365e5aSMatt Jacob static uint32_t isp_pci_rd_reg(ispsoftc_t *, int);
5710365e5aSMatt Jacob static void isp_pci_wr_reg(ispsoftc_t *, int, uint32_t);
5810365e5aSMatt Jacob static uint32_t isp_pci_rd_reg_1080(ispsoftc_t *, int);
5910365e5aSMatt Jacob static void isp_pci_wr_reg_1080(ispsoftc_t *, int, uint32_t);
6010365e5aSMatt Jacob static uint32_t isp_pci_rd_reg_2400(ispsoftc_t *, int);
6110365e5aSMatt Jacob static void isp_pci_wr_reg_2400(ispsoftc_t *, int, uint32_t);
622df76c16SMatt Jacob static int isp_pci_rd_isr(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *);
632df76c16SMatt Jacob static int isp_pci_rd_isr_2300(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *);
642df76c16SMatt Jacob static int isp_pci_rd_isr_2400(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *);
659cd7268eSMatt Jacob static int isp_pci_mbxdma(ispsoftc_t *);
662df76c16SMatt Jacob static int isp_pci_dmasetup(ispsoftc_t *, XS_T *, void *);
679cd7268eSMatt Jacob 
689a5af410SMatt Jacob 
693bda7a83SMatt Jacob static void isp_pci_reset0(ispsoftc_t *);
709cd7268eSMatt Jacob static void isp_pci_reset1(ispsoftc_t *);
719cd7268eSMatt Jacob static void isp_pci_dumpregs(ispsoftc_t *, const char *);
7265adb54cSMatt Jacob 
7365adb54cSMatt Jacob static struct ispmdvec mdvec = {
74126ec864SMatt Jacob 	isp_pci_rd_isr,
7565adb54cSMatt Jacob 	isp_pci_rd_reg,
7665adb54cSMatt Jacob 	isp_pci_wr_reg,
7765adb54cSMatt Jacob 	isp_pci_mbxdma,
7865adb54cSMatt Jacob 	isp_pci_dmasetup,
790a70657fSMatt Jacob 	isp_common_dmateardown,
803bda7a83SMatt Jacob 	isp_pci_reset0,
8165adb54cSMatt Jacob 	isp_pci_reset1,
8265adb54cSMatt Jacob 	isp_pci_dumpregs,
8356aef503SMatt Jacob 	NULL,
84d02373f1SMatt Jacob 	BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64
8565adb54cSMatt Jacob };
8665adb54cSMatt Jacob 
87d59bd469SMatt Jacob static struct ispmdvec mdvec_1080 = {
88126ec864SMatt Jacob 	isp_pci_rd_isr,
89d59bd469SMatt Jacob 	isp_pci_rd_reg_1080,
90d59bd469SMatt Jacob 	isp_pci_wr_reg_1080,
91d59bd469SMatt Jacob 	isp_pci_mbxdma,
92d59bd469SMatt Jacob 	isp_pci_dmasetup,
930a70657fSMatt Jacob 	isp_common_dmateardown,
943bda7a83SMatt Jacob 	isp_pci_reset0,
95d59bd469SMatt Jacob 	isp_pci_reset1,
96d59bd469SMatt Jacob 	isp_pci_dumpregs,
9756aef503SMatt Jacob 	NULL,
98d02373f1SMatt Jacob 	BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64
99d59bd469SMatt Jacob };
100d59bd469SMatt Jacob 
101960f6939SMatt Jacob static struct ispmdvec mdvec_12160 = {
102126ec864SMatt Jacob 	isp_pci_rd_isr,
103960f6939SMatt Jacob 	isp_pci_rd_reg_1080,
104960f6939SMatt Jacob 	isp_pci_wr_reg_1080,
105960f6939SMatt Jacob 	isp_pci_mbxdma,
106960f6939SMatt Jacob 	isp_pci_dmasetup,
1070a70657fSMatt Jacob 	isp_common_dmateardown,
1083bda7a83SMatt Jacob 	isp_pci_reset0,
109960f6939SMatt Jacob 	isp_pci_reset1,
110960f6939SMatt Jacob 	isp_pci_dumpregs,
11156aef503SMatt Jacob 	NULL,
112d02373f1SMatt Jacob 	BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64
113960f6939SMatt Jacob };
114960f6939SMatt Jacob 
11565adb54cSMatt Jacob static struct ispmdvec mdvec_2100 = {
116126ec864SMatt Jacob 	isp_pci_rd_isr,
11765adb54cSMatt Jacob 	isp_pci_rd_reg,
11865adb54cSMatt Jacob 	isp_pci_wr_reg,
11965adb54cSMatt Jacob 	isp_pci_mbxdma,
12065adb54cSMatt Jacob 	isp_pci_dmasetup,
1210a70657fSMatt Jacob 	isp_common_dmateardown,
1223bda7a83SMatt Jacob 	isp_pci_reset0,
12365adb54cSMatt Jacob 	isp_pci_reset1,
124d02373f1SMatt Jacob 	isp_pci_dumpregs
12565adb54cSMatt Jacob };
126222bb542SMatt Jacob 
127222bb542SMatt Jacob static struct ispmdvec mdvec_2200 = {
128126ec864SMatt Jacob 	isp_pci_rd_isr,
129126ec864SMatt Jacob 	isp_pci_rd_reg,
130126ec864SMatt Jacob 	isp_pci_wr_reg,
131126ec864SMatt Jacob 	isp_pci_mbxdma,
132126ec864SMatt Jacob 	isp_pci_dmasetup,
1330a70657fSMatt Jacob 	isp_common_dmateardown,
1343bda7a83SMatt Jacob 	isp_pci_reset0,
135126ec864SMatt Jacob 	isp_pci_reset1,
136126ec864SMatt Jacob 	isp_pci_dumpregs
137126ec864SMatt Jacob };
138126ec864SMatt Jacob 
139126ec864SMatt Jacob static struct ispmdvec mdvec_2300 = {
140126ec864SMatt Jacob 	isp_pci_rd_isr_2300,
141222bb542SMatt Jacob 	isp_pci_rd_reg,
142222bb542SMatt Jacob 	isp_pci_wr_reg,
143222bb542SMatt Jacob 	isp_pci_mbxdma,
144222bb542SMatt Jacob 	isp_pci_dmasetup,
1450a70657fSMatt Jacob 	isp_common_dmateardown,
1463bda7a83SMatt Jacob 	isp_pci_reset0,
147222bb542SMatt Jacob 	isp_pci_reset1,
148d02373f1SMatt Jacob 	isp_pci_dumpregs
149222bb542SMatt Jacob };
150d951bbcaSMatt Jacob 
15110365e5aSMatt Jacob static struct ispmdvec mdvec_2400 = {
15210365e5aSMatt Jacob 	isp_pci_rd_isr_2400,
15310365e5aSMatt Jacob 	isp_pci_rd_reg_2400,
15410365e5aSMatt Jacob 	isp_pci_wr_reg_2400,
15510365e5aSMatt Jacob 	isp_pci_mbxdma,
15610365e5aSMatt Jacob 	isp_pci_dmasetup,
1570a70657fSMatt Jacob 	isp_common_dmateardown,
1583bda7a83SMatt Jacob 	isp_pci_reset0,
15910365e5aSMatt Jacob 	isp_pci_reset1,
16010365e5aSMatt Jacob 	NULL
16110365e5aSMatt Jacob };
16210365e5aSMatt Jacob 
1632df76c16SMatt Jacob static struct ispmdvec mdvec_2500 = {
1642df76c16SMatt Jacob 	isp_pci_rd_isr_2400,
1652df76c16SMatt Jacob 	isp_pci_rd_reg_2400,
1662df76c16SMatt Jacob 	isp_pci_wr_reg_2400,
1672df76c16SMatt Jacob 	isp_pci_mbxdma,
1682df76c16SMatt Jacob 	isp_pci_dmasetup,
1692df76c16SMatt Jacob 	isp_common_dmateardown,
1702df76c16SMatt Jacob 	isp_pci_reset0,
1712df76c16SMatt Jacob 	isp_pci_reset1,
1722df76c16SMatt Jacob 	NULL
1732df76c16SMatt Jacob };
1742df76c16SMatt Jacob 
17565adb54cSMatt Jacob #ifndef	PCIM_CMD_INVEN
17665adb54cSMatt Jacob #define	PCIM_CMD_INVEN			0x10
17765adb54cSMatt Jacob #endif
17865adb54cSMatt Jacob #ifndef	PCIM_CMD_BUSMASTEREN
17965adb54cSMatt Jacob #define	PCIM_CMD_BUSMASTEREN		0x0004
18065adb54cSMatt Jacob #endif
181d951bbcaSMatt Jacob #ifndef	PCIM_CMD_PERRESPEN
182d951bbcaSMatt Jacob #define	PCIM_CMD_PERRESPEN		0x0040
183d951bbcaSMatt Jacob #endif
184d951bbcaSMatt Jacob #ifndef	PCIM_CMD_SEREN
185d951bbcaSMatt Jacob #define	PCIM_CMD_SEREN			0x0100
186d951bbcaSMatt Jacob #endif
1878a97c03aSMatt Jacob #ifndef	PCIM_CMD_INTX_DISABLE
1888a97c03aSMatt Jacob #define	PCIM_CMD_INTX_DISABLE		0x0400
1898a97c03aSMatt Jacob #endif
190d951bbcaSMatt Jacob 
191d951bbcaSMatt Jacob #ifndef	PCIR_COMMAND
192d951bbcaSMatt Jacob #define	PCIR_COMMAND			0x04
193d951bbcaSMatt Jacob #endif
194d951bbcaSMatt Jacob 
195d951bbcaSMatt Jacob #ifndef	PCIR_CACHELNSZ
196d951bbcaSMatt Jacob #define	PCIR_CACHELNSZ			0x0c
197d951bbcaSMatt Jacob #endif
198d951bbcaSMatt Jacob 
199d951bbcaSMatt Jacob #ifndef	PCIR_LATTIMER
200d951bbcaSMatt Jacob #define	PCIR_LATTIMER			0x0d
201d951bbcaSMatt Jacob #endif
202d951bbcaSMatt Jacob 
203ab6d0040SMatt Jacob #ifndef	PCIR_ROMADDR
204ab6d0040SMatt Jacob #define	PCIR_ROMADDR			0x30
205ab6d0040SMatt Jacob #endif
206ab6d0040SMatt Jacob 
20765adb54cSMatt Jacob #ifndef	PCI_VENDOR_QLOGIC
20865adb54cSMatt Jacob #define	PCI_VENDOR_QLOGIC		0x1077
20965adb54cSMatt Jacob #endif
21065adb54cSMatt Jacob 
21165adb54cSMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1020
21265adb54cSMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1020	0x1020
21365adb54cSMatt Jacob #endif
21465adb54cSMatt Jacob 
215d59bd469SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1080
216d59bd469SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1080	0x1080
217d59bd469SMatt Jacob #endif
218d59bd469SMatt Jacob 
219f556e83bSMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP10160
220f556e83bSMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP10160	0x1016
221f556e83bSMatt Jacob #endif
222f556e83bSMatt Jacob 
223960f6939SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP12160
224960f6939SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP12160	0x1216
225960f6939SMatt Jacob #endif
226960f6939SMatt Jacob 
227d59bd469SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1240
228d59bd469SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1240	0x1240
229d59bd469SMatt Jacob #endif
23065adb54cSMatt Jacob 
23122e1dc85SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1280
23222e1dc85SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1280	0x1280
23322e1dc85SMatt Jacob #endif
23422e1dc85SMatt Jacob 
23565adb54cSMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP2100
23665adb54cSMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2100	0x2100
23765adb54cSMatt Jacob #endif
23865adb54cSMatt Jacob 
239222bb542SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP2200
240222bb542SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2200	0x2200
241222bb542SMatt Jacob #endif
242222bb542SMatt Jacob 
243126ec864SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP2300
244126ec864SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2300	0x2300
245126ec864SMatt Jacob #endif
246126ec864SMatt Jacob 
247126ec864SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP2312
248126ec864SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2312	0x2312
249126ec864SMatt Jacob #endif
250126ec864SMatt Jacob 
251e5265237SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP2322
252e5265237SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2322	0x2322
253e5265237SMatt Jacob #endif
254e5265237SMatt Jacob 
2558872e3d7SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP2422
2568872e3d7SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2422	0x2422
2578872e3d7SMatt Jacob #endif
2588872e3d7SMatt Jacob 
25941675df0SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP2432
26041675df0SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2432	0x2432
26141675df0SMatt Jacob #endif
26241675df0SMatt Jacob 
2632df76c16SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP2532
2642df76c16SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2532	0x2532
2652df76c16SMatt Jacob #endif
2662df76c16SMatt Jacob 
267dd1419abSMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP6312
268dd1419abSMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP6312	0x6312
269dd1419abSMatt Jacob #endif
270dd1419abSMatt Jacob 
2719a5af410SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP6322
2729a5af410SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP6322	0x6322
2739a5af410SMatt Jacob #endif
2749a5af410SMatt Jacob 
2759a5af410SMatt Jacob 
27656aef503SMatt Jacob #define	PCI_QLOGIC_ISP1020	\
27756aef503SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC)
278d59bd469SMatt Jacob 
279d59bd469SMatt Jacob #define	PCI_QLOGIC_ISP1080	\
280d59bd469SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC)
281d59bd469SMatt Jacob 
282f556e83bSMatt Jacob #define	PCI_QLOGIC_ISP10160	\
283f556e83bSMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP10160 << 16) | PCI_VENDOR_QLOGIC)
284f556e83bSMatt Jacob 
285960f6939SMatt Jacob #define	PCI_QLOGIC_ISP12160	\
286960f6939SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP12160 << 16) | PCI_VENDOR_QLOGIC)
287960f6939SMatt Jacob 
288d59bd469SMatt Jacob #define	PCI_QLOGIC_ISP1240	\
289d59bd469SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC)
290d59bd469SMatt Jacob 
29122e1dc85SMatt Jacob #define	PCI_QLOGIC_ISP1280	\
29222e1dc85SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1280 << 16) | PCI_VENDOR_QLOGIC)
29322e1dc85SMatt Jacob 
29465adb54cSMatt Jacob #define	PCI_QLOGIC_ISP2100	\
29565adb54cSMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC)
29665adb54cSMatt Jacob 
297222bb542SMatt Jacob #define	PCI_QLOGIC_ISP2200	\
298222bb542SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2200 << 16) | PCI_VENDOR_QLOGIC)
299222bb542SMatt Jacob 
300126ec864SMatt Jacob #define	PCI_QLOGIC_ISP2300	\
301126ec864SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2300 << 16) | PCI_VENDOR_QLOGIC)
302126ec864SMatt Jacob 
303126ec864SMatt Jacob #define	PCI_QLOGIC_ISP2312	\
304126ec864SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2312 << 16) | PCI_VENDOR_QLOGIC)
305126ec864SMatt Jacob 
306e5265237SMatt Jacob #define	PCI_QLOGIC_ISP2322	\
307e5265237SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2322 << 16) | PCI_VENDOR_QLOGIC)
308e5265237SMatt Jacob 
3096c426685SMatt Jacob #define	PCI_QLOGIC_ISP2422	\
3106c426685SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2422 << 16) | PCI_VENDOR_QLOGIC)
3116c426685SMatt Jacob 
31241675df0SMatt Jacob #define	PCI_QLOGIC_ISP2432	\
31341675df0SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2432 << 16) | PCI_VENDOR_QLOGIC)
31441675df0SMatt Jacob 
3152df76c16SMatt Jacob #define	PCI_QLOGIC_ISP2532	\
3162df76c16SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2532 << 16) | PCI_VENDOR_QLOGIC)
3172df76c16SMatt Jacob 
318dd1419abSMatt Jacob #define	PCI_QLOGIC_ISP6312	\
319dd1419abSMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP6312 << 16) | PCI_VENDOR_QLOGIC)
320dd1419abSMatt Jacob 
3219a5af410SMatt Jacob #define	PCI_QLOGIC_ISP6322	\
3229a5af410SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP6322 << 16) | PCI_VENDOR_QLOGIC)
3239a5af410SMatt Jacob 
324e11a1ee8SMatt Jacob /*
325e11a1ee8SMatt Jacob  * Odd case for some AMI raid cards... We need to *not* attach to this.
326e11a1ee8SMatt Jacob  */
327e11a1ee8SMatt Jacob #define	AMI_RAID_SUBVENDOR_ID	0x101e
328e11a1ee8SMatt Jacob 
32965adb54cSMatt Jacob #define	IO_MAP_REG	0x10
33065adb54cSMatt Jacob #define	MEM_MAP_REG	0x14
33165adb54cSMatt Jacob 
332d951bbcaSMatt Jacob #define	PCI_DFLT_LTNCY	0x40
333d951bbcaSMatt Jacob #define	PCI_DFLT_LNSZ	0x10
33465adb54cSMatt Jacob 
335960f6939SMatt Jacob static int isp_pci_probe (device_t);
336960f6939SMatt Jacob static int isp_pci_attach (device_t);
33710365e5aSMatt Jacob static int isp_pci_detach (device_t);
33865adb54cSMatt Jacob 
3391923f739SMatt Jacob 
3400230a28bSMatt Jacob #define	ISP_PCD(isp)	((struct isp_pcisoftc *)isp)->pci_dev
34165adb54cSMatt Jacob struct isp_pcisoftc {
3429cd7268eSMatt Jacob 	ispsoftc_t			pci_isp;
343960f6939SMatt Jacob 	device_t			pci_dev;
344960f6939SMatt Jacob 	struct resource *		pci_reg;
345960f6939SMatt Jacob 	void *				ih;
346d59bd469SMatt Jacob 	int16_t				pci_poff[_NREG_BLKS];
3471923f739SMatt Jacob 	bus_dma_tag_t			dmat;
3480a70657fSMatt Jacob 	int				msicount;
34965adb54cSMatt Jacob };
35065adb54cSMatt Jacob 
35110365e5aSMatt Jacob 
352960f6939SMatt Jacob static device_method_t isp_pci_methods[] = {
353960f6939SMatt Jacob 	/* Device interface */
354960f6939SMatt Jacob 	DEVMETHOD(device_probe,		isp_pci_probe),
355960f6939SMatt Jacob 	DEVMETHOD(device_attach,	isp_pci_attach),
35610365e5aSMatt Jacob 	DEVMETHOD(device_detach,	isp_pci_detach),
357960f6939SMatt Jacob 	{ 0, 0 }
35865adb54cSMatt Jacob };
35965adb54cSMatt Jacob 
360960f6939SMatt Jacob static driver_t isp_pci_driver = {
361960f6939SMatt Jacob 	"isp", isp_pci_methods, sizeof (struct isp_pcisoftc)
362960f6939SMatt Jacob };
363960f6939SMatt Jacob static devclass_t isp_devclass;
364960f6939SMatt Jacob DRIVER_MODULE(isp, pci, isp_pci_driver, isp_devclass, 0, 0);
36565adb54cSMatt Jacob 
366960f6939SMatt Jacob static int
367960f6939SMatt Jacob isp_pci_probe(device_t dev)
36865adb54cSMatt Jacob {
369960f6939SMatt Jacob 	switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) {
37056aef503SMatt Jacob 	case PCI_QLOGIC_ISP1020:
371960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1020/1040 PCI SCSI Adapter");
37265adb54cSMatt Jacob 		break;
373d59bd469SMatt Jacob 	case PCI_QLOGIC_ISP1080:
374960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1080 PCI SCSI Adapter");
375c6608df3SMatt Jacob 		break;
376c6608df3SMatt Jacob 	case PCI_QLOGIC_ISP1240:
377960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1240 PCI SCSI Adapter");
378d59bd469SMatt Jacob 		break;
37922e1dc85SMatt Jacob 	case PCI_QLOGIC_ISP1280:
380960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1280 PCI SCSI Adapter");
381960f6939SMatt Jacob 		break;
382f556e83bSMatt Jacob 	case PCI_QLOGIC_ISP10160:
383f556e83bSMatt Jacob 		device_set_desc(dev, "Qlogic ISP 10160 PCI SCSI Adapter");
384f556e83bSMatt Jacob 		break;
385960f6939SMatt Jacob 	case PCI_QLOGIC_ISP12160:
386e11a1ee8SMatt Jacob 		if (pci_get_subvendor(dev) == AMI_RAID_SUBVENDOR_ID) {
387e11a1ee8SMatt Jacob 			return (ENXIO);
388e11a1ee8SMatt Jacob 		}
389960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 12160 PCI SCSI Adapter");
39022e1dc85SMatt Jacob 		break;
39165adb54cSMatt Jacob 	case PCI_QLOGIC_ISP2100:
392960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2100 PCI FC-AL Adapter");
39365adb54cSMatt Jacob 		break;
3945542fe4bSMatt Jacob 	case PCI_QLOGIC_ISP2200:
395960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2200 PCI FC-AL Adapter");
3965542fe4bSMatt Jacob 		break;
397126ec864SMatt Jacob 	case PCI_QLOGIC_ISP2300:
398126ec864SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2300 PCI FC-AL Adapter");
399126ec864SMatt Jacob 		break;
400126ec864SMatt Jacob 	case PCI_QLOGIC_ISP2312:
401126ec864SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2312 PCI FC-AL Adapter");
402126ec864SMatt Jacob 		break;
403e5265237SMatt Jacob 	case PCI_QLOGIC_ISP2322:
404e5265237SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2322 PCI FC-AL Adapter");
405e5265237SMatt Jacob 		break;
4068872e3d7SMatt Jacob 	case PCI_QLOGIC_ISP2422:
4078872e3d7SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2422 PCI FC-AL Adapter");
4088872e3d7SMatt Jacob 		break;
40941675df0SMatt Jacob 	case PCI_QLOGIC_ISP2432:
41041675df0SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2432 PCI FC-AL Adapter");
41141675df0SMatt Jacob 		break;
4122df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2532:
4132df76c16SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2532 PCI FC-AL Adapter");
4142df76c16SMatt Jacob 		break;
415dd1419abSMatt Jacob 	case PCI_QLOGIC_ISP6312:
416dd1419abSMatt Jacob 		device_set_desc(dev, "Qlogic ISP 6312 PCI FC-AL Adapter");
417dd1419abSMatt Jacob 		break;
4189a5af410SMatt Jacob 	case PCI_QLOGIC_ISP6322:
4199a5af410SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 6322 PCI FC-AL Adapter");
4209a5af410SMatt Jacob 		break;
42165adb54cSMatt Jacob 	default:
422960f6939SMatt Jacob 		return (ENXIO);
42365adb54cSMatt Jacob 	}
42473030e03SMatt Jacob 	if (isp_announced == 0 && bootverbose) {
425d02373f1SMatt Jacob 		printf("Qlogic ISP Driver, FreeBSD Version %d.%d, "
426a95ae193SMatt Jacob 		    "Core Version %d.%d\n",
427d720e6d5SJustin T. Gibbs 		    ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR,
428d720e6d5SJustin T. Gibbs 		    ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR);
42973030e03SMatt Jacob 		isp_announced++;
43065adb54cSMatt Jacob 	}
43156aef503SMatt Jacob 	/*
43256aef503SMatt Jacob 	 * XXXX: Here is where we might load the f/w module
43356aef503SMatt Jacob 	 * XXXX: (or increase a reference count to it).
43456aef503SMatt Jacob 	 */
435b77e575eSWarner Losh 	return (BUS_PROBE_DEFAULT);
43665adb54cSMatt Jacob }
43765adb54cSMatt Jacob 
4389cd7268eSMatt Jacob static void
4392df76c16SMatt Jacob isp_get_generic_options(device_t dev, ispsoftc_t *isp, int *nvp)
4409cd7268eSMatt Jacob {
4419cd7268eSMatt Jacob 	int tval;
442f7c631bcSMatt Jacob 
443222bb542SMatt Jacob 	/*
4449ba86737SMatt Jacob 	 * Figure out if we're supposed to skip this one.
4459ba86737SMatt Jacob 	 */
4466e5c5328SMatt Jacob 	tval = 0;
4472df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "disable", &tval) == 0 && tval) {
4489cd7268eSMatt Jacob 		device_printf(dev, "disabled at user request\n");
4499cd7268eSMatt Jacob 		isp->isp_osinfo.disabled = 1;
4509cd7268eSMatt Jacob 		return;
451b9b599feSMatt Jacob 	}
4526e5c5328SMatt Jacob 
4539cd7268eSMatt Jacob 	tval = 0;
4542df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "fwload_disable", &tval) == 0 && tval != 0) {
4559cd7268eSMatt Jacob 		isp->isp_confopts |= ISP_CFG_NORELOAD;
4569cd7268eSMatt Jacob 	}
4579cd7268eSMatt Jacob 	tval = 0;
4582df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "ignore_nvram", &tval) == 0 && tval != 0) {
4599cd7268eSMatt Jacob 		isp->isp_confopts |= ISP_CFG_NONVRAM;
4609cd7268eSMatt Jacob 	}
461336b5612SMatt Jacob 	tval = 0;
4622df76c16SMatt Jacob 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev), "debug", &tval);
463336b5612SMatt Jacob 	if (tval) {
464336b5612SMatt Jacob 		isp->isp_dblev = tval;
465336b5612SMatt Jacob 	} else {
466336b5612SMatt Jacob 		isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR;
467336b5612SMatt Jacob 	}
468336b5612SMatt Jacob 	if (bootverbose) {
469336b5612SMatt Jacob 		isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO;
470336b5612SMatt Jacob 	}
4712df76c16SMatt Jacob 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev), "vports", &tval);
4722df76c16SMatt Jacob 	if (tval > 0 && tval < 127) {
4732df76c16SMatt Jacob 		*nvp =  tval;
4742df76c16SMatt Jacob 	} else {
4752df76c16SMatt Jacob 		*nvp = 0;
4762df76c16SMatt Jacob 	}
4772df76c16SMatt Jacob 	tval = 1;
4782df76c16SMatt Jacob 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev), "autoconfig", &tval);
4792df76c16SMatt Jacob 	isp_autoconfig = tval;
4802df76c16SMatt Jacob 	tval = 7;
4812df76c16SMatt Jacob 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev), "quickboot_time", &tval);
4822df76c16SMatt Jacob 	isp_quickboot_time = tval;
483336b5612SMatt Jacob 
4842df76c16SMatt Jacob 	tval = 0;
4852df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "forcemulti", &tval) == 0 && tval != 0) {
4862df76c16SMatt Jacob 		isp->isp_osinfo.forcemulti = 1;
4872df76c16SMatt Jacob 	}
488336b5612SMatt Jacob }
489336b5612SMatt Jacob 
490336b5612SMatt Jacob static void
491336b5612SMatt Jacob isp_get_pci_options(device_t dev, int *m1, int *m2)
492336b5612SMatt Jacob {
493336b5612SMatt Jacob 	int tval;
494336b5612SMatt Jacob 	/*
495336b5612SMatt Jacob 	 * Which we should try first - memory mapping or i/o mapping?
496336b5612SMatt Jacob 	 *
497336b5612SMatt Jacob 	 * We used to try memory first followed by i/o on alpha, otherwise
498336b5612SMatt Jacob 	 * the reverse, but we should just try memory first all the time now.
499336b5612SMatt Jacob 	 */
500336b5612SMatt Jacob 	*m1 = PCIM_CMD_MEMEN;
501336b5612SMatt Jacob 	*m2 = PCIM_CMD_PORTEN;
502336b5612SMatt Jacob 
503336b5612SMatt Jacob 	tval = 0;
5042df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "prefer_iomap", &tval) == 0 && tval != 0) {
505336b5612SMatt Jacob 		*m1 = PCIM_CMD_PORTEN;
506336b5612SMatt Jacob 		*m2 = PCIM_CMD_MEMEN;
507336b5612SMatt Jacob 	}
508336b5612SMatt Jacob 	tval = 0;
5092df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "prefer_memmap", &tval) == 0 && tval != 0) {
510336b5612SMatt Jacob 		*m1 = PCIM_CMD_MEMEN;
511336b5612SMatt Jacob 		*m2 = PCIM_CMD_PORTEN;
512336b5612SMatt Jacob 	}
513336b5612SMatt Jacob }
514336b5612SMatt Jacob 
515336b5612SMatt Jacob static void
5162df76c16SMatt Jacob isp_get_specific_options(device_t dev, int chan, ispsoftc_t *isp)
517336b5612SMatt Jacob {
518336b5612SMatt Jacob 	const char *sptr;
519336b5612SMatt Jacob 	int tval;
520336b5612SMatt Jacob 
5212df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "iid", &tval)) {
5222df76c16SMatt Jacob 		if (IS_FC(isp)) {
5232df76c16SMatt Jacob 			ISP_FC_PC(isp, chan)->default_id = 109 - chan;
5242df76c16SMatt Jacob 		} else {
525*17bc427dSMarius Strobl #ifdef __sparc64__
526*17bc427dSMarius Strobl 			ISP_SPI_PC(isp, chan)->iid = OF_getscsinitid(dev);
527*17bc427dSMarius Strobl #else
5282df76c16SMatt Jacob 			ISP_SPI_PC(isp, chan)->iid = 7;
529*17bc427dSMarius Strobl #endif
5302df76c16SMatt Jacob 		}
5312df76c16SMatt Jacob 	} else {
5322df76c16SMatt Jacob 		if (IS_FC(isp)) {
5332df76c16SMatt Jacob 			ISP_FC_PC(isp, chan)->default_id = tval - chan;
5342df76c16SMatt Jacob 		} else {
5352df76c16SMatt Jacob 			ISP_SPI_PC(isp, chan)->iid = tval;
5362df76c16SMatt Jacob 		}
537336b5612SMatt Jacob 		isp->isp_confopts |= ISP_CFG_OWNLOOPID;
538336b5612SMatt Jacob 	}
5392df76c16SMatt Jacob 
5402df76c16SMatt Jacob 	tval = -1;
5412df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "role", &tval) == 0) {
5422df76c16SMatt Jacob 		switch (tval) {
5432df76c16SMatt Jacob 		case ISP_ROLE_NONE:
5442df76c16SMatt Jacob 		case ISP_ROLE_INITIATOR:
5452df76c16SMatt Jacob 		case ISP_ROLE_TARGET:
5462df76c16SMatt Jacob 		case ISP_ROLE_INITIATOR|ISP_ROLE_TARGET:
5472df76c16SMatt Jacob 			device_printf(dev, "setting role to 0x%x\n", tval);
5482df76c16SMatt Jacob 			break;
5492df76c16SMatt Jacob 		default:
5502df76c16SMatt Jacob 			tval = -1;
5512df76c16SMatt Jacob 			break;
552336b5612SMatt Jacob 		}
553336b5612SMatt Jacob 	}
5542df76c16SMatt Jacob 	if (tval == -1) {
5552df76c16SMatt Jacob 		tval = ISP_DEFAULT_ROLES;
5562df76c16SMatt Jacob 	}
557336b5612SMatt Jacob 
558336b5612SMatt Jacob 	if (IS_SCSI(isp)) {
5594ecb1d4aSMatt Jacob 		ISP_SPI_PC(isp, chan)->def_role = tval;
560336b5612SMatt Jacob 		return;
561336b5612SMatt Jacob 	}
5624ecb1d4aSMatt Jacob 	ISP_FC_PC(isp, chan)->def_role = tval;
563336b5612SMatt Jacob 
5649cd7268eSMatt Jacob 	tval = 0;
5652df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "fullduplex", &tval) == 0 && tval != 0) {
5669cd7268eSMatt Jacob 		isp->isp_confopts |= ISP_CFG_FULL_DUPLEX;
5679cd7268eSMatt Jacob 	}
5689cd7268eSMatt Jacob 	sptr = 0;
5692df76c16SMatt Jacob 	if (resource_string_value(device_get_name(dev), device_get_unit(dev), "topology", (const char **) &sptr) == 0 && sptr != 0) {
5709cd7268eSMatt Jacob 		if (strcmp(sptr, "lport") == 0) {
5719cd7268eSMatt Jacob 			isp->isp_confopts |= ISP_CFG_LPORT;
5729cd7268eSMatt Jacob 		} else if (strcmp(sptr, "nport") == 0) {
5739cd7268eSMatt Jacob 			isp->isp_confopts |= ISP_CFG_NPORT;
5749cd7268eSMatt Jacob 		} else if (strcmp(sptr, "lport-only") == 0) {
5759cd7268eSMatt Jacob 			isp->isp_confopts |= ISP_CFG_LPORT_ONLY;
5769cd7268eSMatt Jacob 		} else if (strcmp(sptr, "nport-only") == 0) {
5779cd7268eSMatt Jacob 			isp->isp_confopts |= ISP_CFG_NPORT_ONLY;
5789cd7268eSMatt Jacob 		}
579960f6939SMatt Jacob 	}
580960f6939SMatt Jacob 
5819ba86737SMatt Jacob 	/*
5829cd7268eSMatt Jacob 	 * Because the resource_*_value functions can neither return
5839cd7268eSMatt Jacob 	 * 64 bit integer values, nor can they be directly coerced
5849cd7268eSMatt Jacob 	 * to interpret the right hand side of the assignment as
5859cd7268eSMatt Jacob 	 * you want them to interpret it, we have to force WWN
5869cd7268eSMatt Jacob 	 * hint replacement to specify WWN strings with a leading
5879cd7268eSMatt Jacob 	 * 'w' (e..g w50000000aaaa0001). Sigh.
5889cd7268eSMatt Jacob 	 */
5899cd7268eSMatt Jacob 	sptr = 0;
5902df76c16SMatt Jacob 	tval = resource_string_value(device_get_name(dev), device_get_unit(dev), "portwwn", (const char **) &sptr);
5919cd7268eSMatt Jacob 	if (tval == 0 && sptr != 0 && *sptr++ == 'w') {
5929cd7268eSMatt Jacob 		char *eptr = 0;
5932df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->def_wwpn = strtouq(sptr, &eptr, 16);
5942df76c16SMatt Jacob 		if (eptr < sptr + 16 || ISP_FC_PC(isp, chan)->def_wwpn == -1) {
5959cd7268eSMatt Jacob 			device_printf(dev, "mangled portwwn hint '%s'\n", sptr);
5962df76c16SMatt Jacob 			ISP_FC_PC(isp, chan)->def_wwpn = 0;
5979cd7268eSMatt Jacob 		}
5989cd7268eSMatt Jacob 	}
5999cd7268eSMatt Jacob 
6009cd7268eSMatt Jacob 	sptr = 0;
6012df76c16SMatt Jacob 	tval = resource_string_value(device_get_name(dev), device_get_unit(dev), "nodewwn", (const char **) &sptr);
6029cd7268eSMatt Jacob 	if (tval == 0 && sptr != 0 && *sptr++ == 'w') {
6039cd7268eSMatt Jacob 		char *eptr = 0;
6042df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->def_wwnn = strtouq(sptr, &eptr, 16);
6052df76c16SMatt Jacob 		if (eptr < sptr + 16 || ISP_FC_PC(isp, chan)->def_wwnn == 0) {
6069cd7268eSMatt Jacob 			device_printf(dev, "mangled nodewwn hint '%s'\n", sptr);
6072df76c16SMatt Jacob 			ISP_FC_PC(isp, chan)->def_wwnn = 0;
6089cd7268eSMatt Jacob 		}
6099cd7268eSMatt Jacob 	}
6109cd7268eSMatt Jacob 
61110365e5aSMatt Jacob 	tval = 0;
6122df76c16SMatt Jacob 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev), "hysteresis", &tval);
61310365e5aSMatt Jacob 	if (tval >= 0 && tval < 256) {
6142df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->hysteresis = tval;
61510365e5aSMatt Jacob 	} else {
6162df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->hysteresis = isp_fabric_hysteresis;
61710365e5aSMatt Jacob 	}
61810365e5aSMatt Jacob 
619f7c631bcSMatt Jacob 	tval = -1;
6202df76c16SMatt Jacob 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev), "loop_down_limit", &tval);
62110365e5aSMatt Jacob 	if (tval >= 0 && tval < 0xffff) {
6222df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->loop_down_limit = tval;
62310365e5aSMatt Jacob 	} else {
6242df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->loop_down_limit = isp_loop_down_limit;
62510365e5aSMatt Jacob 	}
62610365e5aSMatt Jacob 
627f7c631bcSMatt Jacob 	tval = -1;
6282df76c16SMatt Jacob 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev), "gone_device_time", &tval);
629f7c631bcSMatt Jacob 	if (tval >= 0 && tval < 0xffff) {
6302df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->gone_device_time = tval;
631f7c631bcSMatt Jacob 	} else {
6322df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->gone_device_time = isp_gone_device_time;
633f7c631bcSMatt Jacob 	}
6349cd7268eSMatt Jacob }
6359cd7268eSMatt Jacob 
6369cd7268eSMatt Jacob static int
6379cd7268eSMatt Jacob isp_pci_attach(device_t dev)
6389cd7268eSMatt Jacob {
6399cd7268eSMatt Jacob 	struct resource *regs, *irq;
6402df76c16SMatt Jacob 	int rtp, rgd, iqd, i, m1, m2, locksetup = 0;
6412df76c16SMatt Jacob 	int isp_nvports = 0;
6422df76c16SMatt Jacob 	uint32_t data, cmd, linesz, did;
6439cd7268eSMatt Jacob 	struct isp_pcisoftc *pcs;
6449cd7268eSMatt Jacob 	ispsoftc_t *isp = NULL;
6452df76c16SMatt Jacob 	size_t psize, xsize;
6462df76c16SMatt Jacob 	char fwname[32];
6479cd7268eSMatt Jacob 
6489cd7268eSMatt Jacob 	pcs = device_get_softc(dev);
6499cd7268eSMatt Jacob 	if (pcs == NULL) {
6509cd7268eSMatt Jacob 		device_printf(dev, "cannot get softc\n");
6519cd7268eSMatt Jacob 		return (ENOMEM);
6529cd7268eSMatt Jacob 	}
6539cd7268eSMatt Jacob 	memset(pcs, 0, sizeof (*pcs));
6542df76c16SMatt Jacob 
6559cd7268eSMatt Jacob 	pcs->pci_dev = dev;
6569cd7268eSMatt Jacob 	isp = &pcs->pci_isp;
6572df76c16SMatt Jacob 	isp->isp_dev = dev;
6582df76c16SMatt Jacob 	isp->isp_nchan = 1;
6599cd7268eSMatt Jacob 
6609cd7268eSMatt Jacob 	/*
661336b5612SMatt Jacob 	 * Get Generic Options
6629cd7268eSMatt Jacob 	 */
6632df76c16SMatt Jacob 	isp_get_generic_options(dev, isp, &isp_nvports);
6649cd7268eSMatt Jacob 
6659cd7268eSMatt Jacob 	/*
6669cd7268eSMatt Jacob 	 * Check to see if options have us disabled
6679cd7268eSMatt Jacob 	 */
6689cd7268eSMatt Jacob 	if (isp->isp_osinfo.disabled) {
6699cd7268eSMatt Jacob 		/*
6709cd7268eSMatt Jacob 		 * But return zero to preserve unit numbering
6719cd7268eSMatt Jacob 		 */
6729cd7268eSMatt Jacob 		return (0);
6739cd7268eSMatt Jacob 	}
6749cd7268eSMatt Jacob 
6759cd7268eSMatt Jacob 	/*
6769cd7268eSMatt Jacob 	 * Get PCI options- which in this case are just mapping preferences.
6779cd7268eSMatt Jacob 	 */
6789cd7268eSMatt Jacob 	isp_get_pci_options(dev, &m1, &m2);
6799cd7268eSMatt Jacob 
680ab6d0040SMatt Jacob 	linesz = PCI_DFLT_LNSZ;
681960f6939SMatt Jacob 	irq = regs = NULL;
682960f6939SMatt Jacob 	rgd = rtp = iqd = 0;
683960f6939SMatt Jacob 
684b49c4674SMatt Jacob 	cmd = pci_read_config(dev, PCIR_COMMAND, 2);
685960f6939SMatt Jacob 	if (cmd & m1) {
686960f6939SMatt Jacob 		rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT;
687960f6939SMatt Jacob 		rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG;
6885f96beb9SNate Lawson 		regs = bus_alloc_resource_any(dev, rtp, &rgd, RF_ACTIVE);
68965adb54cSMatt Jacob 	}
690960f6939SMatt Jacob 	if (regs == NULL && (cmd & m2)) {
691960f6939SMatt Jacob 		rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT;
692960f6939SMatt Jacob 		rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG;
6935f96beb9SNate Lawson 		regs = bus_alloc_resource_any(dev, rtp, &rgd, RF_ACTIVE);
69465adb54cSMatt Jacob 	}
695960f6939SMatt Jacob 	if (regs == NULL) {
696960f6939SMatt Jacob 		device_printf(dev, "unable to map any ports\n");
697960f6939SMatt Jacob 		goto bad;
69865adb54cSMatt Jacob 	}
6999cd7268eSMatt Jacob 	if (bootverbose) {
7002df76c16SMatt Jacob 		device_printf(dev, "using %s space register mapping\n", (rgd == IO_MAP_REG)? "I/O" : "Memory");
7019cd7268eSMatt Jacob 	}
7026a7d12e1SMatt Jacob 	isp->isp_bus_tag = rman_get_bustag(regs);
7036a7d12e1SMatt Jacob 	isp->isp_bus_handle = rman_get_bushandle(regs);
70465adb54cSMatt Jacob 
7052df76c16SMatt Jacob 	pcs->pci_dev = dev;
7062df76c16SMatt Jacob 	pcs->pci_reg = regs;
707d59bd469SMatt Jacob 	pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF;
708d59bd469SMatt Jacob 	pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF;
709d59bd469SMatt Jacob 	pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF;
710d59bd469SMatt Jacob 	pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF;
711d59bd469SMatt Jacob 	pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF;
7122df76c16SMatt Jacob 
7132df76c16SMatt Jacob 	switch (pci_get_devid(dev)) {
7142df76c16SMatt Jacob 	case PCI_QLOGIC_ISP1020:
7152df76c16SMatt Jacob 		did = 0x1040;
7162df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec;
7172df76c16SMatt Jacob 		isp->isp_type = ISP_HA_SCSI_UNKNOWN;
7182df76c16SMatt Jacob 		break;
7192df76c16SMatt Jacob 	case PCI_QLOGIC_ISP1080:
7202df76c16SMatt Jacob 		did = 0x1080;
7212df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_1080;
7222df76c16SMatt Jacob 		isp->isp_type = ISP_HA_SCSI_1080;
7232df76c16SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = ISP1080_DMA_REGS_OFF;
7242df76c16SMatt Jacob 		break;
7252df76c16SMatt Jacob 	case PCI_QLOGIC_ISP1240:
7262df76c16SMatt Jacob 		did = 0x1080;
7272df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_1080;
7282df76c16SMatt Jacob 		isp->isp_type = ISP_HA_SCSI_1240;
7292df76c16SMatt Jacob 		isp->isp_nchan = 2;
7302df76c16SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = ISP1080_DMA_REGS_OFF;
7312df76c16SMatt Jacob 		break;
7322df76c16SMatt Jacob 	case PCI_QLOGIC_ISP1280:
7332df76c16SMatt Jacob 		did = 0x1080;
7342df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_1080;
7352df76c16SMatt Jacob 		isp->isp_type = ISP_HA_SCSI_1280;
7362df76c16SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = ISP1080_DMA_REGS_OFF;
7372df76c16SMatt Jacob 		break;
7382df76c16SMatt Jacob 	case PCI_QLOGIC_ISP10160:
7392df76c16SMatt Jacob 		did = 0x12160;
7402df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_12160;
7412df76c16SMatt Jacob 		isp->isp_type = ISP_HA_SCSI_10160;
7422df76c16SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = ISP1080_DMA_REGS_OFF;
7432df76c16SMatt Jacob 		break;
7442df76c16SMatt Jacob 	case PCI_QLOGIC_ISP12160:
7452df76c16SMatt Jacob 		did = 0x12160;
7462df76c16SMatt Jacob 		isp->isp_nchan = 2;
7472df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_12160;
7482df76c16SMatt Jacob 		isp->isp_type = ISP_HA_SCSI_12160;
7492df76c16SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = ISP1080_DMA_REGS_OFF;
7502df76c16SMatt Jacob 		break;
7512df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2100:
7522df76c16SMatt Jacob 		did = 0x2100;
7532df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_2100;
7542df76c16SMatt Jacob 		isp->isp_type = ISP_HA_FC_2100;
7552df76c16SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2100_OFF;
756960f6939SMatt Jacob 		if (pci_get_revid(dev) < 3) {
757ab6d0040SMatt Jacob 			/*
758ab6d0040SMatt Jacob 			 * XXX: Need to get the actual revision
759ab6d0040SMatt Jacob 			 * XXX: number of the 2100 FB. At any rate,
760ab6d0040SMatt Jacob 			 * XXX: lower cache line size for early revision
761ab6d0040SMatt Jacob 			 * XXX; boards.
762ab6d0040SMatt Jacob 			 */
763ab6d0040SMatt Jacob 			linesz = 1;
764ab6d0040SMatt Jacob 		}
7652df76c16SMatt Jacob 		break;
7662df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2200:
7672df76c16SMatt Jacob 		did = 0x2200;
7682df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_2200;
7692df76c16SMatt Jacob 		isp->isp_type = ISP_HA_FC_2200;
7702df76c16SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2100_OFF;
7712df76c16SMatt Jacob 		break;
7722df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2300:
7732df76c16SMatt Jacob 		did = 0x2300;
7742df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_2300;
7752df76c16SMatt Jacob 		isp->isp_type = ISP_HA_FC_2300;
7762df76c16SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2300_OFF;
7772df76c16SMatt Jacob 		break;
7782df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2312:
7792df76c16SMatt Jacob 	case PCI_QLOGIC_ISP6312:
7802df76c16SMatt Jacob 		did = 0x2300;
7812df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_2300;
7822df76c16SMatt Jacob 		isp->isp_type = ISP_HA_FC_2312;
7832df76c16SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2300_OFF;
7842df76c16SMatt Jacob 		break;
7852df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2322:
7862df76c16SMatt Jacob 	case PCI_QLOGIC_ISP6322:
7872df76c16SMatt Jacob 		did = 0x2322;
7882df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_2300;
7892df76c16SMatt Jacob 		isp->isp_type = ISP_HA_FC_2322;
7902df76c16SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2300_OFF;
7912df76c16SMatt Jacob 		break;
7922df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2422:
7932df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2432:
7942df76c16SMatt Jacob 		did = 0x2400;
7952df76c16SMatt Jacob 		isp->isp_nchan += isp_nvports;
7962df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_2400;
7972df76c16SMatt Jacob 		isp->isp_type = ISP_HA_FC_2400;
7982df76c16SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2400_OFF;
7992df76c16SMatt Jacob 		break;
8002df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2532:
8012df76c16SMatt Jacob 		did = 0x2500;
8022df76c16SMatt Jacob 		isp->isp_nchan += isp_nvports;
8032df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_2500;
8042df76c16SMatt Jacob 		isp->isp_type = ISP_HA_FC_2500;
8052df76c16SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2400_OFF;
8062df76c16SMatt Jacob 		break;
8072df76c16SMatt Jacob 	default:
8082df76c16SMatt Jacob 		device_printf(dev, "unknown device type\n");
8092df76c16SMatt Jacob 		goto bad;
8102df76c16SMatt Jacob 		break;
81165adb54cSMatt Jacob 	}
8122df76c16SMatt Jacob 	isp->isp_revision = pci_get_revid(dev);
8132df76c16SMatt Jacob 
8142df76c16SMatt Jacob 	if (IS_FC(isp)) {
815222bb542SMatt Jacob 		psize = sizeof (fcparam);
8162df76c16SMatt Jacob 		xsize = sizeof (struct isp_fc);
8172df76c16SMatt Jacob 	} else {
8182df76c16SMatt Jacob 		psize = sizeof (sdparam);
8192df76c16SMatt Jacob 		xsize = sizeof (struct isp_spi);
820222bb542SMatt Jacob 	}
8212df76c16SMatt Jacob 	psize *= isp->isp_nchan;
8222df76c16SMatt Jacob 	xsize *= isp->isp_nchan;
8237cc0979fSDavid Malone 	isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT | M_ZERO);
824c6608df3SMatt Jacob 	if (isp->isp_param == NULL) {
825960f6939SMatt Jacob 		device_printf(dev, "cannot allocate parameter data\n");
826960f6939SMatt Jacob 		goto bad;
827c6608df3SMatt Jacob 	}
8282df76c16SMatt Jacob 	isp->isp_osinfo.pc.ptr = malloc(xsize, M_DEVBUF, M_NOWAIT | M_ZERO);
8292df76c16SMatt Jacob 	if (isp->isp_osinfo.pc.ptr == NULL) {
8302df76c16SMatt Jacob 		device_printf(dev, "cannot allocate parameter data\n");
8312df76c16SMatt Jacob 		goto bad;
8322df76c16SMatt Jacob 	}
83365adb54cSMatt Jacob 
834336b5612SMatt Jacob 	/*
835336b5612SMatt Jacob 	 * Now that we know who we are (roughly) get/set specific options
836336b5612SMatt Jacob 	 */
8372df76c16SMatt Jacob 	for (i = 0; i < isp->isp_nchan; i++) {
8382df76c16SMatt Jacob 		isp_get_specific_options(dev, i, isp);
8399a5af410SMatt Jacob 	}
8409a5af410SMatt Jacob 
8412df76c16SMatt Jacob 	/*
8422df76c16SMatt Jacob 	 * The 'it' suffix really only matters for SCSI cards in target mode.
8432df76c16SMatt Jacob 	 */
8449a5af410SMatt Jacob 	isp->isp_osinfo.fw = NULL;
8454ecb1d4aSMatt Jacob 	if (IS_SCSI(isp) && (ISP_SPI_PC(isp, 0)->def_role & ISP_ROLE_TARGET)) {
8469a5af410SMatt Jacob 		snprintf(fwname, sizeof (fwname), "isp_%04x_it", did);
8479a5af410SMatt Jacob 		isp->isp_osinfo.fw = firmware_get(fwname);
8482df76c16SMatt Jacob 	} else if (IS_24XX(isp) && (isp->isp_nchan > 1 || isp->isp_osinfo.forcemulti)) {
8492df76c16SMatt Jacob 		snprintf(fwname, sizeof (fwname), "isp_%04x_multi", did);
8502df76c16SMatt Jacob 		isp->isp_osinfo.fw = firmware_get(fwname);
8519a5af410SMatt Jacob 	}
8529a5af410SMatt Jacob 	if (isp->isp_osinfo.fw == NULL) {
8539a5af410SMatt Jacob 		snprintf(fwname, sizeof (fwname), "isp_%04x", did);
8549a5af410SMatt Jacob 		isp->isp_osinfo.fw = firmware_get(fwname);
8559a5af410SMatt Jacob 	}
8569a5af410SMatt Jacob 	if (isp->isp_osinfo.fw != NULL) {
8575f634111SMatt Jacob 		isp->isp_mdvec->dv_ispfw = isp->isp_osinfo.fw->data;
8589a5af410SMatt Jacob 	}
85956aef503SMatt Jacob 
86056aef503SMatt Jacob 	/*
861d951bbcaSMatt Jacob 	 * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER
862d951bbcaSMatt Jacob 	 * are set.
863d951bbcaSMatt Jacob 	 */
864960f6939SMatt Jacob 	cmd |= PCIM_CMD_SEREN | PCIM_CMD_PERRESPEN |
865960f6939SMatt Jacob 		PCIM_CMD_BUSMASTEREN | PCIM_CMD_INVEN;
8669a5af410SMatt Jacob 
86775c1e828SMatt Jacob 	if (IS_2300(isp)) {	/* per QLogic errata */
86875c1e828SMatt Jacob 		cmd &= ~PCIM_CMD_INVEN;
86975c1e828SMatt Jacob 	}
8709a5af410SMatt Jacob 
8718a97c03aSMatt Jacob 	if (IS_2322(isp) || pci_get_devid(dev) == PCI_QLOGIC_ISP6312) {
8728a97c03aSMatt Jacob 		cmd &= ~PCIM_CMD_INTX_DISABLE;
8738a97c03aSMatt Jacob 	}
8748a97c03aSMatt Jacob 
87506cacb29SMatt Jacob 	if (IS_24XX(isp)) {
87606cacb29SMatt Jacob 		cmd &= ~PCIM_CMD_INTX_DISABLE;
87706cacb29SMatt Jacob 	}
87810365e5aSMatt Jacob 
879b49c4674SMatt Jacob 	pci_write_config(dev, PCIR_COMMAND, cmd, 2);
880ab6d0040SMatt Jacob 
881d951bbcaSMatt Jacob 	/*
882222bb542SMatt Jacob 	 * Make sure the Cache Line Size register is set sensibly.
883d951bbcaSMatt Jacob 	 */
884960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_CACHELNSZ, 1);
8856a7d12e1SMatt Jacob 	if (data == 0 || (linesz != PCI_DFLT_LNSZ && data != linesz)) {
8862df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, "set PCI line size to %d from %d", linesz, data);
8876a7d12e1SMatt Jacob 		data = linesz;
888960f6939SMatt Jacob 		pci_write_config(dev, PCIR_CACHELNSZ, data, 1);
889d951bbcaSMatt Jacob 	}
890ab6d0040SMatt Jacob 
891d951bbcaSMatt Jacob 	/*
892d951bbcaSMatt Jacob 	 * Make sure the Latency Timer is sane.
893d951bbcaSMatt Jacob 	 */
894960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_LATTIMER, 1);
895d951bbcaSMatt Jacob 	if (data < PCI_DFLT_LTNCY) {
896d951bbcaSMatt Jacob 		data = PCI_DFLT_LTNCY;
897d02373f1SMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, "set PCI latency to %d", data);
898960f6939SMatt Jacob 		pci_write_config(dev, PCIR_LATTIMER, data, 1);
899d951bbcaSMatt Jacob 	}
900ab6d0040SMatt Jacob 
901ab6d0040SMatt Jacob 	/*
902ab6d0040SMatt Jacob 	 * Make sure we've disabled the ROM.
903ab6d0040SMatt Jacob 	 */
904960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_ROMADDR, 4);
905ab6d0040SMatt Jacob 	data &= ~1;
906960f6939SMatt Jacob 	pci_write_config(dev, PCIR_ROMADDR, data, 4);
9072df76c16SMatt Jacob 
9082df76c16SMatt Jacob 	/*
9092df76c16SMatt Jacob 	 * Do MSI
9102df76c16SMatt Jacob 	 *
9112df76c16SMatt Jacob 	 * NB: MSI-X needs to be disabled for the 2432 (PCI-Express)
9122df76c16SMatt Jacob 	 */
9130a70657fSMatt Jacob 	if (IS_24XX(isp) || IS_2322(isp)) {
9140a70657fSMatt Jacob 		pcs->msicount = pci_msi_count(dev);
9150a70657fSMatt Jacob 		if (pcs->msicount > 1) {
9160a70657fSMatt Jacob 			pcs->msicount = 1;
9170a70657fSMatt Jacob 		}
9180a70657fSMatt Jacob 		if (pci_alloc_msi(dev, &pcs->msicount) == 0) {
9190a70657fSMatt Jacob 			iqd = 1;
9200a70657fSMatt Jacob 		} else {
921960f6939SMatt Jacob 			iqd = 0;
9220a70657fSMatt Jacob 		}
9230a70657fSMatt Jacob 	}
9242df76c16SMatt Jacob 	irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &iqd, RF_ACTIVE | RF_SHAREABLE);
925960f6939SMatt Jacob 	if (irq == NULL) {
926960f6939SMatt Jacob 		device_printf(dev, "could not allocate interrupt\n");
927960f6939SMatt Jacob 		goto bad;
928960f6939SMatt Jacob 	}
929960f6939SMatt Jacob 
930f09b1922SMatt Jacob 	/* Make sure the lock is set up. */
9316008862bSJohn Baldwin 	mtx_init(&isp->isp_osinfo.lock, "isp", NULL, MTX_DEF);
932f09b1922SMatt Jacob 	locksetup++;
933f09b1922SMatt Jacob 
9342df76c16SMatt Jacob 	if (isp_setup_intr(dev, irq, ISP_IFLAGS, NULL, isp_platform_intr, isp, &pcs->ih)) {
935f09b1922SMatt Jacob 		device_printf(dev, "could not setup interrupt\n");
936f09b1922SMatt Jacob 		goto bad;
937f09b1922SMatt Jacob 	}
938960f6939SMatt Jacob 
93905fbcbb0SMatt Jacob 	/*
94075c1e828SMatt Jacob 	 * Last minute checks...
94175c1e828SMatt Jacob 	 */
94210365e5aSMatt Jacob 	if (IS_23XX(isp) || IS_24XX(isp)) {
94375c1e828SMatt Jacob 		isp->isp_port = pci_get_function(dev);
94475c1e828SMatt Jacob 	}
94575c1e828SMatt Jacob 
94675c1e828SMatt Jacob 	/*
94705fbcbb0SMatt Jacob 	 * Make sure we're in reset state.
94805fbcbb0SMatt Jacob 	 */
9493395b056SMatt Jacob 	ISP_LOCK(isp);
9502df76c16SMatt Jacob 	isp_reset(isp, 1);
95165adb54cSMatt Jacob 	if (isp->isp_state != ISP_RESETSTATE) {
9523395b056SMatt Jacob 		ISP_UNLOCK(isp);
953960f6939SMatt Jacob 		goto bad;
95465adb54cSMatt Jacob 	}
95565adb54cSMatt Jacob 	isp_init(isp);
9562df76c16SMatt Jacob 	if (isp->isp_state == ISP_INITSTATE) {
9572df76c16SMatt Jacob 		isp->isp_state = ISP_RUNSTATE;
9582df76c16SMatt Jacob 	}
9592df76c16SMatt Jacob 	ISP_UNLOCK(isp);
9602df76c16SMatt Jacob 	if (isp_attach(isp)) {
9612df76c16SMatt Jacob 		ISP_LOCK(isp);
96265adb54cSMatt Jacob 		isp_uninit(isp);
9633395b056SMatt Jacob 		ISP_UNLOCK(isp);
964960f6939SMatt Jacob 		goto bad;
965d59bd469SMatt Jacob 	}
966960f6939SMatt Jacob 	return (0);
967960f6939SMatt Jacob 
968960f6939SMatt Jacob bad:
969960f6939SMatt Jacob 	if (pcs && pcs->ih) {
970960f6939SMatt Jacob 		(void) bus_teardown_intr(dev, irq, pcs->ih);
971960f6939SMatt Jacob 	}
9723395b056SMatt Jacob 	if (locksetup && isp) {
9733395b056SMatt Jacob 		mtx_destroy(&isp->isp_osinfo.lock);
9743395b056SMatt Jacob 	}
975960f6939SMatt Jacob 	if (irq) {
976960f6939SMatt Jacob 		(void) bus_release_resource(dev, SYS_RES_IRQ, iqd, irq);
977960f6939SMatt Jacob 	}
9780a70657fSMatt Jacob 	if (pcs && pcs->msicount) {
9790a70657fSMatt Jacob 		pci_release_msi(dev);
9800a70657fSMatt Jacob 	}
981960f6939SMatt Jacob 	if (regs) {
982960f6939SMatt Jacob 		(void) bus_release_resource(dev, rtp, rgd, regs);
983960f6939SMatt Jacob 	}
984960f6939SMatt Jacob 	if (pcs) {
9859cd7268eSMatt Jacob 		if (pcs->pci_isp.isp_param) {
986960f6939SMatt Jacob 			free(pcs->pci_isp.isp_param, M_DEVBUF);
9872df76c16SMatt Jacob 			pcs->pci_isp.isp_param = NULL;
9882df76c16SMatt Jacob 		}
9892df76c16SMatt Jacob 		if (pcs->pci_isp.isp_osinfo.pc.ptr) {
9902df76c16SMatt Jacob 			free(pcs->pci_isp.isp_osinfo.pc.ptr, M_DEVBUF);
9912df76c16SMatt Jacob 			pcs->pci_isp.isp_osinfo.pc.ptr = NULL;
9929cd7268eSMatt Jacob 		}
99365adb54cSMatt Jacob 	}
994960f6939SMatt Jacob 	return (ENXIO);
99565adb54cSMatt Jacob }
99665adb54cSMatt Jacob 
99710365e5aSMatt Jacob static int
99810365e5aSMatt Jacob isp_pci_detach(device_t dev)
99910365e5aSMatt Jacob {
100010365e5aSMatt Jacob 	struct isp_pcisoftc *pcs;
100110365e5aSMatt Jacob 	ispsoftc_t *isp;
100210365e5aSMatt Jacob 
100310365e5aSMatt Jacob 	pcs = device_get_softc(dev);
100410365e5aSMatt Jacob 	if (pcs == NULL) {
100510365e5aSMatt Jacob 		return (ENXIO);
100610365e5aSMatt Jacob 	}
100710365e5aSMatt Jacob 	isp = (ispsoftc_t *) pcs;
100810365e5aSMatt Jacob 	ISP_DISABLE_INTS(isp);
10092df76c16SMatt Jacob 	mtx_destroy(&isp->isp_osinfo.lock);
101010365e5aSMatt Jacob 	return (0);
101110365e5aSMatt Jacob }
101210365e5aSMatt Jacob 
1013126ec864SMatt Jacob #define	IspVirt2Off(a, x)	\
1014126ec864SMatt Jacob 	(((struct isp_pcisoftc *)a)->pci_poff[((x) & _BLK_REG_MASK) >> \
10154cc9e3e7SMatt Jacob 	_BLK_REG_SHFT] + ((x) & 0xfff))
1016126ec864SMatt Jacob 
10176a7d12e1SMatt Jacob #define	BXR2(isp, off)		\
10186a7d12e1SMatt Jacob 	bus_space_read_2(isp->isp_bus_tag, isp->isp_bus_handle, off)
10196a7d12e1SMatt Jacob #define	BXW2(isp, off, v)	\
10206a7d12e1SMatt Jacob 	bus_space_write_2(isp->isp_bus_tag, isp->isp_bus_handle, off, v)
10216a7d12e1SMatt Jacob #define	BXR4(isp, off)		\
10226a7d12e1SMatt Jacob 	bus_space_read_4(isp->isp_bus_tag, isp->isp_bus_handle, off)
10236a7d12e1SMatt Jacob #define	BXW4(isp, off, v)	\
10246a7d12e1SMatt Jacob 	bus_space_write_4(isp->isp_bus_tag, isp->isp_bus_handle, off, v)
1025126ec864SMatt Jacob 
1026126ec864SMatt Jacob 
10272df76c16SMatt Jacob static ISP_INLINE int
10289cd7268eSMatt Jacob isp_pci_rd_debounced(ispsoftc_t *isp, int off, uint16_t *rp)
1029126ec864SMatt Jacob {
103010365e5aSMatt Jacob 	uint32_t val0, val1;
1031126ec864SMatt Jacob 	int i = 0;
1032126ec864SMatt Jacob 
1033126ec864SMatt Jacob 	do {
10346a7d12e1SMatt Jacob 		val0 = BXR2(isp, IspVirt2Off(isp, off));
10356a7d12e1SMatt Jacob 		val1 = BXR2(isp, IspVirt2Off(isp, off));
1036126ec864SMatt Jacob 	} while (val0 != val1 && ++i < 1000);
1037126ec864SMatt Jacob 	if (val0 != val1) {
1038126ec864SMatt Jacob 		return (1);
1039126ec864SMatt Jacob 	}
1040126ec864SMatt Jacob 	*rp = val0;
1041126ec864SMatt Jacob 	return (0);
1042126ec864SMatt Jacob }
1043126ec864SMatt Jacob 
1044126ec864SMatt Jacob static int
10450a70657fSMatt Jacob isp_pci_rd_isr(ispsoftc_t *isp, uint32_t *isrp, uint16_t *semap, uint16_t *mbp)
1046126ec864SMatt Jacob {
10471dae40ebSMatt Jacob 	uint16_t isr, sema;
1048126ec864SMatt Jacob 
1049126ec864SMatt Jacob 	if (IS_2100(isp)) {
1050126ec864SMatt Jacob 		if (isp_pci_rd_debounced(isp, BIU_ISR, &isr)) {
1051126ec864SMatt Jacob 		    return (0);
1052126ec864SMatt Jacob 		}
1053126ec864SMatt Jacob 		if (isp_pci_rd_debounced(isp, BIU_SEMA, &sema)) {
1054126ec864SMatt Jacob 		    return (0);
1055126ec864SMatt Jacob 		}
1056126ec864SMatt Jacob 	} else {
10576a7d12e1SMatt Jacob 		isr = BXR2(isp, IspVirt2Off(isp, BIU_ISR));
10586a7d12e1SMatt Jacob 		sema = BXR2(isp, IspVirt2Off(isp, BIU_SEMA));
1059126ec864SMatt Jacob 	}
1060126ec864SMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG3, "ISR 0x%x SEMA 0x%x", isr, sema);
1061126ec864SMatt Jacob 	isr &= INT_PENDING_MASK(isp);
1062126ec864SMatt Jacob 	sema &= BIU_SEMA_LOCK;
1063126ec864SMatt Jacob 	if (isr == 0 && sema == 0) {
1064126ec864SMatt Jacob 		return (0);
1065126ec864SMatt Jacob 	}
1066126ec864SMatt Jacob 	*isrp = isr;
1067126ec864SMatt Jacob 	if ((*semap = sema) != 0) {
1068126ec864SMatt Jacob 		if (IS_2100(isp)) {
1069126ec864SMatt Jacob 			if (isp_pci_rd_debounced(isp, OUTMAILBOX0, mbp)) {
1070126ec864SMatt Jacob 				return (0);
1071126ec864SMatt Jacob 			}
1072126ec864SMatt Jacob 		} else {
10736a7d12e1SMatt Jacob 			*mbp = BXR2(isp, IspVirt2Off(isp, OUTMAILBOX0));
1074126ec864SMatt Jacob 		}
1075126ec864SMatt Jacob 	}
1076126ec864SMatt Jacob 	return (1);
1077126ec864SMatt Jacob }
1078126ec864SMatt Jacob 
1079126ec864SMatt Jacob static int
1080443e752dSMatt Jacob isp_pci_rd_isr_2300(ispsoftc_t *isp, uint32_t *isrp, uint16_t *semap, uint16_t *mbox0p)
1081126ec864SMatt Jacob {
108210365e5aSMatt Jacob 	uint32_t hccr;
10831dae40ebSMatt Jacob 	uint32_t r2hisr;
1084126ec864SMatt Jacob 
10856a7d12e1SMatt Jacob 	if (!(BXR2(isp, IspVirt2Off(isp, BIU_ISR) & BIU2100_ISR_RISC_INT))) {
10863bd40330SMatt Jacob 		*isrp = 0;
1087db4fa023SMatt Jacob 		return (0);
10883bd40330SMatt Jacob 	}
10896a7d12e1SMatt Jacob 	r2hisr = BXR4(isp, IspVirt2Off(isp, BIU_R2HSTSLO));
1090126ec864SMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG3, "RISC2HOST ISR 0x%x", r2hisr);
1091126ec864SMatt Jacob 	if ((r2hisr & BIU_R2HST_INTR) == 0) {
1092126ec864SMatt Jacob 		*isrp = 0;
1093126ec864SMatt Jacob 		return (0);
1094126ec864SMatt Jacob 	}
1095126ec864SMatt Jacob 	switch (r2hisr & BIU_R2HST_ISTAT_MASK) {
1096126ec864SMatt Jacob 	case ISPR2HST_ROM_MBX_OK:
1097126ec864SMatt Jacob 	case ISPR2HST_ROM_MBX_FAIL:
1098126ec864SMatt Jacob 	case ISPR2HST_MBX_OK:
1099126ec864SMatt Jacob 	case ISPR2HST_MBX_FAIL:
1100126ec864SMatt Jacob 	case ISPR2HST_ASYNC_EVENT:
1101126ec864SMatt Jacob 		*isrp = r2hisr & 0xffff;
1102126ec864SMatt Jacob 		*mbox0p = (r2hisr >> 16);
1103126ec864SMatt Jacob 		*semap = 1;
1104126ec864SMatt Jacob 		return (1);
1105fc3bbaaaSMatt Jacob 	case ISPR2HST_RIO_16:
1106fc3bbaaaSMatt Jacob 		*isrp = r2hisr & 0xffff;
1107443e752dSMatt Jacob 		*mbox0p = ASYNC_RIO16_1;
1108fc3bbaaaSMatt Jacob 		*semap = 1;
1109fc3bbaaaSMatt Jacob 		return (1);
1110fc3bbaaaSMatt Jacob 	case ISPR2HST_FPOST:
1111fc3bbaaaSMatt Jacob 		*isrp = r2hisr & 0xffff;
1112fc3bbaaaSMatt Jacob 		*mbox0p = ASYNC_CMD_CMPLT;
1113fc3bbaaaSMatt Jacob 		*semap = 1;
1114fc3bbaaaSMatt Jacob 		return (1);
1115fc3bbaaaSMatt Jacob 	case ISPR2HST_FPOST_CTIO:
1116fc3bbaaaSMatt Jacob 		*isrp = r2hisr & 0xffff;
1117fc3bbaaaSMatt Jacob 		*mbox0p = ASYNC_CTIO_DONE;
1118fc3bbaaaSMatt Jacob 		*semap = 1;
1119fc3bbaaaSMatt Jacob 		return (1);
1120126ec864SMatt Jacob 	case ISPR2HST_RSPQ_UPDATE:
1121126ec864SMatt Jacob 		*isrp = r2hisr & 0xffff;
1122126ec864SMatt Jacob 		*mbox0p = 0;
1123126ec864SMatt Jacob 		*semap = 0;
1124126ec864SMatt Jacob 		return (1);
1125126ec864SMatt Jacob 	default:
11268a97c03aSMatt Jacob 		hccr = ISP_READ(isp, HCCR);
11278a97c03aSMatt Jacob 		if (hccr & HCCR_PAUSE) {
11288a97c03aSMatt Jacob 			ISP_WRITE(isp, HCCR, HCCR_RESET);
1129443e752dSMatt Jacob 			isp_prt(isp, ISP_LOGERR, "RISC paused at interrupt (%x->%x)", hccr, ISP_READ(isp, HCCR));
11305ccae6a5SMatt Jacob 			ISP_WRITE(isp, BIU_ICR, 0);
11318a97c03aSMatt Jacob 		} else {
1132443e752dSMatt Jacob 			isp_prt(isp, ISP_LOGERR, "unknown interrupt 0x%x\n", r2hisr);
11338a97c03aSMatt Jacob 		}
1134126ec864SMatt Jacob 		return (0);
1135126ec864SMatt Jacob 	}
1136126ec864SMatt Jacob }
1137126ec864SMatt Jacob 
113810365e5aSMatt Jacob static int
1139443e752dSMatt Jacob isp_pci_rd_isr_2400(ispsoftc_t *isp, uint32_t *isrp, uint16_t *semap, uint16_t *mbox0p)
114010365e5aSMatt Jacob {
114110365e5aSMatt Jacob 	uint32_t r2hisr;
114210365e5aSMatt Jacob 
11436a7d12e1SMatt Jacob 	r2hisr = BXR4(isp, IspVirt2Off(isp, BIU2400_R2HSTSLO));
114410365e5aSMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG3, "RISC2HOST ISR 0x%x", r2hisr);
114510365e5aSMatt Jacob 	if ((r2hisr & BIU2400_R2HST_INTR) == 0) {
114610365e5aSMatt Jacob 		*isrp = 0;
114710365e5aSMatt Jacob 		return (0);
114810365e5aSMatt Jacob 	}
114910365e5aSMatt Jacob 	switch (r2hisr & BIU2400_R2HST_ISTAT_MASK) {
115010365e5aSMatt Jacob 	case ISP2400R2HST_ROM_MBX_OK:
115110365e5aSMatt Jacob 	case ISP2400R2HST_ROM_MBX_FAIL:
115210365e5aSMatt Jacob 	case ISP2400R2HST_MBX_OK:
115310365e5aSMatt Jacob 	case ISP2400R2HST_MBX_FAIL:
115410365e5aSMatt Jacob 	case ISP2400R2HST_ASYNC_EVENT:
115510365e5aSMatt Jacob 		*isrp = r2hisr & 0xffff;
115610365e5aSMatt Jacob 		*mbox0p = (r2hisr >> 16);
115710365e5aSMatt Jacob 		*semap = 1;
115810365e5aSMatt Jacob 		return (1);
115910365e5aSMatt Jacob 	case ISP2400R2HST_RSPQ_UPDATE:
116010365e5aSMatt Jacob 	case ISP2400R2HST_ATIO_RSPQ_UPDATE:
116110365e5aSMatt Jacob 	case ISP2400R2HST_ATIO_RQST_UPDATE:
116210365e5aSMatt Jacob 		*isrp = r2hisr & 0xffff;
116310365e5aSMatt Jacob 		*mbox0p = 0;
116410365e5aSMatt Jacob 		*semap = 0;
116510365e5aSMatt Jacob 		return (1);
116610365e5aSMatt Jacob 	default:
116710365e5aSMatt Jacob 		ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_RISC_INT);
116810365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGERR, "unknown interrupt 0x%x\n", r2hisr);
116910365e5aSMatt Jacob 		return (0);
117010365e5aSMatt Jacob 	}
117110365e5aSMatt Jacob }
117210365e5aSMatt Jacob 
117310365e5aSMatt Jacob static uint32_t
11749cd7268eSMatt Jacob isp_pci_rd_reg(ispsoftc_t *isp, int regoff)
117565adb54cSMatt Jacob {
11766a7d12e1SMatt Jacob 	uint16_t rv;
1177126ec864SMatt Jacob 	int oldconf = 0;
117865adb54cSMatt Jacob 
1179d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
118065adb54cSMatt Jacob 		/*
118165adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
118265adb54cSMatt Jacob 		 */
11836a7d12e1SMatt Jacob 		oldconf = BXR2(isp, IspVirt2Off(isp, BIU_CONF1));
1184443e752dSMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1), oldconf | BIU_PCI_CONF1_SXP);
11856a7d12e1SMatt Jacob 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2);
118665adb54cSMatt Jacob 	}
11876a7d12e1SMatt Jacob 	rv = BXR2(isp, IspVirt2Off(isp, regoff));
1188d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
11896a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1), oldconf);
11906a7d12e1SMatt Jacob 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2);
119165adb54cSMatt Jacob 	}
119265adb54cSMatt Jacob 	return (rv);
119365adb54cSMatt Jacob }
119465adb54cSMatt Jacob 
119565adb54cSMatt Jacob static void
119610365e5aSMatt Jacob isp_pci_wr_reg(ispsoftc_t *isp, int regoff, uint32_t val)
119765adb54cSMatt Jacob {
1198126ec864SMatt Jacob 	int oldconf = 0;
1199d59bd469SMatt Jacob 
1200d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
120165adb54cSMatt Jacob 		/*
120265adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
120365adb54cSMatt Jacob 		 */
12046a7d12e1SMatt Jacob 		oldconf = BXR2(isp, IspVirt2Off(isp, BIU_CONF1));
12056a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1),
1206126ec864SMatt Jacob 		    oldconf | BIU_PCI_CONF1_SXP);
12076a7d12e1SMatt Jacob 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2);
120865adb54cSMatt Jacob 	}
12096a7d12e1SMatt Jacob 	BXW2(isp, IspVirt2Off(isp, regoff), val);
12106a7d12e1SMatt Jacob 	MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, regoff), 2);
1211d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
12126a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1), oldconf);
12136a7d12e1SMatt Jacob 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2);
121465adb54cSMatt Jacob 	}
12156a7d12e1SMatt Jacob 
1216f9734398SMatt Jacob }
121765adb54cSMatt Jacob 
121810365e5aSMatt Jacob static uint32_t
12199cd7268eSMatt Jacob isp_pci_rd_reg_1080(ispsoftc_t *isp, int regoff)
1220d59bd469SMatt Jacob {
122110365e5aSMatt Jacob 	uint32_t rv, oc = 0;
1222d59bd469SMatt Jacob 
122322e1dc85SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
122422e1dc85SMatt Jacob 	    (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
122510365e5aSMatt Jacob 		uint32_t tc;
1226d59bd469SMatt Jacob 		/*
1227d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
1228d59bd469SMatt Jacob 		 */
12296a7d12e1SMatt Jacob 		oc = BXR2(isp, IspVirt2Off(isp, BIU_CONF1));
123022e1dc85SMatt Jacob 		tc = oc & ~BIU_PCI1080_CONF1_DMA;
123122e1dc85SMatt Jacob 		if (regoff & SXP_BANK1_SELECT)
123222e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP1;
123322e1dc85SMatt Jacob 		else
123422e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP0;
12356a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1), tc);
12366a7d12e1SMatt Jacob 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2);
1237d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
12386a7d12e1SMatt Jacob 		oc = BXR2(isp, IspVirt2Off(isp, BIU_CONF1));
12396a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1),
1240126ec864SMatt Jacob 		    oc | BIU_PCI1080_CONF1_DMA);
12416a7d12e1SMatt Jacob 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2);
1242d59bd469SMatt Jacob 	}
12436a7d12e1SMatt Jacob 	rv = BXR2(isp, IspVirt2Off(isp, regoff));
124422e1dc85SMatt Jacob 	if (oc) {
12456a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1), oc);
12466a7d12e1SMatt Jacob 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2);
1247d59bd469SMatt Jacob 	}
1248d59bd469SMatt Jacob 	return (rv);
1249d59bd469SMatt Jacob }
1250d59bd469SMatt Jacob 
1251d59bd469SMatt Jacob static void
125210365e5aSMatt Jacob isp_pci_wr_reg_1080(ispsoftc_t *isp, int regoff, uint32_t val)
1253d59bd469SMatt Jacob {
1254126ec864SMatt Jacob 	int oc = 0;
1255d59bd469SMatt Jacob 
125622e1dc85SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
125722e1dc85SMatt Jacob 	    (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
125810365e5aSMatt Jacob 		uint32_t tc;
1259d59bd469SMatt Jacob 		/*
1260d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
1261d59bd469SMatt Jacob 		 */
12626a7d12e1SMatt Jacob 		oc = BXR2(isp, IspVirt2Off(isp, BIU_CONF1));
126322e1dc85SMatt Jacob 		tc = oc & ~BIU_PCI1080_CONF1_DMA;
126422e1dc85SMatt Jacob 		if (regoff & SXP_BANK1_SELECT)
126522e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP1;
126622e1dc85SMatt Jacob 		else
126722e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP0;
12686a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1), tc);
12696a7d12e1SMatt Jacob 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2);
1270d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
12716a7d12e1SMatt Jacob 		oc = BXR2(isp, IspVirt2Off(isp, BIU_CONF1));
12726a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1),
1273126ec864SMatt Jacob 		    oc | BIU_PCI1080_CONF1_DMA);
12746a7d12e1SMatt Jacob 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2);
1275d59bd469SMatt Jacob 	}
12766a7d12e1SMatt Jacob 	BXW2(isp, IspVirt2Off(isp, regoff), val);
12776a7d12e1SMatt Jacob 	MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, regoff), 2);
127822e1dc85SMatt Jacob 	if (oc) {
12796a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1), oc);
12806a7d12e1SMatt Jacob 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2);
128110365e5aSMatt Jacob 	}
128210365e5aSMatt Jacob }
128310365e5aSMatt Jacob 
128410365e5aSMatt Jacob static uint32_t
128510365e5aSMatt Jacob isp_pci_rd_reg_2400(ispsoftc_t *isp, int regoff)
128610365e5aSMatt Jacob {
128710365e5aSMatt Jacob 	uint32_t rv;
128810365e5aSMatt Jacob 	int block = regoff & _BLK_REG_MASK;
128910365e5aSMatt Jacob 
129010365e5aSMatt Jacob 	switch (block) {
129110365e5aSMatt Jacob 	case BIU_BLOCK:
129210365e5aSMatt Jacob 		break;
129310365e5aSMatt Jacob 	case MBOX_BLOCK:
12946a7d12e1SMatt Jacob 		return (BXR2(isp, IspVirt2Off(isp, regoff)));
129510365e5aSMatt Jacob 	case SXP_BLOCK:
129610365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "SXP_BLOCK read at 0x%x", regoff);
129710365e5aSMatt Jacob 		return (0xffffffff);
129810365e5aSMatt Jacob 	case RISC_BLOCK:
129910365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "RISC_BLOCK read at 0x%x", regoff);
130010365e5aSMatt Jacob 		return (0xffffffff);
130110365e5aSMatt Jacob 	case DMA_BLOCK:
130210365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "DMA_BLOCK read at 0x%x", regoff);
130310365e5aSMatt Jacob 		return (0xffffffff);
130410365e5aSMatt Jacob 	default:
130510365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "unknown block read at 0x%x", regoff);
130610365e5aSMatt Jacob 		return (0xffffffff);
130710365e5aSMatt Jacob 	}
130810365e5aSMatt Jacob 
130910365e5aSMatt Jacob 
131010365e5aSMatt Jacob 	switch (regoff) {
131110365e5aSMatt Jacob 	case BIU2400_FLASH_ADDR:
131210365e5aSMatt Jacob 	case BIU2400_FLASH_DATA:
131310365e5aSMatt Jacob 	case BIU2400_ICR:
131410365e5aSMatt Jacob 	case BIU2400_ISR:
131510365e5aSMatt Jacob 	case BIU2400_CSR:
131610365e5aSMatt Jacob 	case BIU2400_REQINP:
131710365e5aSMatt Jacob 	case BIU2400_REQOUTP:
131810365e5aSMatt Jacob 	case BIU2400_RSPINP:
131910365e5aSMatt Jacob 	case BIU2400_RSPOUTP:
13202df76c16SMatt Jacob 	case BIU2400_PRI_REQINP:
13212df76c16SMatt Jacob 	case BIU2400_PRI_REQOUTP:
132210365e5aSMatt Jacob 	case BIU2400_ATIO_RSPINP:
13232df76c16SMatt Jacob 	case BIU2400_ATIO_RSPOUTP:
132410365e5aSMatt Jacob 	case BIU2400_HCCR:
132510365e5aSMatt Jacob 	case BIU2400_GPIOD:
132610365e5aSMatt Jacob 	case BIU2400_GPIOE:
132710365e5aSMatt Jacob 	case BIU2400_HSEMA:
13286a7d12e1SMatt Jacob 		rv = BXR4(isp, IspVirt2Off(isp, regoff));
132910365e5aSMatt Jacob 		break;
133010365e5aSMatt Jacob 	case BIU2400_R2HSTSLO:
13316a7d12e1SMatt Jacob 		rv = BXR4(isp, IspVirt2Off(isp, regoff));
133210365e5aSMatt Jacob 		break;
133310365e5aSMatt Jacob 	case BIU2400_R2HSTSHI:
13346a7d12e1SMatt Jacob 		rv = BXR4(isp, IspVirt2Off(isp, regoff)) >> 16;
133510365e5aSMatt Jacob 		break;
133610365e5aSMatt Jacob 	default:
133710365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGERR,
133810365e5aSMatt Jacob 		    "isp_pci_rd_reg_2400: unknown offset %x", regoff);
133910365e5aSMatt Jacob 		rv = 0xffffffff;
134010365e5aSMatt Jacob 		break;
134110365e5aSMatt Jacob 	}
134210365e5aSMatt Jacob 	return (rv);
134310365e5aSMatt Jacob }
134410365e5aSMatt Jacob 
134510365e5aSMatt Jacob static void
134610365e5aSMatt Jacob isp_pci_wr_reg_2400(ispsoftc_t *isp, int regoff, uint32_t val)
134710365e5aSMatt Jacob {
134810365e5aSMatt Jacob 	int block = regoff & _BLK_REG_MASK;
134910365e5aSMatt Jacob 
135010365e5aSMatt Jacob 	switch (block) {
135110365e5aSMatt Jacob 	case BIU_BLOCK:
135210365e5aSMatt Jacob 		break;
135310365e5aSMatt Jacob 	case MBOX_BLOCK:
13546a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, regoff), val);
13556a7d12e1SMatt Jacob 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, regoff), 2);
135610365e5aSMatt Jacob 		return;
135710365e5aSMatt Jacob 	case SXP_BLOCK:
135810365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "SXP_BLOCK write at 0x%x", regoff);
135910365e5aSMatt Jacob 		return;
136010365e5aSMatt Jacob 	case RISC_BLOCK:
136110365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "RISC_BLOCK write at 0x%x", regoff);
136210365e5aSMatt Jacob 		return;
136310365e5aSMatt Jacob 	case DMA_BLOCK:
136410365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "DMA_BLOCK write at 0x%x", regoff);
136510365e5aSMatt Jacob 		return;
136610365e5aSMatt Jacob 	default:
136710365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "unknown block write at 0x%x",
136810365e5aSMatt Jacob 		    regoff);
136910365e5aSMatt Jacob 		break;
137010365e5aSMatt Jacob 	}
137110365e5aSMatt Jacob 
137210365e5aSMatt Jacob 	switch (regoff) {
137310365e5aSMatt Jacob 	case BIU2400_FLASH_ADDR:
137410365e5aSMatt Jacob 	case BIU2400_FLASH_DATA:
137510365e5aSMatt Jacob 	case BIU2400_ICR:
137610365e5aSMatt Jacob 	case BIU2400_ISR:
137710365e5aSMatt Jacob 	case BIU2400_CSR:
137810365e5aSMatt Jacob 	case BIU2400_REQINP:
137910365e5aSMatt Jacob 	case BIU2400_REQOUTP:
138010365e5aSMatt Jacob 	case BIU2400_RSPINP:
138110365e5aSMatt Jacob 	case BIU2400_RSPOUTP:
13822df76c16SMatt Jacob 	case BIU2400_PRI_REQINP:
13832df76c16SMatt Jacob 	case BIU2400_PRI_REQOUTP:
138410365e5aSMatt Jacob 	case BIU2400_ATIO_RSPINP:
13852df76c16SMatt Jacob 	case BIU2400_ATIO_RSPOUTP:
138610365e5aSMatt Jacob 	case BIU2400_HCCR:
138710365e5aSMatt Jacob 	case BIU2400_GPIOD:
138810365e5aSMatt Jacob 	case BIU2400_GPIOE:
138910365e5aSMatt Jacob 	case BIU2400_HSEMA:
13906a7d12e1SMatt Jacob 		BXW4(isp, IspVirt2Off(isp, regoff), val);
13916a7d12e1SMatt Jacob 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, regoff), 4);
139210365e5aSMatt Jacob 		break;
139310365e5aSMatt Jacob 	default:
139410365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGERR,
139510365e5aSMatt Jacob 		    "isp_pci_wr_reg_2400: bad offset 0x%x", regoff);
139610365e5aSMatt Jacob 		break;
1397d59bd469SMatt Jacob 	}
1398d59bd469SMatt Jacob }
1399d59bd469SMatt Jacob 
1400d720e6d5SJustin T. Gibbs 
1401222bb542SMatt Jacob struct imush {
14029cd7268eSMatt Jacob 	ispsoftc_t *isp;
14032df76c16SMatt Jacob 	caddr_t vbase;
14042df76c16SMatt Jacob 	int chan;
1405222bb542SMatt Jacob 	int error;
1406222bb542SMatt Jacob };
1407222bb542SMatt Jacob 
14081923f739SMatt Jacob static void imc(void *, bus_dma_segment_t *, int, int);
14092df76c16SMatt Jacob static void imc1(void *, bus_dma_segment_t *, int, int);
14101923f739SMatt Jacob 
1411d720e6d5SJustin T. Gibbs static void
14121923f739SMatt Jacob imc(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1413d720e6d5SJustin T. Gibbs {
1414222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
14152df76c16SMatt Jacob 
1416222bb542SMatt Jacob 	if (error) {
1417222bb542SMatt Jacob 		imushp->error = error;
14182df76c16SMatt Jacob 		return;
14192df76c16SMatt Jacob 	}
14202df76c16SMatt Jacob 	if (nseg != 1) {
14212df76c16SMatt Jacob 		imushp->error = EINVAL;
14222df76c16SMatt Jacob 		return;
14232df76c16SMatt Jacob 	}
14242df76c16SMatt Jacob 	imushp->isp->isp_rquest = imushp->vbase;
14252df76c16SMatt Jacob 	imushp->isp->isp_rquest_dma = segs->ds_addr;
14262df76c16SMatt Jacob 	segs->ds_addr += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(imushp->isp));
14272df76c16SMatt Jacob 	imushp->vbase += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(imushp->isp));
14282df76c16SMatt Jacob 	imushp->isp->isp_result_dma = segs->ds_addr;
14292df76c16SMatt Jacob 	imushp->isp->isp_result = imushp->vbase;
14301923f739SMatt Jacob 
14312df76c16SMatt Jacob #ifdef	ISP_TARGET_MODE
14322df76c16SMatt Jacob 	if (IS_24XX(imushp->isp)) {
14332df76c16SMatt Jacob 		segs->ds_addr += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(imushp->isp));
14342df76c16SMatt Jacob 		imushp->vbase += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(imushp->isp));
14352df76c16SMatt Jacob 		imushp->isp->isp_atioq_dma = segs->ds_addr;
14362df76c16SMatt Jacob 		imushp->isp->isp_atioq = imushp->vbase;
14371923f739SMatt Jacob 	}
14382df76c16SMatt Jacob #endif
1439222bb542SMatt Jacob }
14402df76c16SMatt Jacob 
14412df76c16SMatt Jacob static void
14422df76c16SMatt Jacob imc1(void *arg, bus_dma_segment_t *segs, int nseg, int error)
14432df76c16SMatt Jacob {
14442df76c16SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
14452df76c16SMatt Jacob 	if (error) {
14462df76c16SMatt Jacob 		imushp->error = error;
14472df76c16SMatt Jacob 		return;
14482df76c16SMatt Jacob 	}
14492df76c16SMatt Jacob 	if (nseg != 1) {
14502df76c16SMatt Jacob 		imushp->error = EINVAL;
14512df76c16SMatt Jacob 		return;
14522df76c16SMatt Jacob 	}
14532df76c16SMatt Jacob 	FCPARAM(imushp->isp, imushp->chan)->isp_scdma = segs->ds_addr;
14542df76c16SMatt Jacob 	FCPARAM(imushp->isp, imushp->chan)->isp_scratch = imushp->vbase;
1455d720e6d5SJustin T. Gibbs }
1456d720e6d5SJustin T. Gibbs 
1457d720e6d5SJustin T. Gibbs static int
14589cd7268eSMatt Jacob isp_pci_mbxdma(ispsoftc_t *isp)
1459d720e6d5SJustin T. Gibbs {
1460d720e6d5SJustin T. Gibbs 	caddr_t base;
14611dae40ebSMatt Jacob 	uint32_t len;
14622df76c16SMatt Jacob 	int i, error, ns, cmap = 0;
146353af7d22SMatt Jacob 	bus_size_t slim;	/* segment size */
14644b2dc3c4SScott Long 	bus_addr_t llim;	/* low limit of unavailable dma */
146551effc8cSMatt Jacob 	bus_addr_t hlim;	/* high limit of unavailable dma */
1466222bb542SMatt Jacob 	struct imush im;
1467222bb542SMatt Jacob 
1468a95ae193SMatt Jacob 	/*
1469a95ae193SMatt Jacob 	 * Already been here? If so, leave...
1470a95ae193SMatt Jacob 	 */
1471a95ae193SMatt Jacob 	if (isp->isp_rquest) {
1472a95ae193SMatt Jacob 		return (0);
1473a95ae193SMatt Jacob 	}
14740a70657fSMatt Jacob 	ISP_UNLOCK(isp);
1475a95ae193SMatt Jacob 
147610365e5aSMatt Jacob 	if (isp->isp_maxcmds == 0) {
147710365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGERR, "maxcmds not set");
14780a70657fSMatt Jacob 		ISP_LOCK(isp);
147910365e5aSMatt Jacob 		return (1);
148010365e5aSMatt Jacob 	}
148110365e5aSMatt Jacob 
148253af7d22SMatt Jacob 	hlim = BUS_SPACE_MAXADDR;
14831923f739SMatt Jacob 	if (IS_ULTRA2(isp) || IS_FC(isp) || IS_1240(isp)) {
14849b434edeSMatt Jacob 		if (sizeof (bus_size_t) > 4) {
148553af7d22SMatt Jacob 			slim = (bus_size_t) (1ULL << 32);
14869b434edeSMatt Jacob 		} else {
14879b434edeSMatt Jacob 			slim = (bus_size_t) (1UL << 31);
14889b434edeSMatt Jacob 		}
14891dae40ebSMatt Jacob 		llim = BUS_SPACE_MAXADDR;
14901923f739SMatt Jacob 	} else {
14911dae40ebSMatt Jacob 		llim = BUS_SPACE_MAXADDR_32BIT;
14929b434edeSMatt Jacob 		slim = (1UL << 24);
14931923f739SMatt Jacob 	}
14941923f739SMatt Jacob 
14950a70657fSMatt Jacob 	len = isp->isp_maxcmds * sizeof (struct isp_pcmd);
14962df76c16SMatt Jacob 	isp->isp_osinfo.pcmd_pool = (struct isp_pcmd *) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
14970a70657fSMatt Jacob 	if (isp->isp_osinfo.pcmd_pool == NULL) {
14980a70657fSMatt Jacob 		isp_prt(isp, ISP_LOGERR, "cannot allocate pcmds");
14990a70657fSMatt Jacob 		ISP_LOCK(isp);
15000a70657fSMatt Jacob 		return (1);
15010a70657fSMatt Jacob 	}
15020a70657fSMatt Jacob 
150309934867SMatt Jacob 	/*
150409934867SMatt Jacob 	 * XXX: We don't really support 64 bit target mode for parallel scsi yet
150509934867SMatt Jacob 	 */
150609934867SMatt Jacob #ifdef	ISP_TARGET_MODE
150709934867SMatt Jacob 	if (IS_SCSI(isp) && sizeof (bus_addr_t) > 4) {
15080a70657fSMatt Jacob 		free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
150909934867SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "we cannot do DAC for SPI cards yet");
15102df76c16SMatt Jacob 		ISP_LOCK(isp);
151109934867SMatt Jacob 		return (1);
151209934867SMatt Jacob 	}
151309934867SMatt Jacob #endif
151409934867SMatt Jacob 
15152df76c16SMatt Jacob 	if (isp_dma_tag_create(BUS_DMA_ROOTARG(ISP_PCD(isp)), 1, slim, llim, hlim, NULL, NULL, BUS_SPACE_MAXSIZE, ISP_NSEGS, slim, 0, &isp->isp_osinfo.dmat)) {
15160a70657fSMatt Jacob 		free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
151772429e49SMatt Jacob 		ISP_LOCK(isp);
15180a70657fSMatt Jacob 		isp_prt(isp, ISP_LOGERR, "could not create master dma tag");
15191923f739SMatt Jacob 		return (1);
15201923f739SMatt Jacob 	}
15211923f739SMatt Jacob 
1522c8b8a2c4SMatt Jacob 	len = sizeof (isp_hdl_t) * isp->isp_maxcmds;
1523c8b8a2c4SMatt Jacob 	isp->isp_xflist = (isp_hdl_t *) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
1524a95ae193SMatt Jacob 	if (isp->isp_xflist == NULL) {
15250a70657fSMatt Jacob 		free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
152672429e49SMatt Jacob 		ISP_LOCK(isp);
15270a70657fSMatt Jacob 		isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array");
1528a95ae193SMatt Jacob 		return (1);
1529a95ae193SMatt Jacob 	}
1530c8b8a2c4SMatt Jacob 	for (len = 0; len < isp->isp_maxcmds - 1; len++) {
1531c8b8a2c4SMatt Jacob 		isp->isp_xflist[len].cmd = &isp->isp_xflist[len+1];
1532c8b8a2c4SMatt Jacob 	}
1533c8b8a2c4SMatt Jacob 	isp->isp_xffree = isp->isp_xflist;
153451e23558SNate Lawson #ifdef	ISP_TARGET_MODE
153532b3ec7dSMatt Jacob 	len = sizeof (isp_hdl_t) * isp->isp_maxcmds;
1536c8b8a2c4SMatt Jacob 	isp->isp_tgtlist = (isp_hdl_t *) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
153751e23558SNate Lawson 	if (isp->isp_tgtlist == NULL) {
15380a70657fSMatt Jacob 		free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
1539a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
154072429e49SMatt Jacob 		ISP_LOCK(isp);
15410a70657fSMatt Jacob 		isp_prt(isp, ISP_LOGERR, "cannot alloc tgtlist array");
1542a95ae193SMatt Jacob 		return (1);
1543a95ae193SMatt Jacob 	}
1544c8b8a2c4SMatt Jacob 	for (len = 0; len < isp->isp_maxcmds - 1; len++) {
1545c8b8a2c4SMatt Jacob 		isp->isp_tgtlist[len].cmd = &isp->isp_tgtlist[len+1];
1546c8b8a2c4SMatt Jacob 	}
1547c8b8a2c4SMatt Jacob 	isp->isp_tgtfree = isp->isp_tgtlist;
15480a70657fSMatt Jacob #endif
1549a95ae193SMatt Jacob 
1550d720e6d5SJustin T. Gibbs 	/*
15512df76c16SMatt Jacob 	 * Allocate and map the request and result queues (and ATIO queue
15522df76c16SMatt Jacob 	 * if we're a 2400 supporting target mode).
1553d720e6d5SJustin T. Gibbs 	 */
1554d02373f1SMatt Jacob 	len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
1555d02373f1SMatt Jacob 	len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
15562df76c16SMatt Jacob #ifdef	ISP_TARGET_MODE
15572df76c16SMatt Jacob 	if (IS_24XX(isp)) {
15582df76c16SMatt Jacob 		len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
1559d720e6d5SJustin T. Gibbs 	}
15602df76c16SMatt Jacob #endif
15611923f739SMatt Jacob 
15621923f739SMatt Jacob 	ns = (len / PAGE_SIZE) + 1;
15632df76c16SMatt Jacob 
156453af7d22SMatt Jacob 	/*
15652df76c16SMatt Jacob 	 * Create a tag for the control spaces. We don't always need this
15662df76c16SMatt Jacob 	 * to be 32 bits, but we do this for simplicity and speed's sake.
156753af7d22SMatt Jacob 	 */
15682df76c16SMatt Jacob 	if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, slim, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, len, ns, slim, 0, &isp->isp_osinfo.cdmat)) {
15692df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "cannot create a dma tag for control spaces");
15700a70657fSMatt Jacob 		free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
1571a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
157251e23558SNate Lawson #ifdef	ISP_TARGET_MODE
157351e23558SNate Lawson 		free(isp->isp_tgtlist, M_DEVBUF);
157451e23558SNate Lawson #endif
157572429e49SMatt Jacob 		ISP_LOCK(isp);
1576d720e6d5SJustin T. Gibbs 		return (1);
1577d720e6d5SJustin T. Gibbs 	}
1578d720e6d5SJustin T. Gibbs 
15792df76c16SMatt Jacob 	if (bus_dmamem_alloc(isp->isp_osinfo.cdmat, (void **)&base, BUS_DMA_NOWAIT, &isp->isp_osinfo.cdmap) != 0) {
15802df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "cannot allocate %d bytes of CCB memory", len);
15812df76c16SMatt Jacob 		bus_dma_tag_destroy(isp->isp_osinfo.cdmat);
15820a70657fSMatt Jacob 		free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
1583a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
158451e23558SNate Lawson #ifdef	ISP_TARGET_MODE
158551e23558SNate Lawson 		free(isp->isp_tgtlist, M_DEVBUF);
158651e23558SNate Lawson #endif
158772429e49SMatt Jacob 		ISP_LOCK(isp);
1588222bb542SMatt Jacob 		return (1);
1589222bb542SMatt Jacob 	}
1590d720e6d5SJustin T. Gibbs 
15912df76c16SMatt Jacob 	im.isp = isp;
15922df76c16SMatt Jacob 	im.chan = 0;
15932df76c16SMatt Jacob 	im.vbase = base;
15942df76c16SMatt Jacob 	im.error = 0;
15952df76c16SMatt Jacob 
15962df76c16SMatt Jacob 	bus_dmamap_load(isp->isp_osinfo.cdmat, isp->isp_osinfo.cdmap, base, len, imc, &im, 0);
15972df76c16SMatt Jacob 	if (im.error) {
15982df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "error %d loading dma map for control areas", im.error);
15992df76c16SMatt Jacob 		goto bad;
16002df76c16SMatt Jacob 	}
16012df76c16SMatt Jacob 
16022df76c16SMatt Jacob 	if (IS_FC(isp)) {
16032df76c16SMatt Jacob 		for (cmap = 0; cmap < isp->isp_nchan; cmap++) {
16042df76c16SMatt Jacob 			struct isp_fc *fc = ISP_FC_PC(isp, cmap);
16052df76c16SMatt Jacob 			if (isp_dma_tag_create(isp->isp_osinfo.dmat, 64, slim, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, ISP_FC_SCRLEN, 1, slim, 0, &fc->tdmat)) {
16062df76c16SMatt Jacob 				goto bad;
16072df76c16SMatt Jacob 			}
16082df76c16SMatt Jacob 			if (bus_dmamem_alloc(fc->tdmat, (void **)&base, BUS_DMA_NOWAIT, &fc->tdmap) != 0) {
16092df76c16SMatt Jacob 				bus_dma_tag_destroy(fc->tdmat);
16102df76c16SMatt Jacob 				goto bad;
16112df76c16SMatt Jacob 			}
16122df76c16SMatt Jacob 			im.isp = isp;
16132df76c16SMatt Jacob 			im.chan = cmap;
16142df76c16SMatt Jacob 			im.vbase = base;
16152df76c16SMatt Jacob 			im.error = 0;
16162df76c16SMatt Jacob 			bus_dmamap_load(fc->tdmat, fc->tdmap, base, ISP_FC_SCRLEN, imc1, &im, 0);
16172df76c16SMatt Jacob 			if (im.error) {
16182df76c16SMatt Jacob 				bus_dmamem_free(fc->tdmat, base, fc->tdmap);
16192df76c16SMatt Jacob 				bus_dma_tag_destroy(fc->tdmat);
16202df76c16SMatt Jacob 				goto bad;
16212df76c16SMatt Jacob 			}
16222df76c16SMatt Jacob 		}
16232df76c16SMatt Jacob 	}
16242df76c16SMatt Jacob 
1625a95ae193SMatt Jacob 	for (i = 0; i < isp->isp_maxcmds; i++) {
16260a70657fSMatt Jacob 		struct isp_pcmd *pcmd = &isp->isp_osinfo.pcmd_pool[i];
16270a70657fSMatt Jacob 		error = bus_dmamap_create(isp->isp_osinfo.dmat, 0, &pcmd->dmap);
1628d720e6d5SJustin T. Gibbs 		if (error) {
16292df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "error %d creating per-cmd DMA maps", error);
16301923f739SMatt Jacob 			while (--i >= 0) {
16312df76c16SMatt Jacob 				bus_dmamap_destroy(isp->isp_osinfo.dmat, isp->isp_osinfo.pcmd_pool[i].dmap);
16321923f739SMatt Jacob 			}
16331923f739SMatt Jacob 			goto bad;
1634d720e6d5SJustin T. Gibbs 		}
16352df76c16SMatt Jacob 		callout_init_mtx(&pcmd->wdog, &isp->isp_osinfo.lock, 0);
16360a70657fSMatt Jacob 		if (i == isp->isp_maxcmds-1) {
16370a70657fSMatt Jacob 			pcmd->next = NULL;
16380a70657fSMatt Jacob 		} else {
16390a70657fSMatt Jacob 			pcmd->next = &isp->isp_osinfo.pcmd_pool[i+1];
1640d720e6d5SJustin T. Gibbs 		}
16410a70657fSMatt Jacob 	}
16420a70657fSMatt Jacob 	isp->isp_osinfo.pcmd_free = &isp->isp_osinfo.pcmd_pool[0];
164372429e49SMatt Jacob 	ISP_LOCK(isp);
1644d720e6d5SJustin T. Gibbs 	return (0);
16451923f739SMatt Jacob 
16461923f739SMatt Jacob bad:
16472df76c16SMatt Jacob 	while (--cmap >= 0) {
16482df76c16SMatt Jacob 		struct isp_fc *fc = ISP_FC_PC(isp, cmap);
16492df76c16SMatt Jacob 		bus_dmamem_free(fc->tdmat, base, fc->tdmap);
16502df76c16SMatt Jacob 		bus_dma_tag_destroy(fc->tdmat);
16512df76c16SMatt Jacob 	}
16522df76c16SMatt Jacob 	bus_dmamem_free(isp->isp_osinfo.cdmat, base, isp->isp_osinfo.cdmap);
16532df76c16SMatt Jacob 	bus_dma_tag_destroy(isp->isp_osinfo.cdmat);
16541923f739SMatt Jacob 	free(isp->isp_xflist, M_DEVBUF);
165551e23558SNate Lawson #ifdef	ISP_TARGET_MODE
165651e23558SNate Lawson 	free(isp->isp_tgtlist, M_DEVBUF);
165751e23558SNate Lawson #endif
16580a70657fSMatt Jacob 	free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
16591923f739SMatt Jacob 	isp->isp_rquest = NULL;
16600a70657fSMatt Jacob 	ISP_LOCK(isp);
16611923f739SMatt Jacob 	return (1);
1662d720e6d5SJustin T. Gibbs }
1663d720e6d5SJustin T. Gibbs 
1664d720e6d5SJustin T. Gibbs typedef struct {
16659cd7268eSMatt Jacob 	ispsoftc_t *isp;
16669e11e5beSMatt Jacob 	void *cmd_token;
16672df76c16SMatt Jacob 	void *rq;	/* original request */
16681dae40ebSMatt Jacob 	int error;
16692df76c16SMatt Jacob 	bus_size_t mapsize;
1670d720e6d5SJustin T. Gibbs } mush_t;
1671d720e6d5SJustin T. Gibbs 
16724873663cSMatt Jacob #define	MUSHERR_NOQENTRIES	-2
16734873663cSMatt Jacob 
16749e11e5beSMatt Jacob #ifdef	ISP_TARGET_MODE
16752df76c16SMatt Jacob static void tdma2_2(void *, bus_dma_segment_t *, int, bus_size_t, int);
16762df76c16SMatt Jacob static void tdma2(void *, bus_dma_segment_t *, int, int);
16779e11e5beSMatt Jacob 
1678d720e6d5SJustin T. Gibbs static void
16792df76c16SMatt Jacob tdma2_2(void *arg, bus_dma_segment_t *dm_segs, int nseg, bus_size_t mapsize, int error)
1680d720e6d5SJustin T. Gibbs {
1681d720e6d5SJustin T. Gibbs 	mush_t *mp;
16822df76c16SMatt Jacob 	mp = (mush_t *)arg;
16832df76c16SMatt Jacob 	mp->mapsize = mapsize;
16842df76c16SMatt Jacob 	tdma2(arg, dm_segs, nseg, error);
16852df76c16SMatt Jacob }
16862df76c16SMatt Jacob 
16872df76c16SMatt Jacob static void
16882df76c16SMatt Jacob tdma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
16892df76c16SMatt Jacob {
16902df76c16SMatt Jacob 	mush_t *mp;
16919cd7268eSMatt Jacob 	ispsoftc_t *isp;
16922df76c16SMatt Jacob 	struct ccb_scsiio *csio;
16932df76c16SMatt Jacob 	isp_ddir_t ddir;
16942df76c16SMatt Jacob 	ispreq_t *rq;
1695d720e6d5SJustin T. Gibbs 
1696d720e6d5SJustin T. Gibbs 	mp = (mush_t *) arg;
1697d720e6d5SJustin T. Gibbs 	if (error) {
1698d720e6d5SJustin T. Gibbs 		mp->error = error;
1699d720e6d5SJustin T. Gibbs 		return;
1700d720e6d5SJustin T. Gibbs 	}
17019e11e5beSMatt Jacob 	csio = mp->cmd_token;
17024fd13c1bSMatt Jacob 	isp = mp->isp;
17032df76c16SMatt Jacob 	rq = mp->rq;
17042df76c16SMatt Jacob 	if (nseg) {
170509934867SMatt Jacob 		if (sizeof (bus_addr_t) > 4) {
17062df76c16SMatt Jacob 			if (nseg >= ISP_NSEG64_MAX) {
17072df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG64_MAX);
17082df76c16SMatt Jacob 				mp->error = EFAULT;
17099e11e5beSMatt Jacob 				return;
17109e11e5beSMatt Jacob 			}
17112df76c16SMatt Jacob 			if (rq->req_header.rqs_entry_type == RQSTYPE_CTIO2) {
17122df76c16SMatt Jacob 				rq->req_header.rqs_entry_type = RQSTYPE_CTIO3;
17132df76c16SMatt Jacob 			}
171409934867SMatt Jacob 		} else {
17152df76c16SMatt Jacob 			if (nseg >= ISP_NSEG_MAX) {
17162df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG_MAX);
17172df76c16SMatt Jacob 				mp->error = EFAULT;
17182df76c16SMatt Jacob 				return;
171909934867SMatt Jacob 			}
17202df76c16SMatt Jacob 		}
17212df76c16SMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
17222df76c16SMatt Jacob 			bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREWRITE);
17232df76c16SMatt Jacob 			ddir = ISP_TO_DEVICE;
17242df76c16SMatt Jacob 		} else if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
17252df76c16SMatt Jacob 			bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREREAD);
17262df76c16SMatt Jacob 			ddir = ISP_FROM_DEVICE;
172709934867SMatt Jacob 		} else {
17282df76c16SMatt Jacob 			ddir = ISP_NOXFR;
172909934867SMatt Jacob 		}
17302df76c16SMatt Jacob 	} else {
17312df76c16SMatt Jacob 		dm_segs = NULL;
17322df76c16SMatt Jacob 		nseg = 0;
17332df76c16SMatt Jacob 		ddir = ISP_NOXFR;
1734fc087171SMatt Jacob 	}
173565b024e1SMatt Jacob 
17362df76c16SMatt Jacob 	if (isp_send_tgt_cmd(isp, rq, dm_segs, nseg, XS_XFRLEN(csio), ddir, &csio->sense_data, csio->sense_len) != CMD_QUEUED) {
17372df76c16SMatt Jacob 		mp->error = MUSHERR_NOQENTRIES;
173810365e5aSMatt Jacob 	}
17399e11e5beSMatt Jacob }
17409e11e5beSMatt Jacob #endif
17419e11e5beSMatt Jacob 
17422df76c16SMatt Jacob static void dma2_2(void *, bus_dma_segment_t *, int, bus_size_t, int);
1743126ec864SMatt Jacob static void dma2(void *, bus_dma_segment_t *, int, int);
17449e11e5beSMatt Jacob 
17456de9bf77SMatt Jacob static void
17462df76c16SMatt Jacob dma2_2(void *arg, bus_dma_segment_t *dm_segs, int nseg, bus_size_t mapsize, int error)
174710365e5aSMatt Jacob {
174810365e5aSMatt Jacob 	mush_t *mp;
174910365e5aSMatt Jacob 	mp = (mush_t *)arg;
17502df76c16SMatt Jacob 	mp->mapsize = mapsize;
17512df76c16SMatt Jacob 	dma2(arg, dm_segs, nseg, error);
17526de9bf77SMatt Jacob }
17531dae40ebSMatt Jacob 
17549e11e5beSMatt Jacob static void
17559e11e5beSMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
17569e11e5beSMatt Jacob {
17579e11e5beSMatt Jacob 	mush_t *mp;
17589cd7268eSMatt Jacob 	ispsoftc_t *isp;
17599e11e5beSMatt Jacob 	struct ccb_scsiio *csio;
17602df76c16SMatt Jacob 	isp_ddir_t ddir;
17619e11e5beSMatt Jacob 	ispreq_t *rq;
17629e11e5beSMatt Jacob 
17639e11e5beSMatt Jacob 	mp = (mush_t *) arg;
17649e11e5beSMatt Jacob 	if (error) {
17659e11e5beSMatt Jacob 		mp->error = error;
17669e11e5beSMatt Jacob 		return;
17679e11e5beSMatt Jacob 	}
17689e11e5beSMatt Jacob 	csio = mp->cmd_token;
17694fd13c1bSMatt Jacob 	isp = mp->isp;
17709e11e5beSMatt Jacob 	rq = mp->rq;
17712df76c16SMatt Jacob 	if (nseg) {
17722df76c16SMatt Jacob 		if (sizeof (bus_addr_t) > 4) {
17732df76c16SMatt Jacob 			if (nseg >= ISP_NSEG64_MAX) {
17742df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG64_MAX);
17752df76c16SMatt Jacob 				mp->error = EFAULT;
1776d720e6d5SJustin T. Gibbs 				return;
1777d720e6d5SJustin T. Gibbs 			}
17782df76c16SMatt Jacob 			if (rq->req_header.rqs_entry_type == RQSTYPE_T2RQS) {
17792df76c16SMatt Jacob 				rq->req_header.rqs_entry_type = RQSTYPE_T3RQS;
17802df76c16SMatt Jacob 			} else if (rq->req_header.rqs_entry_type == RQSTYPE_REQUEST) {
17812df76c16SMatt Jacob 				rq->req_header.rqs_entry_type = RQSTYPE_A64;
1782d720e6d5SJustin T. Gibbs 			}
17832df76c16SMatt Jacob 		} else {
17842df76c16SMatt Jacob 			if (nseg >= ISP_NSEG_MAX) {
17852df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG_MAX);
17862df76c16SMatt Jacob 				mp->error = EFAULT;
17872df76c16SMatt Jacob 				return;
178810365e5aSMatt Jacob 			}
1789d720e6d5SJustin T. Gibbs 		}
17902df76c16SMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
17912df76c16SMatt Jacob 			bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREREAD);
17922df76c16SMatt Jacob 			ddir = ISP_FROM_DEVICE;
17932df76c16SMatt Jacob 		} else if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
17942df76c16SMatt Jacob 			bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREWRITE);
17952df76c16SMatt Jacob 			ddir = ISP_TO_DEVICE;
17962df76c16SMatt Jacob 		} else {
17972df76c16SMatt Jacob 			ddir = ISP_NOXFR;
17982df76c16SMatt Jacob 		}
17992df76c16SMatt Jacob 	} else {
18002df76c16SMatt Jacob 		dm_segs = NULL;
18012df76c16SMatt Jacob 		nseg = 0;
18022df76c16SMatt Jacob 		ddir = ISP_NOXFR;
1803d720e6d5SJustin T. Gibbs 	}
1804d720e6d5SJustin T. Gibbs 
18052df76c16SMatt Jacob 	if (isp_send_cmd(isp, rq, dm_segs, nseg, XS_XFRLEN(csio), ddir) != CMD_QUEUED) {
18062df76c16SMatt Jacob 		mp->error = MUSHERR_NOQENTRIES;
18072df76c16SMatt Jacob 	}
18082df76c16SMatt Jacob }
18092df76c16SMatt Jacob 
1810d720e6d5SJustin T. Gibbs static int
18112df76c16SMatt Jacob isp_pci_dmasetup(ispsoftc_t *isp, struct ccb_scsiio *csio, void *ff)
1812d720e6d5SJustin T. Gibbs {
1813d720e6d5SJustin T. Gibbs 	mush_t mush, *mp;
1814126ec864SMatt Jacob 	void (*eptr)(void *, bus_dma_segment_t *, int, int);
18152df76c16SMatt Jacob 	void (*eptr2)(void *, bus_dma_segment_t *, int, bus_size_t, int);
1816d720e6d5SJustin T. Gibbs 
18172df76c16SMatt Jacob 	mp = &mush;
18182df76c16SMatt Jacob 	mp->isp = isp;
18192df76c16SMatt Jacob 	mp->cmd_token = csio;
18202df76c16SMatt Jacob 	mp->rq = ff;
18212df76c16SMatt Jacob 	mp->error = 0;
18222df76c16SMatt Jacob 	mp->mapsize = 0;
18232df76c16SMatt Jacob 
182465b024e1SMatt Jacob #ifdef	ISP_TARGET_MODE
182565b024e1SMatt Jacob 	if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) {
18262df76c16SMatt Jacob 		eptr = tdma2;
18272df76c16SMatt Jacob 		eptr2 = tdma2_2;
182865b024e1SMatt Jacob 	} else
182965b024e1SMatt Jacob #endif
18302df76c16SMatt Jacob 	{
183165b024e1SMatt Jacob 		eptr = dma2;
18322df76c16SMatt Jacob 		eptr2 = dma2_2;
18331dae40ebSMatt Jacob 	}
183465b024e1SMatt Jacob 
18354fd13c1bSMatt Jacob 
18362df76c16SMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || (csio->dxfer_len == 0)) {
18372df76c16SMatt Jacob 		(*eptr)(mp, NULL, 0, 0);
18382df76c16SMatt Jacob 	} else if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
18399e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) {
18400a70657fSMatt Jacob 			int error;
18412df76c16SMatt Jacob 			error = bus_dmamap_load(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, csio->data_ptr, csio->dxfer_len, eptr, mp, 0);
18422df76c16SMatt Jacob #if 0
18432df76c16SMatt Jacob 			xpt_print(csio->ccb_h.path, "%s: bus_dmamap_load " "ptr %p len %d returned %d\n", __func__, csio->data_ptr, csio->dxfer_len, error);
18440a70657fSMatt Jacob #endif
18452df76c16SMatt Jacob 
1846d720e6d5SJustin T. Gibbs 			if (error == EINPROGRESS) {
18472df76c16SMatt Jacob 				bus_dmamap_unload(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap);
1848d720e6d5SJustin T. Gibbs 				mp->error = EINVAL;
18492df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "deferred dma allocation not supported");
1850d720e6d5SJustin T. Gibbs 			} else if (error && mp->error == 0) {
18510a5f7e8bSMatt Jacob #ifdef	DIAGNOSTIC
18522df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "error %d in dma mapping code", error);
18530a5f7e8bSMatt Jacob #endif
1854d720e6d5SJustin T. Gibbs 				mp->error = error;
1855d720e6d5SJustin T. Gibbs 			}
1856d720e6d5SJustin T. Gibbs 		} else {
1857d720e6d5SJustin T. Gibbs 			/* Pointer to physical buffer */
1858d720e6d5SJustin T. Gibbs 			struct bus_dma_segment seg;
18596de9bf77SMatt Jacob 			seg.ds_addr = (bus_addr_t)(vm_offset_t)csio->data_ptr;
1860d720e6d5SJustin T. Gibbs 			seg.ds_len = csio->dxfer_len;
18619e11e5beSMatt Jacob 			(*eptr)(mp, &seg, 1, 0);
1862d720e6d5SJustin T. Gibbs 		}
1863d720e6d5SJustin T. Gibbs 	} else {
1864d720e6d5SJustin T. Gibbs 		struct bus_dma_segment *segs;
1865d720e6d5SJustin T. Gibbs 
18669e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) {
18672df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "Physical segment pointers unsupported");
1868d720e6d5SJustin T. Gibbs 			mp->error = EINVAL;
18699e11e5beSMatt Jacob 		} else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) {
18702df76c16SMatt Jacob 			struct uio sguio;
18712df76c16SMatt Jacob 			int error;
18722df76c16SMatt Jacob 
18732df76c16SMatt Jacob 			/*
18742df76c16SMatt Jacob 			 * We're taking advantage of the fact that
18752df76c16SMatt Jacob 			 * the pointer/length sizes and layout of the iovec
18762df76c16SMatt Jacob 			 * structure are the same as the bus_dma_segment
18772df76c16SMatt Jacob 			 * structure.  This might be a little dangerous,
18782df76c16SMatt Jacob 			 * but only if they change the structures, which
18792df76c16SMatt Jacob 			 * seems unlikely.
18802df76c16SMatt Jacob 			 */
18812df76c16SMatt Jacob 			KASSERT((sizeof (sguio.uio_iov) == sizeof (csio->data_ptr) &&
18822df76c16SMatt Jacob 			    sizeof (sguio.uio_iovcnt) >= sizeof (csio->sglist_cnt) &&
18832df76c16SMatt Jacob 			    sizeof (sguio.uio_resid) >= sizeof (csio->dxfer_len)), ("Ken's assumption failed"));
18842df76c16SMatt Jacob 			sguio.uio_iov = (struct iovec *)csio->data_ptr;
18852df76c16SMatt Jacob 			sguio.uio_iovcnt = csio->sglist_cnt;
18862df76c16SMatt Jacob 			sguio.uio_resid = csio->dxfer_len;
18872df76c16SMatt Jacob 			sguio.uio_segflg = UIO_SYSSPACE;
18882df76c16SMatt Jacob 
18892df76c16SMatt Jacob 			error = bus_dmamap_load_uio(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, &sguio, eptr2, mp, 0);
18902df76c16SMatt Jacob 
18912df76c16SMatt Jacob 			if (error != 0 && mp->error == 0) {
18922df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "error %d in dma mapping code", error);
18932df76c16SMatt Jacob 				mp->error = error;
18942df76c16SMatt Jacob 			}
1895d720e6d5SJustin T. Gibbs 		} else {
1896d720e6d5SJustin T. Gibbs 			/* Just use the segments provided */
1897d720e6d5SJustin T. Gibbs 			segs = (struct bus_dma_segment *) csio->data_ptr;
18989e11e5beSMatt Jacob 			(*eptr)(mp, segs, csio->sglist_cnt, 0);
1899d720e6d5SJustin T. Gibbs 		}
1900d720e6d5SJustin T. Gibbs 	}
1901d720e6d5SJustin T. Gibbs 	if (mp->error) {
19024873663cSMatt Jacob 		int retval = CMD_COMPLETE;
19034873663cSMatt Jacob 		if (mp->error == MUSHERR_NOQENTRIES) {
19044873663cSMatt Jacob 			retval = CMD_EAGAIN;
19054873663cSMatt Jacob 		} else if (mp->error == EFBIG) {
19060a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_REQ_TOO_BIG);
1907d720e6d5SJustin T. Gibbs 		} else if (mp->error == EINVAL) {
19080a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_REQ_INVALID);
1909d720e6d5SJustin T. Gibbs 		} else {
19100a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_UNREC_HBA_ERROR);
1911d720e6d5SJustin T. Gibbs 		}
19124873663cSMatt Jacob 		return (retval);
19130a5f7e8bSMatt Jacob 	}
19144873663cSMatt Jacob 	return (CMD_QUEUED);
1915d720e6d5SJustin T. Gibbs }
1916d720e6d5SJustin T. Gibbs 
1917d720e6d5SJustin T. Gibbs static void
19183bda7a83SMatt Jacob isp_pci_reset0(ispsoftc_t *isp)
19193bda7a83SMatt Jacob {
19203bda7a83SMatt Jacob 	ISP_DISABLE_INTS(isp);
19213bda7a83SMatt Jacob }
19223bda7a83SMatt Jacob 
19233bda7a83SMatt Jacob static void
19249cd7268eSMatt Jacob isp_pci_reset1(ispsoftc_t *isp)
192565adb54cSMatt Jacob {
192610365e5aSMatt Jacob 	if (!IS_24XX(isp)) {
192765adb54cSMatt Jacob 		/* Make sure the BIOS is disabled */
192865adb54cSMatt Jacob 		isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS);
192910365e5aSMatt Jacob 	}
1930469b6b9eSMatt Jacob 	/* and enable interrupts */
193110365e5aSMatt Jacob 	ISP_ENABLE_INTS(isp);
193265adb54cSMatt Jacob }
193365adb54cSMatt Jacob 
193465adb54cSMatt Jacob static void
19359cd7268eSMatt Jacob isp_pci_dumpregs(ispsoftc_t *isp, const char *msg)
193665adb54cSMatt Jacob {
19371923f739SMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp;
1938d02373f1SMatt Jacob 	if (msg)
19396e5c5328SMatt Jacob 		printf("%s: %s\n", device_get_nameunit(isp->isp_dev), msg);
19406e5c5328SMatt Jacob 	else
19416e5c5328SMatt Jacob 		printf("%s:\n", device_get_nameunit(isp->isp_dev));
1942d02373f1SMatt Jacob 	if (IS_SCSI(isp))
1943d02373f1SMatt Jacob 		printf("    biu_conf1=%x", ISP_READ(isp, BIU_CONF1));
1944d02373f1SMatt Jacob 	else
1945d02373f1SMatt Jacob 		printf("    biu_csr=%x", ISP_READ(isp, BIU2100_CSR));
1946d02373f1SMatt Jacob 	printf(" biu_icr=%x biu_isr=%x biu_sema=%x ", ISP_READ(isp, BIU_ICR),
1947d02373f1SMatt Jacob 	    ISP_READ(isp, BIU_ISR), ISP_READ(isp, BIU_SEMA));
1948d02373f1SMatt Jacob 	printf("risc_hccr=%x\n", ISP_READ(isp, HCCR));
1949d02373f1SMatt Jacob 
1950d02373f1SMatt Jacob 
1951d02373f1SMatt Jacob 	if (IS_SCSI(isp)) {
1952d02373f1SMatt Jacob 		ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE);
1953d02373f1SMatt Jacob 		printf("    cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n",
1954d02373f1SMatt Jacob 			ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS),
1955d02373f1SMatt Jacob 			ISP_READ(isp, CDMA_FIFO_STS));
1956d02373f1SMatt Jacob 		printf("    ddma_conf=%x ddma_sts=%x ddma_fifostat=%x\n",
1957d02373f1SMatt Jacob 			ISP_READ(isp, DDMA_CONF), ISP_READ(isp, DDMA_STATUS),
1958d02373f1SMatt Jacob 			ISP_READ(isp, DDMA_FIFO_STS));
1959d02373f1SMatt Jacob 		printf("    sxp_int=%x sxp_gross=%x sxp(scsi_ctrl)=%x\n",
1960d02373f1SMatt Jacob 			ISP_READ(isp, SXP_INTERRUPT),
1961d02373f1SMatt Jacob 			ISP_READ(isp, SXP_GROSS_ERR),
1962d02373f1SMatt Jacob 			ISP_READ(isp, SXP_PINS_CTRL));
1963d02373f1SMatt Jacob 		ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE);
1964d02373f1SMatt Jacob 	}
1965d02373f1SMatt Jacob 	printf("    mbox regs: %x %x %x %x %x\n",
1966d02373f1SMatt Jacob 	    ISP_READ(isp, OUTMAILBOX0), ISP_READ(isp, OUTMAILBOX1),
1967d02373f1SMatt Jacob 	    ISP_READ(isp, OUTMAILBOX2), ISP_READ(isp, OUTMAILBOX3),
1968d02373f1SMatt Jacob 	    ISP_READ(isp, OUTMAILBOX4));
1969d02373f1SMatt Jacob 	printf("    PCI Status Command/Status=%x\n",
19701923f739SMatt Jacob 	    pci_read_config(pcs->pci_dev, PCIR_COMMAND, 1));
197165adb54cSMatt Jacob }
1972