xref: /freebsd/sys/dev/isp/isp_pci.c (revision 9e7d423d23c6e3ed8d9b55ff602843eb79fc1825)
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 
4917bc427dSMarius Strobl #ifdef __sparc64__
5017bc427dSMarius Strobl #include <dev/ofw/openfirm.h>
5117bc427dSMarius Strobl #include <machine/ofw_machdep.h>
5217bc427dSMarius Strobl #endif
5317bc427dSMarius 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 
275a959d921SMatt Jacob #ifndef        PCI_PRODUCT_QLOGIC_ISP5432
276a959d921SMatt Jacob #define        PCI_PRODUCT_QLOGIC_ISP5432      0x5432
277a959d921SMatt Jacob #endif
278a959d921SMatt Jacob 
279a959d921SMatt Jacob #define        PCI_QLOGIC_ISP5432      \
280a959d921SMatt Jacob        ((PCI_PRODUCT_QLOGIC_ISP5432 << 16) | PCI_VENDOR_QLOGIC)
2819a5af410SMatt Jacob 
28256aef503SMatt Jacob #define	PCI_QLOGIC_ISP1020	\
28356aef503SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC)
284d59bd469SMatt Jacob 
285d59bd469SMatt Jacob #define	PCI_QLOGIC_ISP1080	\
286d59bd469SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC)
287d59bd469SMatt Jacob 
288f556e83bSMatt Jacob #define	PCI_QLOGIC_ISP10160	\
289f556e83bSMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP10160 << 16) | PCI_VENDOR_QLOGIC)
290f556e83bSMatt Jacob 
291960f6939SMatt Jacob #define	PCI_QLOGIC_ISP12160	\
292960f6939SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP12160 << 16) | PCI_VENDOR_QLOGIC)
293960f6939SMatt Jacob 
294d59bd469SMatt Jacob #define	PCI_QLOGIC_ISP1240	\
295d59bd469SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC)
296d59bd469SMatt Jacob 
29722e1dc85SMatt Jacob #define	PCI_QLOGIC_ISP1280	\
29822e1dc85SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1280 << 16) | PCI_VENDOR_QLOGIC)
29922e1dc85SMatt Jacob 
30065adb54cSMatt Jacob #define	PCI_QLOGIC_ISP2100	\
30165adb54cSMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC)
30265adb54cSMatt Jacob 
303222bb542SMatt Jacob #define	PCI_QLOGIC_ISP2200	\
304222bb542SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2200 << 16) | PCI_VENDOR_QLOGIC)
305222bb542SMatt Jacob 
306126ec864SMatt Jacob #define	PCI_QLOGIC_ISP2300	\
307126ec864SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2300 << 16) | PCI_VENDOR_QLOGIC)
308126ec864SMatt Jacob 
309126ec864SMatt Jacob #define	PCI_QLOGIC_ISP2312	\
310126ec864SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2312 << 16) | PCI_VENDOR_QLOGIC)
311126ec864SMatt Jacob 
312e5265237SMatt Jacob #define	PCI_QLOGIC_ISP2322	\
313e5265237SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2322 << 16) | PCI_VENDOR_QLOGIC)
314e5265237SMatt Jacob 
3156c426685SMatt Jacob #define	PCI_QLOGIC_ISP2422	\
3166c426685SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2422 << 16) | PCI_VENDOR_QLOGIC)
3176c426685SMatt Jacob 
31841675df0SMatt Jacob #define	PCI_QLOGIC_ISP2432	\
31941675df0SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2432 << 16) | PCI_VENDOR_QLOGIC)
32041675df0SMatt Jacob 
3212df76c16SMatt Jacob #define	PCI_QLOGIC_ISP2532	\
3222df76c16SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2532 << 16) | PCI_VENDOR_QLOGIC)
3232df76c16SMatt Jacob 
324dd1419abSMatt Jacob #define	PCI_QLOGIC_ISP6312	\
325dd1419abSMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP6312 << 16) | PCI_VENDOR_QLOGIC)
326dd1419abSMatt Jacob 
3279a5af410SMatt Jacob #define	PCI_QLOGIC_ISP6322	\
3289a5af410SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP6322 << 16) | PCI_VENDOR_QLOGIC)
3299a5af410SMatt Jacob 
330e11a1ee8SMatt Jacob /*
331e11a1ee8SMatt Jacob  * Odd case for some AMI raid cards... We need to *not* attach to this.
332e11a1ee8SMatt Jacob  */
333e11a1ee8SMatt Jacob #define	AMI_RAID_SUBVENDOR_ID	0x101e
334e11a1ee8SMatt Jacob 
33565adb54cSMatt Jacob #define	IO_MAP_REG	0x10
33665adb54cSMatt Jacob #define	MEM_MAP_REG	0x14
33765adb54cSMatt Jacob 
338d951bbcaSMatt Jacob #define	PCI_DFLT_LTNCY	0x40
339d951bbcaSMatt Jacob #define	PCI_DFLT_LNSZ	0x10
34065adb54cSMatt Jacob 
341960f6939SMatt Jacob static int isp_pci_probe (device_t);
342960f6939SMatt Jacob static int isp_pci_attach (device_t);
34310365e5aSMatt Jacob static int isp_pci_detach (device_t);
34465adb54cSMatt Jacob 
3451923f739SMatt Jacob 
3460230a28bSMatt Jacob #define	ISP_PCD(isp)	((struct isp_pcisoftc *)isp)->pci_dev
34765adb54cSMatt Jacob struct isp_pcisoftc {
3489cd7268eSMatt Jacob 	ispsoftc_t			pci_isp;
349960f6939SMatt Jacob 	device_t			pci_dev;
350e95725cbSMatt Jacob 	struct resource *		regs;
351e95725cbSMatt Jacob 	void *				irq;
352e95725cbSMatt Jacob 	int				iqd;
353e95725cbSMatt Jacob 	int				rtp;
354e95725cbSMatt Jacob 	int				rgd;
355960f6939SMatt Jacob 	void *				ih;
356d59bd469SMatt Jacob 	int16_t				pci_poff[_NREG_BLKS];
3571923f739SMatt Jacob 	bus_dma_tag_t			dmat;
3580a70657fSMatt Jacob 	int				msicount;
35965adb54cSMatt Jacob };
36065adb54cSMatt Jacob 
36110365e5aSMatt Jacob 
362960f6939SMatt Jacob static device_method_t isp_pci_methods[] = {
363960f6939SMatt Jacob 	/* Device interface */
364960f6939SMatt Jacob 	DEVMETHOD(device_probe,		isp_pci_probe),
365960f6939SMatt Jacob 	DEVMETHOD(device_attach,	isp_pci_attach),
36610365e5aSMatt Jacob 	DEVMETHOD(device_detach,	isp_pci_detach),
367960f6939SMatt Jacob 	{ 0, 0 }
36865adb54cSMatt Jacob };
36965adb54cSMatt Jacob 
370960f6939SMatt Jacob static driver_t isp_pci_driver = {
371960f6939SMatt Jacob 	"isp", isp_pci_methods, sizeof (struct isp_pcisoftc)
372960f6939SMatt Jacob };
373960f6939SMatt Jacob static devclass_t isp_devclass;
374960f6939SMatt Jacob DRIVER_MODULE(isp, pci, isp_pci_driver, isp_devclass, 0, 0);
375d45ce511SEitan Adler MODULE_DEPEND(isp, cam, 1, 1, 1);
376d45ce511SEitan Adler MODULE_DEPEND(isp, firmware, 1, 1, 1);
377*9e7d423dSMatt Jacob static int isp_nvports = 0;
37865adb54cSMatt Jacob 
379960f6939SMatt Jacob static int
380960f6939SMatt Jacob isp_pci_probe(device_t dev)
38165adb54cSMatt Jacob {
382960f6939SMatt Jacob 	switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) {
38356aef503SMatt Jacob 	case PCI_QLOGIC_ISP1020:
384960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1020/1040 PCI SCSI Adapter");
38565adb54cSMatt Jacob 		break;
386d59bd469SMatt Jacob 	case PCI_QLOGIC_ISP1080:
387960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1080 PCI SCSI Adapter");
388c6608df3SMatt Jacob 		break;
389c6608df3SMatt Jacob 	case PCI_QLOGIC_ISP1240:
390960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1240 PCI SCSI Adapter");
391d59bd469SMatt Jacob 		break;
39222e1dc85SMatt Jacob 	case PCI_QLOGIC_ISP1280:
393960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1280 PCI SCSI Adapter");
394960f6939SMatt Jacob 		break;
395f556e83bSMatt Jacob 	case PCI_QLOGIC_ISP10160:
396f556e83bSMatt Jacob 		device_set_desc(dev, "Qlogic ISP 10160 PCI SCSI Adapter");
397f556e83bSMatt Jacob 		break;
398960f6939SMatt Jacob 	case PCI_QLOGIC_ISP12160:
399e11a1ee8SMatt Jacob 		if (pci_get_subvendor(dev) == AMI_RAID_SUBVENDOR_ID) {
400e11a1ee8SMatt Jacob 			return (ENXIO);
401e11a1ee8SMatt Jacob 		}
402960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 12160 PCI SCSI Adapter");
40322e1dc85SMatt Jacob 		break;
40465adb54cSMatt Jacob 	case PCI_QLOGIC_ISP2100:
405960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2100 PCI FC-AL Adapter");
40665adb54cSMatt Jacob 		break;
4075542fe4bSMatt Jacob 	case PCI_QLOGIC_ISP2200:
408960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2200 PCI FC-AL Adapter");
4095542fe4bSMatt Jacob 		break;
410126ec864SMatt Jacob 	case PCI_QLOGIC_ISP2300:
411126ec864SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2300 PCI FC-AL Adapter");
412126ec864SMatt Jacob 		break;
413126ec864SMatt Jacob 	case PCI_QLOGIC_ISP2312:
414126ec864SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2312 PCI FC-AL Adapter");
415126ec864SMatt Jacob 		break;
416e5265237SMatt Jacob 	case PCI_QLOGIC_ISP2322:
417e5265237SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2322 PCI FC-AL Adapter");
418e5265237SMatt Jacob 		break;
4198872e3d7SMatt Jacob 	case PCI_QLOGIC_ISP2422:
4208872e3d7SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2422 PCI FC-AL Adapter");
4218872e3d7SMatt Jacob 		break;
42241675df0SMatt Jacob 	case PCI_QLOGIC_ISP2432:
42341675df0SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2432 PCI FC-AL Adapter");
42441675df0SMatt Jacob 		break;
4252df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2532:
4262df76c16SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2532 PCI FC-AL Adapter");
4272df76c16SMatt Jacob 		break;
428a959d921SMatt Jacob 	case PCI_QLOGIC_ISP5432:
429a959d921SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 5432 PCI FC-AL Adapter");
430a959d921SMatt Jacob 		break;
431dd1419abSMatt Jacob 	case PCI_QLOGIC_ISP6312:
432dd1419abSMatt Jacob 		device_set_desc(dev, "Qlogic ISP 6312 PCI FC-AL Adapter");
433dd1419abSMatt Jacob 		break;
4349a5af410SMatt Jacob 	case PCI_QLOGIC_ISP6322:
4359a5af410SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 6322 PCI FC-AL Adapter");
4369a5af410SMatt Jacob 		break;
43765adb54cSMatt Jacob 	default:
438960f6939SMatt Jacob 		return (ENXIO);
43965adb54cSMatt Jacob 	}
44073030e03SMatt Jacob 	if (isp_announced == 0 && bootverbose) {
441d02373f1SMatt Jacob 		printf("Qlogic ISP Driver, FreeBSD Version %d.%d, "
442a95ae193SMatt Jacob 		    "Core Version %d.%d\n",
443d720e6d5SJustin T. Gibbs 		    ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR,
444d720e6d5SJustin T. Gibbs 		    ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR);
44573030e03SMatt Jacob 		isp_announced++;
44665adb54cSMatt Jacob 	}
44756aef503SMatt Jacob 	/*
44856aef503SMatt Jacob 	 * XXXX: Here is where we might load the f/w module
44956aef503SMatt Jacob 	 * XXXX: (or increase a reference count to it).
45056aef503SMatt Jacob 	 */
451b77e575eSWarner Losh 	return (BUS_PROBE_DEFAULT);
45265adb54cSMatt Jacob }
45365adb54cSMatt Jacob 
4549cd7268eSMatt Jacob static void
455*9e7d423dSMatt Jacob isp_get_generic_options(device_t dev, ispsoftc_t *isp)
4569cd7268eSMatt Jacob {
4579cd7268eSMatt Jacob 	int tval;
458f7c631bcSMatt Jacob 
459222bb542SMatt Jacob 	/*
4609ba86737SMatt Jacob 	 * Figure out if we're supposed to skip this one.
4619ba86737SMatt Jacob 	 */
4626e5c5328SMatt Jacob 	tval = 0;
4632df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "disable", &tval) == 0 && tval) {
4649cd7268eSMatt Jacob 		device_printf(dev, "disabled at user request\n");
4659cd7268eSMatt Jacob 		isp->isp_osinfo.disabled = 1;
4669cd7268eSMatt Jacob 		return;
467b9b599feSMatt Jacob 	}
4686e5c5328SMatt Jacob 
4699cd7268eSMatt Jacob 	tval = 0;
4702df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "fwload_disable", &tval) == 0 && tval != 0) {
4719cd7268eSMatt Jacob 		isp->isp_confopts |= ISP_CFG_NORELOAD;
4729cd7268eSMatt Jacob 	}
4739cd7268eSMatt Jacob 	tval = 0;
4742df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "ignore_nvram", &tval) == 0 && tval != 0) {
4759cd7268eSMatt Jacob 		isp->isp_confopts |= ISP_CFG_NONVRAM;
4769cd7268eSMatt Jacob 	}
477336b5612SMatt Jacob 	tval = 0;
4782df76c16SMatt Jacob 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev), "debug", &tval);
479336b5612SMatt Jacob 	if (tval) {
480336b5612SMatt Jacob 		isp->isp_dblev = tval;
481336b5612SMatt Jacob 	} else {
482336b5612SMatt Jacob 		isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR;
483336b5612SMatt Jacob 	}
484336b5612SMatt Jacob 	if (bootverbose) {
485336b5612SMatt Jacob 		isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO;
486336b5612SMatt Jacob 	}
487*9e7d423dSMatt Jacob 	tval = -1;
4882df76c16SMatt Jacob 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev), "vports", &tval);
4892df76c16SMatt Jacob 	if (tval > 0 && tval < 127) {
490*9e7d423dSMatt Jacob 		isp_nvports = tval;
4912df76c16SMatt Jacob 	}
4922df76c16SMatt Jacob 	tval = 1;
4932df76c16SMatt Jacob 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev), "autoconfig", &tval);
4942df76c16SMatt Jacob 	isp_autoconfig = tval;
4952df76c16SMatt Jacob 	tval = 7;
4962df76c16SMatt Jacob 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev), "quickboot_time", &tval);
4972df76c16SMatt Jacob 	isp_quickboot_time = tval;
498336b5612SMatt Jacob }
499336b5612SMatt Jacob 
500336b5612SMatt Jacob static void
501336b5612SMatt Jacob isp_get_pci_options(device_t dev, int *m1, int *m2)
502336b5612SMatt Jacob {
503336b5612SMatt Jacob 	int tval;
504336b5612SMatt Jacob 	/*
505336b5612SMatt Jacob 	 * Which we should try first - memory mapping or i/o mapping?
506336b5612SMatt Jacob 	 *
507336b5612SMatt Jacob 	 * We used to try memory first followed by i/o on alpha, otherwise
508336b5612SMatt Jacob 	 * the reverse, but we should just try memory first all the time now.
509336b5612SMatt Jacob 	 */
510336b5612SMatt Jacob 	*m1 = PCIM_CMD_MEMEN;
511336b5612SMatt Jacob 	*m2 = PCIM_CMD_PORTEN;
512336b5612SMatt Jacob 
513336b5612SMatt Jacob 	tval = 0;
5142df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "prefer_iomap", &tval) == 0 && tval != 0) {
515336b5612SMatt Jacob 		*m1 = PCIM_CMD_PORTEN;
516336b5612SMatt Jacob 		*m2 = PCIM_CMD_MEMEN;
517336b5612SMatt Jacob 	}
518336b5612SMatt Jacob 	tval = 0;
5192df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "prefer_memmap", &tval) == 0 && tval != 0) {
520336b5612SMatt Jacob 		*m1 = PCIM_CMD_MEMEN;
521336b5612SMatt Jacob 		*m2 = PCIM_CMD_PORTEN;
522336b5612SMatt Jacob 	}
523336b5612SMatt Jacob }
524336b5612SMatt Jacob 
525336b5612SMatt Jacob static void
5262df76c16SMatt Jacob isp_get_specific_options(device_t dev, int chan, ispsoftc_t *isp)
527336b5612SMatt Jacob {
528336b5612SMatt Jacob 	const char *sptr;
529*9e7d423dSMatt Jacob 	int tval = 0;
530336b5612SMatt Jacob 
5312df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "iid", &tval)) {
5322df76c16SMatt Jacob 		if (IS_FC(isp)) {
5332df76c16SMatt Jacob 			ISP_FC_PC(isp, chan)->default_id = 109 - chan;
5342df76c16SMatt Jacob 		} else {
53517bc427dSMarius Strobl #ifdef __sparc64__
53617bc427dSMarius Strobl 			ISP_SPI_PC(isp, chan)->iid = OF_getscsinitid(dev);
53717bc427dSMarius Strobl #else
5382df76c16SMatt Jacob 			ISP_SPI_PC(isp, chan)->iid = 7;
53917bc427dSMarius Strobl #endif
5402df76c16SMatt Jacob 		}
5412df76c16SMatt Jacob 	} else {
5422df76c16SMatt Jacob 		if (IS_FC(isp)) {
5432df76c16SMatt Jacob 			ISP_FC_PC(isp, chan)->default_id = tval - chan;
5442df76c16SMatt Jacob 		} else {
5452df76c16SMatt Jacob 			ISP_SPI_PC(isp, chan)->iid = tval;
5462df76c16SMatt Jacob 		}
547336b5612SMatt Jacob 		isp->isp_confopts |= ISP_CFG_OWNLOOPID;
548336b5612SMatt Jacob 	}
5492df76c16SMatt Jacob 
5502df76c16SMatt Jacob 	tval = -1;
5512df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "role", &tval) == 0) {
5522df76c16SMatt Jacob 		switch (tval) {
5532df76c16SMatt Jacob 		case ISP_ROLE_NONE:
5542df76c16SMatt Jacob 		case ISP_ROLE_INITIATOR:
5552df76c16SMatt Jacob 		case ISP_ROLE_TARGET:
5562df76c16SMatt Jacob 		case ISP_ROLE_INITIATOR|ISP_ROLE_TARGET:
5572df76c16SMatt Jacob 			device_printf(dev, "setting role to 0x%x\n", tval);
5582df76c16SMatt Jacob 			break;
5592df76c16SMatt Jacob 		default:
5602df76c16SMatt Jacob 			tval = -1;
5612df76c16SMatt Jacob 			break;
562336b5612SMatt Jacob 		}
563336b5612SMatt Jacob 	}
5642df76c16SMatt Jacob 	if (tval == -1) {
5652df76c16SMatt Jacob 		tval = ISP_DEFAULT_ROLES;
5662df76c16SMatt Jacob 	}
567336b5612SMatt Jacob 
568336b5612SMatt Jacob 	if (IS_SCSI(isp)) {
5694ecb1d4aSMatt Jacob 		ISP_SPI_PC(isp, chan)->def_role = tval;
570336b5612SMatt Jacob 		return;
571336b5612SMatt Jacob 	}
5724ecb1d4aSMatt Jacob 	ISP_FC_PC(isp, chan)->def_role = tval;
573336b5612SMatt Jacob 
5749cd7268eSMatt Jacob 	tval = 0;
5752df76c16SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "fullduplex", &tval) == 0 && tval != 0) {
5769cd7268eSMatt Jacob 		isp->isp_confopts |= ISP_CFG_FULL_DUPLEX;
5779cd7268eSMatt Jacob 	}
5789cd7268eSMatt Jacob 	sptr = 0;
5792df76c16SMatt Jacob 	if (resource_string_value(device_get_name(dev), device_get_unit(dev), "topology", (const char **) &sptr) == 0 && sptr != 0) {
5809cd7268eSMatt Jacob 		if (strcmp(sptr, "lport") == 0) {
5819cd7268eSMatt Jacob 			isp->isp_confopts |= ISP_CFG_LPORT;
5829cd7268eSMatt Jacob 		} else if (strcmp(sptr, "nport") == 0) {
5839cd7268eSMatt Jacob 			isp->isp_confopts |= ISP_CFG_NPORT;
5849cd7268eSMatt Jacob 		} else if (strcmp(sptr, "lport-only") == 0) {
5859cd7268eSMatt Jacob 			isp->isp_confopts |= ISP_CFG_LPORT_ONLY;
5869cd7268eSMatt Jacob 		} else if (strcmp(sptr, "nport-only") == 0) {
5879cd7268eSMatt Jacob 			isp->isp_confopts |= ISP_CFG_NPORT_ONLY;
5889cd7268eSMatt Jacob 		}
589960f6939SMatt Jacob 	}
590960f6939SMatt Jacob 
5919ba86737SMatt Jacob 	/*
5929cd7268eSMatt Jacob 	 * Because the resource_*_value functions can neither return
5939cd7268eSMatt Jacob 	 * 64 bit integer values, nor can they be directly coerced
5949cd7268eSMatt Jacob 	 * to interpret the right hand side of the assignment as
5959cd7268eSMatt Jacob 	 * you want them to interpret it, we have to force WWN
5969cd7268eSMatt Jacob 	 * hint replacement to specify WWN strings with a leading
5979cd7268eSMatt Jacob 	 * 'w' (e..g w50000000aaaa0001). Sigh.
5989cd7268eSMatt Jacob 	 */
5999cd7268eSMatt Jacob 	sptr = 0;
6002df76c16SMatt Jacob 	tval = resource_string_value(device_get_name(dev), device_get_unit(dev), "portwwn", (const char **) &sptr);
6019cd7268eSMatt Jacob 	if (tval == 0 && sptr != 0 && *sptr++ == 'w') {
6029cd7268eSMatt Jacob 		char *eptr = 0;
6032df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->def_wwpn = strtouq(sptr, &eptr, 16);
6042df76c16SMatt Jacob 		if (eptr < sptr + 16 || ISP_FC_PC(isp, chan)->def_wwpn == -1) {
6059cd7268eSMatt Jacob 			device_printf(dev, "mangled portwwn hint '%s'\n", sptr);
6062df76c16SMatt Jacob 			ISP_FC_PC(isp, chan)->def_wwpn = 0;
6079cd7268eSMatt Jacob 		}
6089cd7268eSMatt Jacob 	}
6099cd7268eSMatt Jacob 
6109cd7268eSMatt Jacob 	sptr = 0;
6112df76c16SMatt Jacob 	tval = resource_string_value(device_get_name(dev), device_get_unit(dev), "nodewwn", (const char **) &sptr);
6129cd7268eSMatt Jacob 	if (tval == 0 && sptr != 0 && *sptr++ == 'w') {
6139cd7268eSMatt Jacob 		char *eptr = 0;
6142df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->def_wwnn = strtouq(sptr, &eptr, 16);
6152df76c16SMatt Jacob 		if (eptr < sptr + 16 || ISP_FC_PC(isp, chan)->def_wwnn == 0) {
6169cd7268eSMatt Jacob 			device_printf(dev, "mangled nodewwn hint '%s'\n", sptr);
6172df76c16SMatt Jacob 			ISP_FC_PC(isp, chan)->def_wwnn = 0;
6189cd7268eSMatt Jacob 		}
6199cd7268eSMatt Jacob 	}
6209cd7268eSMatt Jacob 
62110365e5aSMatt Jacob 	tval = 0;
6222df76c16SMatt Jacob 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev), "hysteresis", &tval);
62310365e5aSMatt Jacob 	if (tval >= 0 && tval < 256) {
6242df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->hysteresis = tval;
62510365e5aSMatt Jacob 	} else {
6262df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->hysteresis = isp_fabric_hysteresis;
62710365e5aSMatt Jacob 	}
62810365e5aSMatt Jacob 
629f7c631bcSMatt Jacob 	tval = -1;
6302df76c16SMatt Jacob 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev), "loop_down_limit", &tval);
63110365e5aSMatt Jacob 	if (tval >= 0 && tval < 0xffff) {
6322df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->loop_down_limit = tval;
63310365e5aSMatt Jacob 	} else {
6342df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->loop_down_limit = isp_loop_down_limit;
63510365e5aSMatt Jacob 	}
63610365e5aSMatt Jacob 
637f7c631bcSMatt Jacob 	tval = -1;
6382df76c16SMatt Jacob 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev), "gone_device_time", &tval);
639f7c631bcSMatt Jacob 	if (tval >= 0 && tval < 0xffff) {
6402df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->gone_device_time = tval;
641f7c631bcSMatt Jacob 	} else {
6422df76c16SMatt Jacob 		ISP_FC_PC(isp, chan)->gone_device_time = isp_gone_device_time;
643f7c631bcSMatt Jacob 	}
6449cd7268eSMatt Jacob }
6459cd7268eSMatt Jacob 
6469cd7268eSMatt Jacob static int
6479cd7268eSMatt Jacob isp_pci_attach(device_t dev)
6489cd7268eSMatt Jacob {
649e95725cbSMatt Jacob 	int i, m1, m2, locksetup = 0;
6502df76c16SMatt Jacob 	uint32_t data, cmd, linesz, did;
6519cd7268eSMatt Jacob 	struct isp_pcisoftc *pcs;
652a035b0afSMatt Jacob 	ispsoftc_t *isp;
6532df76c16SMatt Jacob 	size_t psize, xsize;
6542df76c16SMatt Jacob 	char fwname[32];
6559cd7268eSMatt Jacob 
6569cd7268eSMatt Jacob 	pcs = device_get_softc(dev);
6579cd7268eSMatt Jacob 	if (pcs == NULL) {
6589cd7268eSMatt Jacob 		device_printf(dev, "cannot get softc\n");
6599cd7268eSMatt Jacob 		return (ENOMEM);
6609cd7268eSMatt Jacob 	}
6619cd7268eSMatt Jacob 	memset(pcs, 0, sizeof (*pcs));
6622df76c16SMatt Jacob 
6639cd7268eSMatt Jacob 	pcs->pci_dev = dev;
6649cd7268eSMatt Jacob 	isp = &pcs->pci_isp;
6652df76c16SMatt Jacob 	isp->isp_dev = dev;
6662df76c16SMatt Jacob 	isp->isp_nchan = 1;
6679cd7268eSMatt Jacob 
6689cd7268eSMatt Jacob 	/*
669336b5612SMatt Jacob 	 * Get Generic Options
6709cd7268eSMatt Jacob 	 */
671*9e7d423dSMatt Jacob 	isp_nvports = 0;
672*9e7d423dSMatt Jacob 	isp_get_generic_options(dev, isp);
6739cd7268eSMatt Jacob 
6749cd7268eSMatt Jacob 	/*
6759cd7268eSMatt Jacob 	 * Check to see if options have us disabled
6769cd7268eSMatt Jacob 	 */
6779cd7268eSMatt Jacob 	if (isp->isp_osinfo.disabled) {
6789cd7268eSMatt Jacob 		/*
6799cd7268eSMatt Jacob 		 * But return zero to preserve unit numbering
6809cd7268eSMatt Jacob 		 */
6819cd7268eSMatt Jacob 		return (0);
6829cd7268eSMatt Jacob 	}
6839cd7268eSMatt Jacob 
6849cd7268eSMatt Jacob 	/*
6859cd7268eSMatt Jacob 	 * Get PCI options- which in this case are just mapping preferences.
6869cd7268eSMatt Jacob 	 */
6879cd7268eSMatt Jacob 	isp_get_pci_options(dev, &m1, &m2);
6889cd7268eSMatt Jacob 
689ab6d0040SMatt Jacob 	linesz = PCI_DFLT_LNSZ;
690e95725cbSMatt Jacob 	pcs->irq = pcs->regs = NULL;
691e95725cbSMatt Jacob 	pcs->rgd = pcs->rtp = pcs->iqd = 0;
692960f6939SMatt Jacob 
693b49c4674SMatt Jacob 	cmd = pci_read_config(dev, PCIR_COMMAND, 2);
694960f6939SMatt Jacob 	if (cmd & m1) {
695e95725cbSMatt Jacob 		pcs->rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT;
696e95725cbSMatt Jacob 		pcs->rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG;
697e95725cbSMatt Jacob 		pcs->regs = bus_alloc_resource_any(dev, pcs->rtp, &pcs->rgd, RF_ACTIVE);
69865adb54cSMatt Jacob 	}
699e95725cbSMatt Jacob 	if (pcs->regs == NULL && (cmd & m2)) {
700e95725cbSMatt Jacob 		pcs->rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT;
701e95725cbSMatt Jacob 		pcs->rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG;
702e95725cbSMatt Jacob 		pcs->regs = bus_alloc_resource_any(dev, pcs->rtp, &pcs->rgd, RF_ACTIVE);
70365adb54cSMatt Jacob 	}
704e95725cbSMatt Jacob 	if (pcs->regs == NULL) {
705960f6939SMatt Jacob 		device_printf(dev, "unable to map any ports\n");
706960f6939SMatt Jacob 		goto bad;
70765adb54cSMatt Jacob 	}
7089cd7268eSMatt Jacob 	if (bootverbose) {
709e95725cbSMatt Jacob 		device_printf(dev, "using %s space register mapping\n", (pcs->rgd == IO_MAP_REG)? "I/O" : "Memory");
7109cd7268eSMatt Jacob 	}
711e95725cbSMatt Jacob 	isp->isp_bus_tag = rman_get_bustag(pcs->regs);
712e95725cbSMatt Jacob 	isp->isp_bus_handle = rman_get_bushandle(pcs->regs);
71365adb54cSMatt Jacob 
7142df76c16SMatt Jacob 	pcs->pci_dev = dev;
715d59bd469SMatt Jacob 	pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF;
716d59bd469SMatt Jacob 	pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF;
717d59bd469SMatt Jacob 	pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF;
718d59bd469SMatt Jacob 	pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF;
719d59bd469SMatt Jacob 	pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF;
7202df76c16SMatt Jacob 
7212df76c16SMatt Jacob 	switch (pci_get_devid(dev)) {
7222df76c16SMatt Jacob 	case PCI_QLOGIC_ISP1020:
7232df76c16SMatt Jacob 		did = 0x1040;
7242df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec;
7252df76c16SMatt Jacob 		isp->isp_type = ISP_HA_SCSI_UNKNOWN;
7262df76c16SMatt Jacob 		break;
7272df76c16SMatt Jacob 	case PCI_QLOGIC_ISP1080:
7282df76c16SMatt Jacob 		did = 0x1080;
7292df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_1080;
7302df76c16SMatt Jacob 		isp->isp_type = ISP_HA_SCSI_1080;
7312df76c16SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = ISP1080_DMA_REGS_OFF;
7322df76c16SMatt Jacob 		break;
7332df76c16SMatt Jacob 	case PCI_QLOGIC_ISP1240:
7342df76c16SMatt Jacob 		did = 0x1080;
7352df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_1080;
7362df76c16SMatt Jacob 		isp->isp_type = ISP_HA_SCSI_1240;
7372df76c16SMatt Jacob 		isp->isp_nchan = 2;
7382df76c16SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = ISP1080_DMA_REGS_OFF;
7392df76c16SMatt Jacob 		break;
7402df76c16SMatt Jacob 	case PCI_QLOGIC_ISP1280:
7412df76c16SMatt Jacob 		did = 0x1080;
7422df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_1080;
7432df76c16SMatt Jacob 		isp->isp_type = ISP_HA_SCSI_1280;
7442df76c16SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = ISP1080_DMA_REGS_OFF;
7452df76c16SMatt Jacob 		break;
7462df76c16SMatt Jacob 	case PCI_QLOGIC_ISP10160:
7472df76c16SMatt Jacob 		did = 0x12160;
7482df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_12160;
7492df76c16SMatt Jacob 		isp->isp_type = ISP_HA_SCSI_10160;
7502df76c16SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = ISP1080_DMA_REGS_OFF;
7512df76c16SMatt Jacob 		break;
7522df76c16SMatt Jacob 	case PCI_QLOGIC_ISP12160:
7532df76c16SMatt Jacob 		did = 0x12160;
7542df76c16SMatt Jacob 		isp->isp_nchan = 2;
7552df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_12160;
7562df76c16SMatt Jacob 		isp->isp_type = ISP_HA_SCSI_12160;
7572df76c16SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = ISP1080_DMA_REGS_OFF;
7582df76c16SMatt Jacob 		break;
7592df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2100:
7602df76c16SMatt Jacob 		did = 0x2100;
7612df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_2100;
7622df76c16SMatt Jacob 		isp->isp_type = ISP_HA_FC_2100;
7632df76c16SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2100_OFF;
764960f6939SMatt Jacob 		if (pci_get_revid(dev) < 3) {
765ab6d0040SMatt Jacob 			/*
766ab6d0040SMatt Jacob 			 * XXX: Need to get the actual revision
767ab6d0040SMatt Jacob 			 * XXX: number of the 2100 FB. At any rate,
768ab6d0040SMatt Jacob 			 * XXX: lower cache line size for early revision
769ab6d0040SMatt Jacob 			 * XXX; boards.
770ab6d0040SMatt Jacob 			 */
771ab6d0040SMatt Jacob 			linesz = 1;
772ab6d0040SMatt Jacob 		}
7732df76c16SMatt Jacob 		break;
7742df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2200:
7752df76c16SMatt Jacob 		did = 0x2200;
7762df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_2200;
7772df76c16SMatt Jacob 		isp->isp_type = ISP_HA_FC_2200;
7782df76c16SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2100_OFF;
7792df76c16SMatt Jacob 		break;
7802df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2300:
7812df76c16SMatt Jacob 		did = 0x2300;
7822df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_2300;
7832df76c16SMatt Jacob 		isp->isp_type = ISP_HA_FC_2300;
7842df76c16SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2300_OFF;
7852df76c16SMatt Jacob 		break;
7862df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2312:
7872df76c16SMatt Jacob 	case PCI_QLOGIC_ISP6312:
7882df76c16SMatt Jacob 		did = 0x2300;
7892df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_2300;
7902df76c16SMatt Jacob 		isp->isp_type = ISP_HA_FC_2312;
7912df76c16SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2300_OFF;
7922df76c16SMatt Jacob 		break;
7932df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2322:
7942df76c16SMatt Jacob 	case PCI_QLOGIC_ISP6322:
7952df76c16SMatt Jacob 		did = 0x2322;
7962df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_2300;
7972df76c16SMatt Jacob 		isp->isp_type = ISP_HA_FC_2322;
7982df76c16SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2300_OFF;
7992df76c16SMatt Jacob 		break;
8002df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2422:
8012df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2432:
8022df76c16SMatt Jacob 		did = 0x2400;
8032df76c16SMatt Jacob 		isp->isp_nchan += isp_nvports;
8042df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_2400;
8052df76c16SMatt Jacob 		isp->isp_type = ISP_HA_FC_2400;
8062df76c16SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2400_OFF;
8072df76c16SMatt Jacob 		break;
8082df76c16SMatt Jacob 	case PCI_QLOGIC_ISP2532:
8092df76c16SMatt Jacob 		did = 0x2500;
8102df76c16SMatt Jacob 		isp->isp_nchan += isp_nvports;
8112df76c16SMatt Jacob 		isp->isp_mdvec = &mdvec_2500;
8122df76c16SMatt Jacob 		isp->isp_type = ISP_HA_FC_2500;
8132df76c16SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2400_OFF;
8142df76c16SMatt Jacob 		break;
815a959d921SMatt Jacob 	case PCI_QLOGIC_ISP5432:
816a959d921SMatt Jacob 		did = 0x2500;
817a959d921SMatt Jacob 		isp->isp_mdvec = &mdvec_2500;
818a959d921SMatt Jacob 		isp->isp_type = ISP_HA_FC_2500;
819a959d921SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2400_OFF;
820a959d921SMatt Jacob 		break;
8212df76c16SMatt Jacob 	default:
8222df76c16SMatt Jacob 		device_printf(dev, "unknown device type\n");
8232df76c16SMatt Jacob 		goto bad;
8242df76c16SMatt Jacob 		break;
82565adb54cSMatt Jacob 	}
8262df76c16SMatt Jacob 	isp->isp_revision = pci_get_revid(dev);
8272df76c16SMatt Jacob 
8282df76c16SMatt Jacob 	if (IS_FC(isp)) {
829222bb542SMatt Jacob 		psize = sizeof (fcparam);
8302df76c16SMatt Jacob 		xsize = sizeof (struct isp_fc);
8312df76c16SMatt Jacob 	} else {
8322df76c16SMatt Jacob 		psize = sizeof (sdparam);
8332df76c16SMatt Jacob 		xsize = sizeof (struct isp_spi);
834222bb542SMatt Jacob 	}
8352df76c16SMatt Jacob 	psize *= isp->isp_nchan;
8362df76c16SMatt Jacob 	xsize *= isp->isp_nchan;
8377cc0979fSDavid Malone 	isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT | M_ZERO);
838c6608df3SMatt Jacob 	if (isp->isp_param == NULL) {
839960f6939SMatt Jacob 		device_printf(dev, "cannot allocate parameter data\n");
840960f6939SMatt Jacob 		goto bad;
841c6608df3SMatt Jacob 	}
8422df76c16SMatt Jacob 	isp->isp_osinfo.pc.ptr = malloc(xsize, M_DEVBUF, M_NOWAIT | M_ZERO);
8432df76c16SMatt Jacob 	if (isp->isp_osinfo.pc.ptr == NULL) {
8442df76c16SMatt Jacob 		device_printf(dev, "cannot allocate parameter data\n");
8452df76c16SMatt Jacob 		goto bad;
8462df76c16SMatt Jacob 	}
84765adb54cSMatt Jacob 
848336b5612SMatt Jacob 	/*
849336b5612SMatt Jacob 	 * Now that we know who we are (roughly) get/set specific options
850336b5612SMatt Jacob 	 */
8512df76c16SMatt Jacob 	for (i = 0; i < isp->isp_nchan; i++) {
8522df76c16SMatt Jacob 		isp_get_specific_options(dev, i, isp);
8539a5af410SMatt Jacob 	}
8549a5af410SMatt Jacob 
8552df76c16SMatt Jacob 	/*
8562df76c16SMatt Jacob 	 * The 'it' suffix really only matters for SCSI cards in target mode.
8572df76c16SMatt Jacob 	 */
8589a5af410SMatt Jacob 	isp->isp_osinfo.fw = NULL;
8594ecb1d4aSMatt Jacob 	if (IS_SCSI(isp) && (ISP_SPI_PC(isp, 0)->def_role & ISP_ROLE_TARGET)) {
8609a5af410SMatt Jacob 		snprintf(fwname, sizeof (fwname), "isp_%04x_it", did);
8619a5af410SMatt Jacob 		isp->isp_osinfo.fw = firmware_get(fwname);
862ad0ab753SMatt Jacob 	} else if (IS_24XX(isp)) {
8632df76c16SMatt Jacob 		snprintf(fwname, sizeof (fwname), "isp_%04x_multi", did);
8642df76c16SMatt Jacob 		isp->isp_osinfo.fw = firmware_get(fwname);
8659a5af410SMatt Jacob 	}
8669a5af410SMatt Jacob 	if (isp->isp_osinfo.fw == NULL) {
8679a5af410SMatt Jacob 		snprintf(fwname, sizeof (fwname), "isp_%04x", did);
8689a5af410SMatt Jacob 		isp->isp_osinfo.fw = firmware_get(fwname);
8699a5af410SMatt Jacob 	}
8709a5af410SMatt Jacob 	if (isp->isp_osinfo.fw != NULL) {
871ad0ab753SMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, "loaded firmware %s", fwname);
8725f634111SMatt Jacob 		isp->isp_mdvec->dv_ispfw = isp->isp_osinfo.fw->data;
8739a5af410SMatt Jacob 	}
87456aef503SMatt Jacob 
87556aef503SMatt Jacob 	/*
876ad0ab753SMatt Jacob 	 * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER are set.
877d951bbcaSMatt Jacob 	 */
878*9e7d423dSMatt Jacob 	cmd |= PCIM_CMD_SEREN | PCIM_CMD_PERRESPEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_INVEN;
87975c1e828SMatt Jacob 	if (IS_2300(isp)) {	/* per QLogic errata */
88075c1e828SMatt Jacob 		cmd &= ~PCIM_CMD_INVEN;
88175c1e828SMatt Jacob 	}
8828a97c03aSMatt Jacob 	if (IS_2322(isp) || pci_get_devid(dev) == PCI_QLOGIC_ISP6312) {
8838a97c03aSMatt Jacob 		cmd &= ~PCIM_CMD_INTX_DISABLE;
8848a97c03aSMatt Jacob 	}
88506cacb29SMatt Jacob 	if (IS_24XX(isp)) {
88606cacb29SMatt Jacob 		cmd &= ~PCIM_CMD_INTX_DISABLE;
88706cacb29SMatt Jacob 	}
888b49c4674SMatt Jacob 	pci_write_config(dev, PCIR_COMMAND, cmd, 2);
889ab6d0040SMatt Jacob 
890d951bbcaSMatt Jacob 	/*
891222bb542SMatt Jacob 	 * Make sure the Cache Line Size register is set sensibly.
892d951bbcaSMatt Jacob 	 */
893960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_CACHELNSZ, 1);
8946a7d12e1SMatt Jacob 	if (data == 0 || (linesz != PCI_DFLT_LNSZ && data != linesz)) {
895ad0ab753SMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0, "set PCI line size to %d from %d", linesz, data);
8966a7d12e1SMatt Jacob 		data = linesz;
897960f6939SMatt Jacob 		pci_write_config(dev, PCIR_CACHELNSZ, data, 1);
898d951bbcaSMatt Jacob 	}
899ab6d0040SMatt Jacob 
900d951bbcaSMatt Jacob 	/*
901d951bbcaSMatt Jacob 	 * Make sure the Latency Timer is sane.
902d951bbcaSMatt Jacob 	 */
903960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_LATTIMER, 1);
904d951bbcaSMatt Jacob 	if (data < PCI_DFLT_LTNCY) {
905d951bbcaSMatt Jacob 		data = PCI_DFLT_LTNCY;
906ad0ab753SMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0, "set PCI latency to %d", data);
907960f6939SMatt Jacob 		pci_write_config(dev, PCIR_LATTIMER, data, 1);
908d951bbcaSMatt Jacob 	}
909ab6d0040SMatt Jacob 
910ab6d0040SMatt Jacob 	/*
911ab6d0040SMatt Jacob 	 * Make sure we've disabled the ROM.
912ab6d0040SMatt Jacob 	 */
913960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_ROMADDR, 4);
914ab6d0040SMatt Jacob 	data &= ~1;
915960f6939SMatt Jacob 	pci_write_config(dev, PCIR_ROMADDR, data, 4);
9162df76c16SMatt Jacob 
9172df76c16SMatt Jacob 	/*
9182df76c16SMatt Jacob 	 * Do MSI
9192df76c16SMatt Jacob 	 *
9202df76c16SMatt Jacob 	 * NB: MSI-X needs to be disabled for the 2432 (PCI-Express)
9212df76c16SMatt Jacob 	 */
9220a70657fSMatt Jacob 	if (IS_24XX(isp) || IS_2322(isp)) {
9230a70657fSMatt Jacob 		pcs->msicount = pci_msi_count(dev);
9240a70657fSMatt Jacob 		if (pcs->msicount > 1) {
9250a70657fSMatt Jacob 			pcs->msicount = 1;
9260a70657fSMatt Jacob 		}
9270a70657fSMatt Jacob 		if (pci_alloc_msi(dev, &pcs->msicount) == 0) {
928e95725cbSMatt Jacob 			pcs->iqd = 1;
9290a70657fSMatt Jacob 		} else {
930e95725cbSMatt Jacob 			pcs->iqd = 0;
9310a70657fSMatt Jacob 		}
9320a70657fSMatt Jacob 	}
933e95725cbSMatt Jacob 	pcs->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &pcs->iqd, RF_ACTIVE | RF_SHAREABLE);
934e95725cbSMatt Jacob 	if (pcs->irq == NULL) {
935960f6939SMatt Jacob 		device_printf(dev, "could not allocate interrupt\n");
936960f6939SMatt Jacob 		goto bad;
937960f6939SMatt Jacob 	}
938960f6939SMatt Jacob 
939f09b1922SMatt Jacob 	/* Make sure the lock is set up. */
9406008862bSJohn Baldwin 	mtx_init(&isp->isp_osinfo.lock, "isp", NULL, MTX_DEF);
941f09b1922SMatt Jacob 	locksetup++;
942f09b1922SMatt Jacob 
943e95725cbSMatt Jacob 	if (isp_setup_intr(dev, pcs->irq, ISP_IFLAGS, NULL, isp_platform_intr, isp, &pcs->ih)) {
944f09b1922SMatt Jacob 		device_printf(dev, "could not setup interrupt\n");
945f09b1922SMatt Jacob 		goto bad;
946f09b1922SMatt Jacob 	}
947960f6939SMatt Jacob 
94805fbcbb0SMatt Jacob 	/*
94975c1e828SMatt Jacob 	 * Last minute checks...
95075c1e828SMatt Jacob 	 */
95110365e5aSMatt Jacob 	if (IS_23XX(isp) || IS_24XX(isp)) {
95275c1e828SMatt Jacob 		isp->isp_port = pci_get_function(dev);
95375c1e828SMatt Jacob 	}
95475c1e828SMatt Jacob 
95575c1e828SMatt Jacob 	/*
95605fbcbb0SMatt Jacob 	 * Make sure we're in reset state.
95705fbcbb0SMatt Jacob 	 */
9583395b056SMatt Jacob 	ISP_LOCK(isp);
9592df76c16SMatt Jacob 	isp_reset(isp, 1);
96065adb54cSMatt Jacob 	if (isp->isp_state != ISP_RESETSTATE) {
9613395b056SMatt Jacob 		ISP_UNLOCK(isp);
962960f6939SMatt Jacob 		goto bad;
96365adb54cSMatt Jacob 	}
96465adb54cSMatt Jacob 	isp_init(isp);
9652df76c16SMatt Jacob 	if (isp->isp_state == ISP_INITSTATE) {
9662df76c16SMatt Jacob 		isp->isp_state = ISP_RUNSTATE;
9672df76c16SMatt Jacob 	}
9682df76c16SMatt Jacob 	ISP_UNLOCK(isp);
9692df76c16SMatt Jacob 	if (isp_attach(isp)) {
9702df76c16SMatt Jacob 		ISP_LOCK(isp);
97165adb54cSMatt Jacob 		isp_uninit(isp);
9723395b056SMatt Jacob 		ISP_UNLOCK(isp);
973960f6939SMatt Jacob 		goto bad;
974d59bd469SMatt Jacob 	}
975960f6939SMatt Jacob 	return (0);
976960f6939SMatt Jacob 
977960f6939SMatt Jacob bad:
978a035b0afSMatt Jacob 	if (pcs->ih) {
979e95725cbSMatt Jacob 		(void) bus_teardown_intr(dev, pcs->irq, pcs->ih);
980960f6939SMatt Jacob 	}
981a035b0afSMatt Jacob 	if (locksetup) {
9823395b056SMatt Jacob 		mtx_destroy(&isp->isp_osinfo.lock);
9833395b056SMatt Jacob 	}
984e95725cbSMatt Jacob 	if (pcs->irq) {
985e95725cbSMatt Jacob 		(void) bus_release_resource(dev, SYS_RES_IRQ, pcs->iqd, pcs->irq);
986960f6939SMatt Jacob 	}
987a035b0afSMatt Jacob 	if (pcs->msicount) {
9880a70657fSMatt Jacob 		pci_release_msi(dev);
9890a70657fSMatt Jacob 	}
990e95725cbSMatt Jacob 	if (pcs->regs) {
991e95725cbSMatt Jacob 		(void) bus_release_resource(dev, pcs->rtp, pcs->rgd, pcs->regs);
992960f6939SMatt Jacob 	}
9939cd7268eSMatt Jacob 	if (pcs->pci_isp.isp_param) {
994960f6939SMatt Jacob 		free(pcs->pci_isp.isp_param, M_DEVBUF);
9952df76c16SMatt Jacob 		pcs->pci_isp.isp_param = NULL;
9962df76c16SMatt Jacob 	}
9972df76c16SMatt Jacob 	if (pcs->pci_isp.isp_osinfo.pc.ptr) {
9982df76c16SMatt Jacob 		free(pcs->pci_isp.isp_osinfo.pc.ptr, M_DEVBUF);
9992df76c16SMatt Jacob 		pcs->pci_isp.isp_osinfo.pc.ptr = NULL;
10009cd7268eSMatt Jacob 	}
1001960f6939SMatt Jacob 	return (ENXIO);
100265adb54cSMatt Jacob }
100365adb54cSMatt Jacob 
100410365e5aSMatt Jacob static int
100510365e5aSMatt Jacob isp_pci_detach(device_t dev)
100610365e5aSMatt Jacob {
100710365e5aSMatt Jacob 	struct isp_pcisoftc *pcs;
100810365e5aSMatt Jacob 	ispsoftc_t *isp;
1009e95725cbSMatt Jacob 	int status;
101010365e5aSMatt Jacob 
101110365e5aSMatt Jacob 	pcs = device_get_softc(dev);
101210365e5aSMatt Jacob 	if (pcs == NULL) {
101310365e5aSMatt Jacob 		return (ENXIO);
101410365e5aSMatt Jacob 	}
101510365e5aSMatt Jacob 	isp = (ispsoftc_t *) pcs;
1016e95725cbSMatt Jacob 	status = isp_detach(isp);
1017e95725cbSMatt Jacob 	if (status)
1018e95725cbSMatt Jacob 		return (status);
1019e95725cbSMatt Jacob 	ISP_LOCK(isp);
1020e95725cbSMatt Jacob 	isp_uninit(isp);
1021e95725cbSMatt Jacob 	if (pcs->ih) {
1022e95725cbSMatt Jacob 		(void) bus_teardown_intr(dev, pcs->irq, pcs->ih);
1023e95725cbSMatt Jacob 	}
1024e95725cbSMatt Jacob 	ISP_UNLOCK(isp);
10252df76c16SMatt Jacob 	mtx_destroy(&isp->isp_osinfo.lock);
1026e95725cbSMatt Jacob 	(void) bus_release_resource(dev, SYS_RES_IRQ, pcs->iqd, pcs->irq);
1027e95725cbSMatt Jacob 	if (pcs->msicount) {
1028e95725cbSMatt Jacob 		pci_release_msi(dev);
1029e95725cbSMatt Jacob 	}
1030e95725cbSMatt Jacob 	(void) bus_release_resource(dev, pcs->rtp, pcs->rgd, pcs->regs);
1031e95725cbSMatt Jacob 	if (pcs->pci_isp.isp_param) {
1032e95725cbSMatt Jacob 		free(pcs->pci_isp.isp_param, M_DEVBUF);
1033e95725cbSMatt Jacob 		pcs->pci_isp.isp_param = NULL;
1034e95725cbSMatt Jacob 	}
1035e95725cbSMatt Jacob 	if (pcs->pci_isp.isp_osinfo.pc.ptr) {
1036e95725cbSMatt Jacob 		free(pcs->pci_isp.isp_osinfo.pc.ptr, M_DEVBUF);
1037e95725cbSMatt Jacob 		pcs->pci_isp.isp_osinfo.pc.ptr = NULL;
1038e95725cbSMatt Jacob 	}
103910365e5aSMatt Jacob 	return (0);
104010365e5aSMatt Jacob }
104110365e5aSMatt Jacob 
1042126ec864SMatt Jacob #define	IspVirt2Off(a, x)	\
1043126ec864SMatt Jacob 	(((struct isp_pcisoftc *)a)->pci_poff[((x) & _BLK_REG_MASK) >> \
10444cc9e3e7SMatt Jacob 	_BLK_REG_SHFT] + ((x) & 0xfff))
1045126ec864SMatt Jacob 
10466a7d12e1SMatt Jacob #define	BXR2(isp, off)		\
10476a7d12e1SMatt Jacob 	bus_space_read_2(isp->isp_bus_tag, isp->isp_bus_handle, off)
10486a7d12e1SMatt Jacob #define	BXW2(isp, off, v)	\
10496a7d12e1SMatt Jacob 	bus_space_write_2(isp->isp_bus_tag, isp->isp_bus_handle, off, v)
10506a7d12e1SMatt Jacob #define	BXR4(isp, off)		\
10516a7d12e1SMatt Jacob 	bus_space_read_4(isp->isp_bus_tag, isp->isp_bus_handle, off)
10526a7d12e1SMatt Jacob #define	BXW4(isp, off, v)	\
10536a7d12e1SMatt Jacob 	bus_space_write_4(isp->isp_bus_tag, isp->isp_bus_handle, off, v)
1054126ec864SMatt Jacob 
1055126ec864SMatt Jacob 
10562df76c16SMatt Jacob static ISP_INLINE int
10579cd7268eSMatt Jacob isp_pci_rd_debounced(ispsoftc_t *isp, int off, uint16_t *rp)
1058126ec864SMatt Jacob {
105910365e5aSMatt Jacob 	uint32_t val0, val1;
1060126ec864SMatt Jacob 	int i = 0;
1061126ec864SMatt Jacob 
1062126ec864SMatt Jacob 	do {
10636a7d12e1SMatt Jacob 		val0 = BXR2(isp, IspVirt2Off(isp, off));
10646a7d12e1SMatt Jacob 		val1 = BXR2(isp, IspVirt2Off(isp, off));
1065126ec864SMatt Jacob 	} while (val0 != val1 && ++i < 1000);
1066126ec864SMatt Jacob 	if (val0 != val1) {
1067126ec864SMatt Jacob 		return (1);
1068126ec864SMatt Jacob 	}
1069126ec864SMatt Jacob 	*rp = val0;
1070126ec864SMatt Jacob 	return (0);
1071126ec864SMatt Jacob }
1072126ec864SMatt Jacob 
1073126ec864SMatt Jacob static int
10740a70657fSMatt Jacob isp_pci_rd_isr(ispsoftc_t *isp, uint32_t *isrp, uint16_t *semap, uint16_t *mbp)
1075126ec864SMatt Jacob {
10761dae40ebSMatt Jacob 	uint16_t isr, sema;
1077126ec864SMatt Jacob 
1078126ec864SMatt Jacob 	if (IS_2100(isp)) {
1079126ec864SMatt Jacob 		if (isp_pci_rd_debounced(isp, BIU_ISR, &isr)) {
1080126ec864SMatt Jacob 		    return (0);
1081126ec864SMatt Jacob 		}
1082126ec864SMatt Jacob 		if (isp_pci_rd_debounced(isp, BIU_SEMA, &sema)) {
1083126ec864SMatt Jacob 		    return (0);
1084126ec864SMatt Jacob 		}
1085126ec864SMatt Jacob 	} else {
10866a7d12e1SMatt Jacob 		isr = BXR2(isp, IspVirt2Off(isp, BIU_ISR));
10876a7d12e1SMatt Jacob 		sema = BXR2(isp, IspVirt2Off(isp, BIU_SEMA));
1088126ec864SMatt Jacob 	}
1089126ec864SMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG3, "ISR 0x%x SEMA 0x%x", isr, sema);
1090126ec864SMatt Jacob 	isr &= INT_PENDING_MASK(isp);
1091126ec864SMatt Jacob 	sema &= BIU_SEMA_LOCK;
1092126ec864SMatt Jacob 	if (isr == 0 && sema == 0) {
1093126ec864SMatt Jacob 		return (0);
1094126ec864SMatt Jacob 	}
1095126ec864SMatt Jacob 	*isrp = isr;
1096126ec864SMatt Jacob 	if ((*semap = sema) != 0) {
1097126ec864SMatt Jacob 		if (IS_2100(isp)) {
1098126ec864SMatt Jacob 			if (isp_pci_rd_debounced(isp, OUTMAILBOX0, mbp)) {
1099126ec864SMatt Jacob 				return (0);
1100126ec864SMatt Jacob 			}
1101126ec864SMatt Jacob 		} else {
11026a7d12e1SMatt Jacob 			*mbp = BXR2(isp, IspVirt2Off(isp, OUTMAILBOX0));
1103126ec864SMatt Jacob 		}
1104126ec864SMatt Jacob 	}
1105126ec864SMatt Jacob 	return (1);
1106126ec864SMatt Jacob }
1107126ec864SMatt Jacob 
1108126ec864SMatt Jacob static int
1109443e752dSMatt Jacob isp_pci_rd_isr_2300(ispsoftc_t *isp, uint32_t *isrp, uint16_t *semap, uint16_t *mbox0p)
1110126ec864SMatt Jacob {
111110365e5aSMatt Jacob 	uint32_t hccr;
11121dae40ebSMatt Jacob 	uint32_t r2hisr;
1113126ec864SMatt Jacob 
11146a7d12e1SMatt Jacob 	if (!(BXR2(isp, IspVirt2Off(isp, BIU_ISR) & BIU2100_ISR_RISC_INT))) {
11153bd40330SMatt Jacob 		*isrp = 0;
1116db4fa023SMatt Jacob 		return (0);
11173bd40330SMatt Jacob 	}
11186a7d12e1SMatt Jacob 	r2hisr = BXR4(isp, IspVirt2Off(isp, BIU_R2HSTSLO));
1119126ec864SMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG3, "RISC2HOST ISR 0x%x", r2hisr);
1120126ec864SMatt Jacob 	if ((r2hisr & BIU_R2HST_INTR) == 0) {
1121126ec864SMatt Jacob 		*isrp = 0;
1122126ec864SMatt Jacob 		return (0);
1123126ec864SMatt Jacob 	}
1124126ec864SMatt Jacob 	switch (r2hisr & BIU_R2HST_ISTAT_MASK) {
1125126ec864SMatt Jacob 	case ISPR2HST_ROM_MBX_OK:
1126126ec864SMatt Jacob 	case ISPR2HST_ROM_MBX_FAIL:
1127126ec864SMatt Jacob 	case ISPR2HST_MBX_OK:
1128126ec864SMatt Jacob 	case ISPR2HST_MBX_FAIL:
1129126ec864SMatt Jacob 	case ISPR2HST_ASYNC_EVENT:
1130126ec864SMatt Jacob 		*isrp = r2hisr & 0xffff;
1131126ec864SMatt Jacob 		*mbox0p = (r2hisr >> 16);
1132126ec864SMatt Jacob 		*semap = 1;
1133126ec864SMatt Jacob 		return (1);
1134fc3bbaaaSMatt Jacob 	case ISPR2HST_RIO_16:
1135fc3bbaaaSMatt Jacob 		*isrp = r2hisr & 0xffff;
1136443e752dSMatt Jacob 		*mbox0p = ASYNC_RIO16_1;
1137fc3bbaaaSMatt Jacob 		*semap = 1;
1138fc3bbaaaSMatt Jacob 		return (1);
1139fc3bbaaaSMatt Jacob 	case ISPR2HST_FPOST:
1140fc3bbaaaSMatt Jacob 		*isrp = r2hisr & 0xffff;
1141fc3bbaaaSMatt Jacob 		*mbox0p = ASYNC_CMD_CMPLT;
1142fc3bbaaaSMatt Jacob 		*semap = 1;
1143fc3bbaaaSMatt Jacob 		return (1);
1144fc3bbaaaSMatt Jacob 	case ISPR2HST_FPOST_CTIO:
1145fc3bbaaaSMatt Jacob 		*isrp = r2hisr & 0xffff;
1146fc3bbaaaSMatt Jacob 		*mbox0p = ASYNC_CTIO_DONE;
1147fc3bbaaaSMatt Jacob 		*semap = 1;
1148fc3bbaaaSMatt Jacob 		return (1);
1149126ec864SMatt Jacob 	case ISPR2HST_RSPQ_UPDATE:
1150126ec864SMatt Jacob 		*isrp = r2hisr & 0xffff;
1151126ec864SMatt Jacob 		*mbox0p = 0;
1152126ec864SMatt Jacob 		*semap = 0;
1153126ec864SMatt Jacob 		return (1);
1154126ec864SMatt Jacob 	default:
11558a97c03aSMatt Jacob 		hccr = ISP_READ(isp, HCCR);
11568a97c03aSMatt Jacob 		if (hccr & HCCR_PAUSE) {
11578a97c03aSMatt Jacob 			ISP_WRITE(isp, HCCR, HCCR_RESET);
1158443e752dSMatt Jacob 			isp_prt(isp, ISP_LOGERR, "RISC paused at interrupt (%x->%x)", hccr, ISP_READ(isp, HCCR));
11595ccae6a5SMatt Jacob 			ISP_WRITE(isp, BIU_ICR, 0);
11608a97c03aSMatt Jacob 		} else {
1161443e752dSMatt Jacob 			isp_prt(isp, ISP_LOGERR, "unknown interrupt 0x%x\n", r2hisr);
11628a97c03aSMatt Jacob 		}
1163126ec864SMatt Jacob 		return (0);
1164126ec864SMatt Jacob 	}
1165126ec864SMatt Jacob }
1166126ec864SMatt Jacob 
116710365e5aSMatt Jacob static int
1168443e752dSMatt Jacob isp_pci_rd_isr_2400(ispsoftc_t *isp, uint32_t *isrp, uint16_t *semap, uint16_t *mbox0p)
116910365e5aSMatt Jacob {
117010365e5aSMatt Jacob 	uint32_t r2hisr;
117110365e5aSMatt Jacob 
11726a7d12e1SMatt Jacob 	r2hisr = BXR4(isp, IspVirt2Off(isp, BIU2400_R2HSTSLO));
117310365e5aSMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG3, "RISC2HOST ISR 0x%x", r2hisr);
117410365e5aSMatt Jacob 	if ((r2hisr & BIU2400_R2HST_INTR) == 0) {
117510365e5aSMatt Jacob 		*isrp = 0;
117610365e5aSMatt Jacob 		return (0);
117710365e5aSMatt Jacob 	}
117810365e5aSMatt Jacob 	switch (r2hisr & BIU2400_R2HST_ISTAT_MASK) {
117910365e5aSMatt Jacob 	case ISP2400R2HST_ROM_MBX_OK:
118010365e5aSMatt Jacob 	case ISP2400R2HST_ROM_MBX_FAIL:
118110365e5aSMatt Jacob 	case ISP2400R2HST_MBX_OK:
118210365e5aSMatt Jacob 	case ISP2400R2HST_MBX_FAIL:
118310365e5aSMatt Jacob 	case ISP2400R2HST_ASYNC_EVENT:
118410365e5aSMatt Jacob 		*isrp = r2hisr & 0xffff;
118510365e5aSMatt Jacob 		*mbox0p = (r2hisr >> 16);
118610365e5aSMatt Jacob 		*semap = 1;
118710365e5aSMatt Jacob 		return (1);
118810365e5aSMatt Jacob 	case ISP2400R2HST_RSPQ_UPDATE:
118910365e5aSMatt Jacob 	case ISP2400R2HST_ATIO_RSPQ_UPDATE:
119010365e5aSMatt Jacob 	case ISP2400R2HST_ATIO_RQST_UPDATE:
119110365e5aSMatt Jacob 		*isrp = r2hisr & 0xffff;
119210365e5aSMatt Jacob 		*mbox0p = 0;
119310365e5aSMatt Jacob 		*semap = 0;
119410365e5aSMatt Jacob 		return (1);
119510365e5aSMatt Jacob 	default:
119610365e5aSMatt Jacob 		ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_RISC_INT);
119710365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGERR, "unknown interrupt 0x%x\n", r2hisr);
119810365e5aSMatt Jacob 		return (0);
119910365e5aSMatt Jacob 	}
120010365e5aSMatt Jacob }
120110365e5aSMatt Jacob 
120210365e5aSMatt Jacob static uint32_t
12039cd7268eSMatt Jacob isp_pci_rd_reg(ispsoftc_t *isp, int regoff)
120465adb54cSMatt Jacob {
12056a7d12e1SMatt Jacob 	uint16_t rv;
1206126ec864SMatt Jacob 	int oldconf = 0;
120765adb54cSMatt Jacob 
1208d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
120965adb54cSMatt Jacob 		/*
121065adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
121165adb54cSMatt Jacob 		 */
12126a7d12e1SMatt Jacob 		oldconf = BXR2(isp, IspVirt2Off(isp, BIU_CONF1));
1213443e752dSMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1), oldconf | BIU_PCI_CONF1_SXP);
121437bb79f1SMarius Strobl 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2, -1);
121565adb54cSMatt Jacob 	}
12166a7d12e1SMatt Jacob 	rv = BXR2(isp, IspVirt2Off(isp, regoff));
1217d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
12186a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1), oldconf);
121937bb79f1SMarius Strobl 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2, -1);
122065adb54cSMatt Jacob 	}
122165adb54cSMatt Jacob 	return (rv);
122265adb54cSMatt Jacob }
122365adb54cSMatt Jacob 
122465adb54cSMatt Jacob static void
122510365e5aSMatt Jacob isp_pci_wr_reg(ispsoftc_t *isp, int regoff, uint32_t val)
122665adb54cSMatt Jacob {
1227126ec864SMatt Jacob 	int oldconf = 0;
1228d59bd469SMatt Jacob 
1229d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
123065adb54cSMatt Jacob 		/*
123165adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
123265adb54cSMatt Jacob 		 */
12336a7d12e1SMatt Jacob 		oldconf = BXR2(isp, IspVirt2Off(isp, BIU_CONF1));
12346a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1),
1235126ec864SMatt Jacob 		    oldconf | BIU_PCI_CONF1_SXP);
123637bb79f1SMarius Strobl 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2, -1);
123765adb54cSMatt Jacob 	}
12386a7d12e1SMatt Jacob 	BXW2(isp, IspVirt2Off(isp, regoff), val);
123937bb79f1SMarius Strobl 	MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, regoff), 2, -1);
1240d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
12416a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1), oldconf);
124237bb79f1SMarius Strobl 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2, -1);
124365adb54cSMatt Jacob 	}
12446a7d12e1SMatt Jacob 
1245f9734398SMatt Jacob }
124665adb54cSMatt Jacob 
124710365e5aSMatt Jacob static uint32_t
12489cd7268eSMatt Jacob isp_pci_rd_reg_1080(ispsoftc_t *isp, int regoff)
1249d59bd469SMatt Jacob {
125010365e5aSMatt Jacob 	uint32_t rv, oc = 0;
1251d59bd469SMatt Jacob 
125222e1dc85SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
125322e1dc85SMatt Jacob 	    (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
125410365e5aSMatt Jacob 		uint32_t tc;
1255d59bd469SMatt Jacob 		/*
1256d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
1257d59bd469SMatt Jacob 		 */
12586a7d12e1SMatt Jacob 		oc = BXR2(isp, IspVirt2Off(isp, BIU_CONF1));
125922e1dc85SMatt Jacob 		tc = oc & ~BIU_PCI1080_CONF1_DMA;
126022e1dc85SMatt Jacob 		if (regoff & SXP_BANK1_SELECT)
126122e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP1;
126222e1dc85SMatt Jacob 		else
126322e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP0;
12646a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1), tc);
126537bb79f1SMarius Strobl 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2, -1);
1266d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
12676a7d12e1SMatt Jacob 		oc = BXR2(isp, IspVirt2Off(isp, BIU_CONF1));
12686a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1),
1269126ec864SMatt Jacob 		    oc | BIU_PCI1080_CONF1_DMA);
127037bb79f1SMarius Strobl 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2, -1);
1271d59bd469SMatt Jacob 	}
12726a7d12e1SMatt Jacob 	rv = BXR2(isp, IspVirt2Off(isp, regoff));
127322e1dc85SMatt Jacob 	if (oc) {
12746a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1), oc);
127537bb79f1SMarius Strobl 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2, -1);
1276d59bd469SMatt Jacob 	}
1277d59bd469SMatt Jacob 	return (rv);
1278d59bd469SMatt Jacob }
1279d59bd469SMatt Jacob 
1280d59bd469SMatt Jacob static void
128110365e5aSMatt Jacob isp_pci_wr_reg_1080(ispsoftc_t *isp, int regoff, uint32_t val)
1282d59bd469SMatt Jacob {
1283126ec864SMatt Jacob 	int oc = 0;
1284d59bd469SMatt Jacob 
128522e1dc85SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
128622e1dc85SMatt Jacob 	    (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
128710365e5aSMatt Jacob 		uint32_t tc;
1288d59bd469SMatt Jacob 		/*
1289d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
1290d59bd469SMatt Jacob 		 */
12916a7d12e1SMatt Jacob 		oc = BXR2(isp, IspVirt2Off(isp, BIU_CONF1));
129222e1dc85SMatt Jacob 		tc = oc & ~BIU_PCI1080_CONF1_DMA;
129322e1dc85SMatt Jacob 		if (regoff & SXP_BANK1_SELECT)
129422e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP1;
129522e1dc85SMatt Jacob 		else
129622e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP0;
12976a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1), tc);
129837bb79f1SMarius Strobl 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2, -1);
1299d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
13006a7d12e1SMatt Jacob 		oc = BXR2(isp, IspVirt2Off(isp, BIU_CONF1));
13016a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1),
1302126ec864SMatt Jacob 		    oc | BIU_PCI1080_CONF1_DMA);
130337bb79f1SMarius Strobl 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2, -1);
1304d59bd469SMatt Jacob 	}
13056a7d12e1SMatt Jacob 	BXW2(isp, IspVirt2Off(isp, regoff), val);
130637bb79f1SMarius Strobl 	MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, regoff), 2, -1);
130722e1dc85SMatt Jacob 	if (oc) {
13086a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, BIU_CONF1), oc);
130937bb79f1SMarius Strobl 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2, -1);
131010365e5aSMatt Jacob 	}
131110365e5aSMatt Jacob }
131210365e5aSMatt Jacob 
131310365e5aSMatt Jacob static uint32_t
131410365e5aSMatt Jacob isp_pci_rd_reg_2400(ispsoftc_t *isp, int regoff)
131510365e5aSMatt Jacob {
131610365e5aSMatt Jacob 	uint32_t rv;
131710365e5aSMatt Jacob 	int block = regoff & _BLK_REG_MASK;
131810365e5aSMatt Jacob 
131910365e5aSMatt Jacob 	switch (block) {
132010365e5aSMatt Jacob 	case BIU_BLOCK:
132110365e5aSMatt Jacob 		break;
132210365e5aSMatt Jacob 	case MBOX_BLOCK:
13236a7d12e1SMatt Jacob 		return (BXR2(isp, IspVirt2Off(isp, regoff)));
132410365e5aSMatt Jacob 	case SXP_BLOCK:
132510365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "SXP_BLOCK read at 0x%x", regoff);
132610365e5aSMatt Jacob 		return (0xffffffff);
132710365e5aSMatt Jacob 	case RISC_BLOCK:
132810365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "RISC_BLOCK read at 0x%x", regoff);
132910365e5aSMatt Jacob 		return (0xffffffff);
133010365e5aSMatt Jacob 	case DMA_BLOCK:
133110365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "DMA_BLOCK read at 0x%x", regoff);
133210365e5aSMatt Jacob 		return (0xffffffff);
133310365e5aSMatt Jacob 	default:
133410365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "unknown block read at 0x%x", regoff);
133510365e5aSMatt Jacob 		return (0xffffffff);
133610365e5aSMatt Jacob 	}
133710365e5aSMatt Jacob 
133810365e5aSMatt Jacob 
133910365e5aSMatt Jacob 	switch (regoff) {
134010365e5aSMatt Jacob 	case BIU2400_FLASH_ADDR:
134110365e5aSMatt Jacob 	case BIU2400_FLASH_DATA:
134210365e5aSMatt Jacob 	case BIU2400_ICR:
134310365e5aSMatt Jacob 	case BIU2400_ISR:
134410365e5aSMatt Jacob 	case BIU2400_CSR:
134510365e5aSMatt Jacob 	case BIU2400_REQINP:
134610365e5aSMatt Jacob 	case BIU2400_REQOUTP:
134710365e5aSMatt Jacob 	case BIU2400_RSPINP:
134810365e5aSMatt Jacob 	case BIU2400_RSPOUTP:
13492df76c16SMatt Jacob 	case BIU2400_PRI_REQINP:
13502df76c16SMatt Jacob 	case BIU2400_PRI_REQOUTP:
135110365e5aSMatt Jacob 	case BIU2400_ATIO_RSPINP:
13522df76c16SMatt Jacob 	case BIU2400_ATIO_RSPOUTP:
135310365e5aSMatt Jacob 	case BIU2400_HCCR:
135410365e5aSMatt Jacob 	case BIU2400_GPIOD:
135510365e5aSMatt Jacob 	case BIU2400_GPIOE:
135610365e5aSMatt Jacob 	case BIU2400_HSEMA:
13576a7d12e1SMatt Jacob 		rv = BXR4(isp, IspVirt2Off(isp, regoff));
135810365e5aSMatt Jacob 		break;
135910365e5aSMatt Jacob 	case BIU2400_R2HSTSLO:
13606a7d12e1SMatt Jacob 		rv = BXR4(isp, IspVirt2Off(isp, regoff));
136110365e5aSMatt Jacob 		break;
136210365e5aSMatt Jacob 	case BIU2400_R2HSTSHI:
13636a7d12e1SMatt Jacob 		rv = BXR4(isp, IspVirt2Off(isp, regoff)) >> 16;
136410365e5aSMatt Jacob 		break;
136510365e5aSMatt Jacob 	default:
136610365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGERR,
136710365e5aSMatt Jacob 		    "isp_pci_rd_reg_2400: unknown offset %x", regoff);
136810365e5aSMatt Jacob 		rv = 0xffffffff;
136910365e5aSMatt Jacob 		break;
137010365e5aSMatt Jacob 	}
137110365e5aSMatt Jacob 	return (rv);
137210365e5aSMatt Jacob }
137310365e5aSMatt Jacob 
137410365e5aSMatt Jacob static void
137510365e5aSMatt Jacob isp_pci_wr_reg_2400(ispsoftc_t *isp, int regoff, uint32_t val)
137610365e5aSMatt Jacob {
137710365e5aSMatt Jacob 	int block = regoff & _BLK_REG_MASK;
137810365e5aSMatt Jacob 
137910365e5aSMatt Jacob 	switch (block) {
138010365e5aSMatt Jacob 	case BIU_BLOCK:
138110365e5aSMatt Jacob 		break;
138210365e5aSMatt Jacob 	case MBOX_BLOCK:
13836a7d12e1SMatt Jacob 		BXW2(isp, IspVirt2Off(isp, regoff), val);
138437bb79f1SMarius Strobl 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, regoff), 2, -1);
138510365e5aSMatt Jacob 		return;
138610365e5aSMatt Jacob 	case SXP_BLOCK:
138710365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "SXP_BLOCK write at 0x%x", regoff);
138810365e5aSMatt Jacob 		return;
138910365e5aSMatt Jacob 	case RISC_BLOCK:
139010365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "RISC_BLOCK write at 0x%x", regoff);
139110365e5aSMatt Jacob 		return;
139210365e5aSMatt Jacob 	case DMA_BLOCK:
139310365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "DMA_BLOCK write at 0x%x", regoff);
139410365e5aSMatt Jacob 		return;
139510365e5aSMatt Jacob 	default:
139610365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "unknown block write at 0x%x",
139710365e5aSMatt Jacob 		    regoff);
139810365e5aSMatt Jacob 		break;
139910365e5aSMatt Jacob 	}
140010365e5aSMatt Jacob 
140110365e5aSMatt Jacob 	switch (regoff) {
140210365e5aSMatt Jacob 	case BIU2400_FLASH_ADDR:
140310365e5aSMatt Jacob 	case BIU2400_FLASH_DATA:
140410365e5aSMatt Jacob 	case BIU2400_ICR:
140510365e5aSMatt Jacob 	case BIU2400_ISR:
140610365e5aSMatt Jacob 	case BIU2400_CSR:
140710365e5aSMatt Jacob 	case BIU2400_REQINP:
140810365e5aSMatt Jacob 	case BIU2400_REQOUTP:
140910365e5aSMatt Jacob 	case BIU2400_RSPINP:
141010365e5aSMatt Jacob 	case BIU2400_RSPOUTP:
14112df76c16SMatt Jacob 	case BIU2400_PRI_REQINP:
14122df76c16SMatt Jacob 	case BIU2400_PRI_REQOUTP:
141310365e5aSMatt Jacob 	case BIU2400_ATIO_RSPINP:
14142df76c16SMatt Jacob 	case BIU2400_ATIO_RSPOUTP:
141510365e5aSMatt Jacob 	case BIU2400_HCCR:
141610365e5aSMatt Jacob 	case BIU2400_GPIOD:
141710365e5aSMatt Jacob 	case BIU2400_GPIOE:
141810365e5aSMatt Jacob 	case BIU2400_HSEMA:
14196a7d12e1SMatt Jacob 		BXW4(isp, IspVirt2Off(isp, regoff), val);
142037bb79f1SMarius Strobl 		MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, regoff), 4, -1);
142110365e5aSMatt Jacob 		break;
142210365e5aSMatt Jacob 	default:
142310365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGERR,
142410365e5aSMatt Jacob 		    "isp_pci_wr_reg_2400: bad offset 0x%x", regoff);
142510365e5aSMatt Jacob 		break;
1426d59bd469SMatt Jacob 	}
1427d59bd469SMatt Jacob }
1428d59bd469SMatt Jacob 
1429d720e6d5SJustin T. Gibbs 
1430222bb542SMatt Jacob struct imush {
14319cd7268eSMatt Jacob 	ispsoftc_t *isp;
14322df76c16SMatt Jacob 	caddr_t vbase;
14332df76c16SMatt Jacob 	int chan;
1434222bb542SMatt Jacob 	int error;
1435222bb542SMatt Jacob };
1436222bb542SMatt Jacob 
14371923f739SMatt Jacob static void imc(void *, bus_dma_segment_t *, int, int);
14382df76c16SMatt Jacob static void imc1(void *, bus_dma_segment_t *, int, int);
14391923f739SMatt Jacob 
1440d720e6d5SJustin T. Gibbs static void
14411923f739SMatt Jacob imc(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1442d720e6d5SJustin T. Gibbs {
1443222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
14442df76c16SMatt Jacob 
1445222bb542SMatt Jacob 	if (error) {
1446222bb542SMatt Jacob 		imushp->error = error;
14472df76c16SMatt Jacob 		return;
14482df76c16SMatt Jacob 	}
14492df76c16SMatt Jacob 	if (nseg != 1) {
14502df76c16SMatt Jacob 		imushp->error = EINVAL;
14512df76c16SMatt Jacob 		return;
14522df76c16SMatt Jacob 	}
14537d3cea31SMatt Jacob 	isp_prt(imushp->isp, ISP_LOGDEBUG0, "request/result area @ 0x%jx/0x%jx", (uintmax_t) segs->ds_addr, (uintmax_t) segs->ds_len);
14542df76c16SMatt Jacob 	imushp->isp->isp_rquest = imushp->vbase;
14552df76c16SMatt Jacob 	imushp->isp->isp_rquest_dma = segs->ds_addr;
14562df76c16SMatt Jacob 	segs->ds_addr += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(imushp->isp));
14572df76c16SMatt Jacob 	imushp->vbase += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(imushp->isp));
14582df76c16SMatt Jacob 	imushp->isp->isp_result_dma = segs->ds_addr;
14592df76c16SMatt Jacob 	imushp->isp->isp_result = imushp->vbase;
14601923f739SMatt Jacob 
14612df76c16SMatt Jacob #ifdef	ISP_TARGET_MODE
14622df76c16SMatt Jacob 	if (IS_24XX(imushp->isp)) {
14632df76c16SMatt Jacob 		segs->ds_addr += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(imushp->isp));
14642df76c16SMatt Jacob 		imushp->vbase += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(imushp->isp));
14652df76c16SMatt Jacob 		imushp->isp->isp_atioq_dma = segs->ds_addr;
14662df76c16SMatt Jacob 		imushp->isp->isp_atioq = imushp->vbase;
14671923f739SMatt Jacob 	}
14682df76c16SMatt Jacob #endif
1469222bb542SMatt Jacob }
14702df76c16SMatt Jacob 
14712df76c16SMatt Jacob static void
14722df76c16SMatt Jacob imc1(void *arg, bus_dma_segment_t *segs, int nseg, int error)
14732df76c16SMatt Jacob {
14742df76c16SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
14752df76c16SMatt Jacob 	if (error) {
14762df76c16SMatt Jacob 		imushp->error = error;
14772df76c16SMatt Jacob 		return;
14782df76c16SMatt Jacob 	}
14792df76c16SMatt Jacob 	if (nseg != 1) {
14802df76c16SMatt Jacob 		imushp->error = EINVAL;
14812df76c16SMatt Jacob 		return;
14822df76c16SMatt Jacob 	}
14837d3cea31SMatt Jacob 	isp_prt(imushp->isp, ISP_LOGDEBUG0, "scdma @ 0x%jx/0x%jx", (uintmax_t) segs->ds_addr, (uintmax_t) segs->ds_len);
14842df76c16SMatt Jacob 	FCPARAM(imushp->isp, imushp->chan)->isp_scdma = segs->ds_addr;
14852df76c16SMatt Jacob 	FCPARAM(imushp->isp, imushp->chan)->isp_scratch = imushp->vbase;
1486d720e6d5SJustin T. Gibbs }
1487d720e6d5SJustin T. Gibbs 
1488d720e6d5SJustin T. Gibbs static int
14899cd7268eSMatt Jacob isp_pci_mbxdma(ispsoftc_t *isp)
1490d720e6d5SJustin T. Gibbs {
1491d720e6d5SJustin T. Gibbs 	caddr_t base;
14921dae40ebSMatt Jacob 	uint32_t len;
14932df76c16SMatt Jacob 	int i, error, ns, cmap = 0;
149453af7d22SMatt Jacob 	bus_size_t slim;	/* segment size */
14954b2dc3c4SScott Long 	bus_addr_t llim;	/* low limit of unavailable dma */
149651effc8cSMatt Jacob 	bus_addr_t hlim;	/* high limit of unavailable dma */
1497222bb542SMatt Jacob 	struct imush im;
1498222bb542SMatt Jacob 
1499a95ae193SMatt Jacob 	/*
1500a95ae193SMatt Jacob 	 * Already been here? If so, leave...
1501a95ae193SMatt Jacob 	 */
1502a95ae193SMatt Jacob 	if (isp->isp_rquest) {
1503a95ae193SMatt Jacob 		return (0);
1504a95ae193SMatt Jacob 	}
15050a70657fSMatt Jacob 	ISP_UNLOCK(isp);
1506a95ae193SMatt Jacob 
150710365e5aSMatt Jacob 	if (isp->isp_maxcmds == 0) {
150810365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGERR, "maxcmds not set");
15090a70657fSMatt Jacob 		ISP_LOCK(isp);
151010365e5aSMatt Jacob 		return (1);
151110365e5aSMatt Jacob 	}
151210365e5aSMatt Jacob 
151353af7d22SMatt Jacob 	hlim = BUS_SPACE_MAXADDR;
15141923f739SMatt Jacob 	if (IS_ULTRA2(isp) || IS_FC(isp) || IS_1240(isp)) {
15159b434edeSMatt Jacob 		if (sizeof (bus_size_t) > 4) {
151653af7d22SMatt Jacob 			slim = (bus_size_t) (1ULL << 32);
15179b434edeSMatt Jacob 		} else {
15189b434edeSMatt Jacob 			slim = (bus_size_t) (1UL << 31);
15199b434edeSMatt Jacob 		}
15201dae40ebSMatt Jacob 		llim = BUS_SPACE_MAXADDR;
15211923f739SMatt Jacob 	} else {
15221dae40ebSMatt Jacob 		llim = BUS_SPACE_MAXADDR_32BIT;
15239b434edeSMatt Jacob 		slim = (1UL << 24);
15241923f739SMatt Jacob 	}
15251923f739SMatt Jacob 
15260a70657fSMatt Jacob 	len = isp->isp_maxcmds * sizeof (struct isp_pcmd);
15272df76c16SMatt Jacob 	isp->isp_osinfo.pcmd_pool = (struct isp_pcmd *) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
15280a70657fSMatt Jacob 	if (isp->isp_osinfo.pcmd_pool == NULL) {
15290a70657fSMatt Jacob 		isp_prt(isp, ISP_LOGERR, "cannot allocate pcmds");
15300a70657fSMatt Jacob 		ISP_LOCK(isp);
15310a70657fSMatt Jacob 		return (1);
15320a70657fSMatt Jacob 	}
15330a70657fSMatt Jacob 
153409934867SMatt Jacob 	/*
153509934867SMatt Jacob 	 * XXX: We don't really support 64 bit target mode for parallel scsi yet
153609934867SMatt Jacob 	 */
153709934867SMatt Jacob #ifdef	ISP_TARGET_MODE
153809934867SMatt Jacob 	if (IS_SCSI(isp) && sizeof (bus_addr_t) > 4) {
15390a70657fSMatt Jacob 		free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
154009934867SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "we cannot do DAC for SPI cards yet");
15412df76c16SMatt Jacob 		ISP_LOCK(isp);
154209934867SMatt Jacob 		return (1);
154309934867SMatt Jacob 	}
154409934867SMatt Jacob #endif
154509934867SMatt Jacob 
15462df76c16SMatt 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)) {
15470a70657fSMatt Jacob 		free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
154872429e49SMatt Jacob 		ISP_LOCK(isp);
15490a70657fSMatt Jacob 		isp_prt(isp, ISP_LOGERR, "could not create master dma tag");
15501923f739SMatt Jacob 		return (1);
15511923f739SMatt Jacob 	}
15521923f739SMatt Jacob 
1553c8b8a2c4SMatt Jacob 	len = sizeof (isp_hdl_t) * isp->isp_maxcmds;
1554c8b8a2c4SMatt Jacob 	isp->isp_xflist = (isp_hdl_t *) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
1555a95ae193SMatt Jacob 	if (isp->isp_xflist == NULL) {
15560a70657fSMatt Jacob 		free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
155772429e49SMatt Jacob 		ISP_LOCK(isp);
15580a70657fSMatt Jacob 		isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array");
1559a95ae193SMatt Jacob 		return (1);
1560a95ae193SMatt Jacob 	}
1561c8b8a2c4SMatt Jacob 	for (len = 0; len < isp->isp_maxcmds - 1; len++) {
1562c8b8a2c4SMatt Jacob 		isp->isp_xflist[len].cmd = &isp->isp_xflist[len+1];
1563c8b8a2c4SMatt Jacob 	}
1564c8b8a2c4SMatt Jacob 	isp->isp_xffree = isp->isp_xflist;
156551e23558SNate Lawson #ifdef	ISP_TARGET_MODE
156632b3ec7dSMatt Jacob 	len = sizeof (isp_hdl_t) * isp->isp_maxcmds;
1567c8b8a2c4SMatt Jacob 	isp->isp_tgtlist = (isp_hdl_t *) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
156851e23558SNate Lawson 	if (isp->isp_tgtlist == NULL) {
15690a70657fSMatt Jacob 		free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
1570a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
157172429e49SMatt Jacob 		ISP_LOCK(isp);
15720a70657fSMatt Jacob 		isp_prt(isp, ISP_LOGERR, "cannot alloc tgtlist array");
1573a95ae193SMatt Jacob 		return (1);
1574a95ae193SMatt Jacob 	}
1575c8b8a2c4SMatt Jacob 	for (len = 0; len < isp->isp_maxcmds - 1; len++) {
1576c8b8a2c4SMatt Jacob 		isp->isp_tgtlist[len].cmd = &isp->isp_tgtlist[len+1];
1577c8b8a2c4SMatt Jacob 	}
1578c8b8a2c4SMatt Jacob 	isp->isp_tgtfree = isp->isp_tgtlist;
15790a70657fSMatt Jacob #endif
1580a95ae193SMatt Jacob 
1581d720e6d5SJustin T. Gibbs 	/*
15822df76c16SMatt Jacob 	 * Allocate and map the request and result queues (and ATIO queue
15832df76c16SMatt Jacob 	 * if we're a 2400 supporting target mode).
1584d720e6d5SJustin T. Gibbs 	 */
1585d02373f1SMatt Jacob 	len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
1586d02373f1SMatt Jacob 	len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
15872df76c16SMatt Jacob #ifdef	ISP_TARGET_MODE
15882df76c16SMatt Jacob 	if (IS_24XX(isp)) {
15892df76c16SMatt Jacob 		len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
1590d720e6d5SJustin T. Gibbs 	}
15912df76c16SMatt Jacob #endif
15921923f739SMatt Jacob 
15931923f739SMatt Jacob 	ns = (len / PAGE_SIZE) + 1;
15942df76c16SMatt Jacob 
159553af7d22SMatt Jacob 	/*
15962df76c16SMatt Jacob 	 * Create a tag for the control spaces. We don't always need this
15972df76c16SMatt Jacob 	 * to be 32 bits, but we do this for simplicity and speed's sake.
159853af7d22SMatt Jacob 	 */
15992df76c16SMatt 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)) {
16002df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "cannot create a dma tag for control spaces");
16010a70657fSMatt Jacob 		free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
1602a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
160351e23558SNate Lawson #ifdef	ISP_TARGET_MODE
160451e23558SNate Lawson 		free(isp->isp_tgtlist, M_DEVBUF);
160551e23558SNate Lawson #endif
160672429e49SMatt Jacob 		ISP_LOCK(isp);
1607d720e6d5SJustin T. Gibbs 		return (1);
1608d720e6d5SJustin T. Gibbs 	}
1609d720e6d5SJustin T. Gibbs 
161037bb79f1SMarius Strobl 	if (bus_dmamem_alloc(isp->isp_osinfo.cdmat, (void **)&base, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &isp->isp_osinfo.cdmap) != 0) {
16112df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "cannot allocate %d bytes of CCB memory", len);
16122df76c16SMatt Jacob 		bus_dma_tag_destroy(isp->isp_osinfo.cdmat);
16130a70657fSMatt Jacob 		free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
1614a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
161551e23558SNate Lawson #ifdef	ISP_TARGET_MODE
161651e23558SNate Lawson 		free(isp->isp_tgtlist, M_DEVBUF);
161751e23558SNate Lawson #endif
161872429e49SMatt Jacob 		ISP_LOCK(isp);
1619222bb542SMatt Jacob 		return (1);
1620222bb542SMatt Jacob 	}
1621d720e6d5SJustin T. Gibbs 
16222df76c16SMatt Jacob 	im.isp = isp;
16232df76c16SMatt Jacob 	im.chan = 0;
16242df76c16SMatt Jacob 	im.vbase = base;
16252df76c16SMatt Jacob 	im.error = 0;
16262df76c16SMatt Jacob 
16272df76c16SMatt Jacob 	bus_dmamap_load(isp->isp_osinfo.cdmat, isp->isp_osinfo.cdmap, base, len, imc, &im, 0);
16282df76c16SMatt Jacob 	if (im.error) {
16292df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "error %d loading dma map for control areas", im.error);
16302df76c16SMatt Jacob 		goto bad;
16312df76c16SMatt Jacob 	}
16322df76c16SMatt Jacob 
16332df76c16SMatt Jacob 	if (IS_FC(isp)) {
16342df76c16SMatt Jacob 		for (cmap = 0; cmap < isp->isp_nchan; cmap++) {
16352df76c16SMatt Jacob 			struct isp_fc *fc = ISP_FC_PC(isp, cmap);
16362df76c16SMatt 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)) {
16372df76c16SMatt Jacob 				goto bad;
16382df76c16SMatt Jacob 			}
163937bb79f1SMarius Strobl 			if (bus_dmamem_alloc(fc->tdmat, (void **)&base, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &fc->tdmap) != 0) {
16402df76c16SMatt Jacob 				bus_dma_tag_destroy(fc->tdmat);
16412df76c16SMatt Jacob 				goto bad;
16422df76c16SMatt Jacob 			}
16432df76c16SMatt Jacob 			im.isp = isp;
16442df76c16SMatt Jacob 			im.chan = cmap;
16452df76c16SMatt Jacob 			im.vbase = base;
16462df76c16SMatt Jacob 			im.error = 0;
16472df76c16SMatt Jacob 			bus_dmamap_load(fc->tdmat, fc->tdmap, base, ISP_FC_SCRLEN, imc1, &im, 0);
16482df76c16SMatt Jacob 			if (im.error) {
16492df76c16SMatt Jacob 				bus_dmamem_free(fc->tdmat, base, fc->tdmap);
16502df76c16SMatt Jacob 				bus_dma_tag_destroy(fc->tdmat);
16512df76c16SMatt Jacob 				goto bad;
16522df76c16SMatt Jacob 			}
16532df76c16SMatt Jacob 		}
16542df76c16SMatt Jacob 	}
16552df76c16SMatt Jacob 
1656a95ae193SMatt Jacob 	for (i = 0; i < isp->isp_maxcmds; i++) {
16570a70657fSMatt Jacob 		struct isp_pcmd *pcmd = &isp->isp_osinfo.pcmd_pool[i];
16580a70657fSMatt Jacob 		error = bus_dmamap_create(isp->isp_osinfo.dmat, 0, &pcmd->dmap);
1659d720e6d5SJustin T. Gibbs 		if (error) {
16602df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "error %d creating per-cmd DMA maps", error);
16611923f739SMatt Jacob 			while (--i >= 0) {
16622df76c16SMatt Jacob 				bus_dmamap_destroy(isp->isp_osinfo.dmat, isp->isp_osinfo.pcmd_pool[i].dmap);
16631923f739SMatt Jacob 			}
16641923f739SMatt Jacob 			goto bad;
1665d720e6d5SJustin T. Gibbs 		}
16662df76c16SMatt Jacob 		callout_init_mtx(&pcmd->wdog, &isp->isp_osinfo.lock, 0);
16670a70657fSMatt Jacob 		if (i == isp->isp_maxcmds-1) {
16680a70657fSMatt Jacob 			pcmd->next = NULL;
16690a70657fSMatt Jacob 		} else {
16700a70657fSMatt Jacob 			pcmd->next = &isp->isp_osinfo.pcmd_pool[i+1];
1671d720e6d5SJustin T. Gibbs 		}
16720a70657fSMatt Jacob 	}
16730a70657fSMatt Jacob 	isp->isp_osinfo.pcmd_free = &isp->isp_osinfo.pcmd_pool[0];
167472429e49SMatt Jacob 	ISP_LOCK(isp);
1675d720e6d5SJustin T. Gibbs 	return (0);
16761923f739SMatt Jacob 
16771923f739SMatt Jacob bad:
16782df76c16SMatt Jacob 	while (--cmap >= 0) {
16792df76c16SMatt Jacob 		struct isp_fc *fc = ISP_FC_PC(isp, cmap);
16802df76c16SMatt Jacob 		bus_dmamem_free(fc->tdmat, base, fc->tdmap);
16812df76c16SMatt Jacob 		bus_dma_tag_destroy(fc->tdmat);
16822df76c16SMatt Jacob 	}
16832df76c16SMatt Jacob 	bus_dmamem_free(isp->isp_osinfo.cdmat, base, isp->isp_osinfo.cdmap);
16842df76c16SMatt Jacob 	bus_dma_tag_destroy(isp->isp_osinfo.cdmat);
16851923f739SMatt Jacob 	free(isp->isp_xflist, M_DEVBUF);
168651e23558SNate Lawson #ifdef	ISP_TARGET_MODE
168751e23558SNate Lawson 	free(isp->isp_tgtlist, M_DEVBUF);
168851e23558SNate Lawson #endif
16890a70657fSMatt Jacob 	free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
16901923f739SMatt Jacob 	isp->isp_rquest = NULL;
16910a70657fSMatt Jacob 	ISP_LOCK(isp);
16921923f739SMatt Jacob 	return (1);
1693d720e6d5SJustin T. Gibbs }
1694d720e6d5SJustin T. Gibbs 
1695d720e6d5SJustin T. Gibbs typedef struct {
16969cd7268eSMatt Jacob 	ispsoftc_t *isp;
16979e11e5beSMatt Jacob 	void *cmd_token;
16982df76c16SMatt Jacob 	void *rq;	/* original request */
16991dae40ebSMatt Jacob 	int error;
17002df76c16SMatt Jacob 	bus_size_t mapsize;
1701d720e6d5SJustin T. Gibbs } mush_t;
1702d720e6d5SJustin T. Gibbs 
17034873663cSMatt Jacob #define	MUSHERR_NOQENTRIES	-2
17044873663cSMatt Jacob 
17059e11e5beSMatt Jacob #ifdef	ISP_TARGET_MODE
17062df76c16SMatt Jacob static void tdma2_2(void *, bus_dma_segment_t *, int, bus_size_t, int);
17072df76c16SMatt Jacob static void tdma2(void *, bus_dma_segment_t *, int, int);
17089e11e5beSMatt Jacob 
1709d720e6d5SJustin T. Gibbs static void
17102df76c16SMatt Jacob tdma2_2(void *arg, bus_dma_segment_t *dm_segs, int nseg, bus_size_t mapsize, int error)
1711d720e6d5SJustin T. Gibbs {
1712d720e6d5SJustin T. Gibbs 	mush_t *mp;
17132df76c16SMatt Jacob 	mp = (mush_t *)arg;
17142df76c16SMatt Jacob 	mp->mapsize = mapsize;
17152df76c16SMatt Jacob 	tdma2(arg, dm_segs, nseg, error);
17162df76c16SMatt Jacob }
17172df76c16SMatt Jacob 
17182df76c16SMatt Jacob static void
17192df76c16SMatt Jacob tdma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
17202df76c16SMatt Jacob {
17212df76c16SMatt Jacob 	mush_t *mp;
17229cd7268eSMatt Jacob 	ispsoftc_t *isp;
17232df76c16SMatt Jacob 	struct ccb_scsiio *csio;
17242df76c16SMatt Jacob 	isp_ddir_t ddir;
17252df76c16SMatt Jacob 	ispreq_t *rq;
1726d720e6d5SJustin T. Gibbs 
1727d720e6d5SJustin T. Gibbs 	mp = (mush_t *) arg;
1728d720e6d5SJustin T. Gibbs 	if (error) {
1729d720e6d5SJustin T. Gibbs 		mp->error = error;
1730d720e6d5SJustin T. Gibbs 		return;
1731d720e6d5SJustin T. Gibbs 	}
17329e11e5beSMatt Jacob 	csio = mp->cmd_token;
17334fd13c1bSMatt Jacob 	isp = mp->isp;
17342df76c16SMatt Jacob 	rq = mp->rq;
17352df76c16SMatt Jacob 	if (nseg) {
173609934867SMatt Jacob 		if (sizeof (bus_addr_t) > 4) {
17372df76c16SMatt Jacob 			if (nseg >= ISP_NSEG64_MAX) {
17382df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG64_MAX);
17392df76c16SMatt Jacob 				mp->error = EFAULT;
17409e11e5beSMatt Jacob 				return;
17419e11e5beSMatt Jacob 			}
17422df76c16SMatt Jacob 			if (rq->req_header.rqs_entry_type == RQSTYPE_CTIO2) {
17432df76c16SMatt Jacob 				rq->req_header.rqs_entry_type = RQSTYPE_CTIO3;
17442df76c16SMatt Jacob 			}
174509934867SMatt Jacob 		} else {
17462df76c16SMatt Jacob 			if (nseg >= ISP_NSEG_MAX) {
17472df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG_MAX);
17482df76c16SMatt Jacob 				mp->error = EFAULT;
17492df76c16SMatt Jacob 				return;
175009934867SMatt Jacob 			}
17512df76c16SMatt Jacob 		}
17522df76c16SMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
17532df76c16SMatt Jacob 			bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREWRITE);
17542df76c16SMatt Jacob 			ddir = ISP_TO_DEVICE;
17552df76c16SMatt Jacob 		} else if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
17562df76c16SMatt Jacob 			bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREREAD);
17572df76c16SMatt Jacob 			ddir = ISP_FROM_DEVICE;
175809934867SMatt Jacob 		} else {
1759a035b0afSMatt Jacob 			dm_segs = NULL;
1760a035b0afSMatt Jacob 			nseg = 0;
17612df76c16SMatt Jacob 			ddir = ISP_NOXFR;
176209934867SMatt Jacob 		}
17632df76c16SMatt Jacob 	} else {
17642df76c16SMatt Jacob 		dm_segs = NULL;
17652df76c16SMatt Jacob 		nseg = 0;
17662df76c16SMatt Jacob 		ddir = ISP_NOXFR;
1767fc087171SMatt Jacob 	}
176865b024e1SMatt Jacob 
17692df76c16SMatt Jacob 	if (isp_send_tgt_cmd(isp, rq, dm_segs, nseg, XS_XFRLEN(csio), ddir, &csio->sense_data, csio->sense_len) != CMD_QUEUED) {
17702df76c16SMatt Jacob 		mp->error = MUSHERR_NOQENTRIES;
177110365e5aSMatt Jacob 	}
17729e11e5beSMatt Jacob }
17739e11e5beSMatt Jacob #endif
17749e11e5beSMatt Jacob 
17752df76c16SMatt Jacob static void dma2_2(void *, bus_dma_segment_t *, int, bus_size_t, int);
1776126ec864SMatt Jacob static void dma2(void *, bus_dma_segment_t *, int, int);
17779e11e5beSMatt Jacob 
17786de9bf77SMatt Jacob static void
17792df76c16SMatt Jacob dma2_2(void *arg, bus_dma_segment_t *dm_segs, int nseg, bus_size_t mapsize, int error)
178010365e5aSMatt Jacob {
178110365e5aSMatt Jacob 	mush_t *mp;
178210365e5aSMatt Jacob 	mp = (mush_t *)arg;
17832df76c16SMatt Jacob 	mp->mapsize = mapsize;
17842df76c16SMatt Jacob 	dma2(arg, dm_segs, nseg, error);
17856de9bf77SMatt Jacob }
17861dae40ebSMatt Jacob 
17879e11e5beSMatt Jacob static void
17889e11e5beSMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
17899e11e5beSMatt Jacob {
17909e11e5beSMatt Jacob 	mush_t *mp;
17919cd7268eSMatt Jacob 	ispsoftc_t *isp;
17929e11e5beSMatt Jacob 	struct ccb_scsiio *csio;
17932df76c16SMatt Jacob 	isp_ddir_t ddir;
17949e11e5beSMatt Jacob 	ispreq_t *rq;
17959e11e5beSMatt Jacob 
17969e11e5beSMatt Jacob 	mp = (mush_t *) arg;
17979e11e5beSMatt Jacob 	if (error) {
17989e11e5beSMatt Jacob 		mp->error = error;
17999e11e5beSMatt Jacob 		return;
18009e11e5beSMatt Jacob 	}
18019e11e5beSMatt Jacob 	csio = mp->cmd_token;
18024fd13c1bSMatt Jacob 	isp = mp->isp;
18039e11e5beSMatt Jacob 	rq = mp->rq;
18042df76c16SMatt Jacob 	if (nseg) {
18052df76c16SMatt Jacob 		if (sizeof (bus_addr_t) > 4) {
18062df76c16SMatt Jacob 			if (nseg >= ISP_NSEG64_MAX) {
18072df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG64_MAX);
18082df76c16SMatt Jacob 				mp->error = EFAULT;
1809d720e6d5SJustin T. Gibbs 				return;
1810d720e6d5SJustin T. Gibbs 			}
18112df76c16SMatt Jacob 			if (rq->req_header.rqs_entry_type == RQSTYPE_T2RQS) {
18122df76c16SMatt Jacob 				rq->req_header.rqs_entry_type = RQSTYPE_T3RQS;
18132df76c16SMatt Jacob 			} else if (rq->req_header.rqs_entry_type == RQSTYPE_REQUEST) {
18142df76c16SMatt Jacob 				rq->req_header.rqs_entry_type = RQSTYPE_A64;
1815d720e6d5SJustin T. Gibbs 			}
18162df76c16SMatt Jacob 		} else {
18172df76c16SMatt Jacob 			if (nseg >= ISP_NSEG_MAX) {
18182df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG_MAX);
18192df76c16SMatt Jacob 				mp->error = EFAULT;
18202df76c16SMatt Jacob 				return;
182110365e5aSMatt Jacob 			}
1822d720e6d5SJustin T. Gibbs 		}
18232df76c16SMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
18242df76c16SMatt Jacob 			bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREREAD);
18252df76c16SMatt Jacob 			ddir = ISP_FROM_DEVICE;
18262df76c16SMatt Jacob 		} else if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
18272df76c16SMatt Jacob 			bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREWRITE);
18282df76c16SMatt Jacob 			ddir = ISP_TO_DEVICE;
18292df76c16SMatt Jacob 		} else {
18302df76c16SMatt Jacob 			ddir = ISP_NOXFR;
18312df76c16SMatt Jacob 		}
18322df76c16SMatt Jacob 	} else {
18332df76c16SMatt Jacob 		dm_segs = NULL;
18342df76c16SMatt Jacob 		nseg = 0;
18352df76c16SMatt Jacob 		ddir = ISP_NOXFR;
1836d720e6d5SJustin T. Gibbs 	}
1837d720e6d5SJustin T. Gibbs 
18382df76c16SMatt Jacob 	if (isp_send_cmd(isp, rq, dm_segs, nseg, XS_XFRLEN(csio), ddir) != CMD_QUEUED) {
18392df76c16SMatt Jacob 		mp->error = MUSHERR_NOQENTRIES;
18402df76c16SMatt Jacob 	}
18412df76c16SMatt Jacob }
18422df76c16SMatt Jacob 
1843d720e6d5SJustin T. Gibbs static int
18442df76c16SMatt Jacob isp_pci_dmasetup(ispsoftc_t *isp, struct ccb_scsiio *csio, void *ff)
1845d720e6d5SJustin T. Gibbs {
1846d720e6d5SJustin T. Gibbs 	mush_t mush, *mp;
1847126ec864SMatt Jacob 	void (*eptr)(void *, bus_dma_segment_t *, int, int);
18482df76c16SMatt Jacob 	void (*eptr2)(void *, bus_dma_segment_t *, int, bus_size_t, int);
1849d720e6d5SJustin T. Gibbs 
18502df76c16SMatt Jacob 	mp = &mush;
18512df76c16SMatt Jacob 	mp->isp = isp;
18522df76c16SMatt Jacob 	mp->cmd_token = csio;
18532df76c16SMatt Jacob 	mp->rq = ff;
18542df76c16SMatt Jacob 	mp->error = 0;
18552df76c16SMatt Jacob 	mp->mapsize = 0;
18562df76c16SMatt Jacob 
185765b024e1SMatt Jacob #ifdef	ISP_TARGET_MODE
185865b024e1SMatt Jacob 	if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) {
18592df76c16SMatt Jacob 		eptr = tdma2;
18602df76c16SMatt Jacob 		eptr2 = tdma2_2;
186165b024e1SMatt Jacob 	} else
186265b024e1SMatt Jacob #endif
18632df76c16SMatt Jacob 	{
186465b024e1SMatt Jacob 		eptr = dma2;
18652df76c16SMatt Jacob 		eptr2 = dma2_2;
18661dae40ebSMatt Jacob 	}
186765b024e1SMatt Jacob 
18684fd13c1bSMatt Jacob 
18692df76c16SMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || (csio->dxfer_len == 0)) {
18702df76c16SMatt Jacob 		(*eptr)(mp, NULL, 0, 0);
18712df76c16SMatt Jacob 	} else if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
18729e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) {
18730a70657fSMatt Jacob 			int error;
18742df76c16SMatt Jacob 			error = bus_dmamap_load(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, csio->data_ptr, csio->dxfer_len, eptr, mp, 0);
18752df76c16SMatt Jacob #if 0
18762df76c16SMatt 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);
18770a70657fSMatt Jacob #endif
18782df76c16SMatt Jacob 
1879d720e6d5SJustin T. Gibbs 			if (error == EINPROGRESS) {
18802df76c16SMatt Jacob 				bus_dmamap_unload(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap);
1881d720e6d5SJustin T. Gibbs 				mp->error = EINVAL;
18822df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "deferred dma allocation not supported");
1883d720e6d5SJustin T. Gibbs 			} else if (error && mp->error == 0) {
18840a5f7e8bSMatt Jacob #ifdef	DIAGNOSTIC
18852df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "error %d in dma mapping code", error);
18860a5f7e8bSMatt Jacob #endif
1887d720e6d5SJustin T. Gibbs 				mp->error = error;
1888d720e6d5SJustin T. Gibbs 			}
1889d720e6d5SJustin T. Gibbs 		} else {
1890d720e6d5SJustin T. Gibbs 			/* Pointer to physical buffer */
1891d720e6d5SJustin T. Gibbs 			struct bus_dma_segment seg;
18926de9bf77SMatt Jacob 			seg.ds_addr = (bus_addr_t)(vm_offset_t)csio->data_ptr;
1893d720e6d5SJustin T. Gibbs 			seg.ds_len = csio->dxfer_len;
18949e11e5beSMatt Jacob 			(*eptr)(mp, &seg, 1, 0);
1895d720e6d5SJustin T. Gibbs 		}
1896d720e6d5SJustin T. Gibbs 	} else {
1897d720e6d5SJustin T. Gibbs 		struct bus_dma_segment *segs;
1898d720e6d5SJustin T. Gibbs 
18999e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) {
19002df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "Physical segment pointers unsupported");
1901d720e6d5SJustin T. Gibbs 			mp->error = EINVAL;
19029e11e5beSMatt Jacob 		} else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) {
19032df76c16SMatt Jacob 			struct uio sguio;
19042df76c16SMatt Jacob 			int error;
19052df76c16SMatt Jacob 
19062df76c16SMatt Jacob 			/*
19072df76c16SMatt Jacob 			 * We're taking advantage of the fact that
19082df76c16SMatt Jacob 			 * the pointer/length sizes and layout of the iovec
19092df76c16SMatt Jacob 			 * structure are the same as the bus_dma_segment
19102df76c16SMatt Jacob 			 * structure.  This might be a little dangerous,
19112df76c16SMatt Jacob 			 * but only if they change the structures, which
19122df76c16SMatt Jacob 			 * seems unlikely.
19132df76c16SMatt Jacob 			 */
19142df76c16SMatt Jacob 			KASSERT((sizeof (sguio.uio_iov) == sizeof (csio->data_ptr) &&
19152df76c16SMatt Jacob 			    sizeof (sguio.uio_iovcnt) >= sizeof (csio->sglist_cnt) &&
19162df76c16SMatt Jacob 			    sizeof (sguio.uio_resid) >= sizeof (csio->dxfer_len)), ("Ken's assumption failed"));
19172df76c16SMatt Jacob 			sguio.uio_iov = (struct iovec *)csio->data_ptr;
19182df76c16SMatt Jacob 			sguio.uio_iovcnt = csio->sglist_cnt;
19192df76c16SMatt Jacob 			sguio.uio_resid = csio->dxfer_len;
19202df76c16SMatt Jacob 			sguio.uio_segflg = UIO_SYSSPACE;
19212df76c16SMatt Jacob 
19222df76c16SMatt Jacob 			error = bus_dmamap_load_uio(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, &sguio, eptr2, mp, 0);
19232df76c16SMatt Jacob 
19242df76c16SMatt Jacob 			if (error != 0 && mp->error == 0) {
19252df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "error %d in dma mapping code", error);
19262df76c16SMatt Jacob 				mp->error = error;
19272df76c16SMatt Jacob 			}
1928d720e6d5SJustin T. Gibbs 		} else {
1929d720e6d5SJustin T. Gibbs 			/* Just use the segments provided */
1930d720e6d5SJustin T. Gibbs 			segs = (struct bus_dma_segment *) csio->data_ptr;
19319e11e5beSMatt Jacob 			(*eptr)(mp, segs, csio->sglist_cnt, 0);
1932d720e6d5SJustin T. Gibbs 		}
1933d720e6d5SJustin T. Gibbs 	}
1934d720e6d5SJustin T. Gibbs 	if (mp->error) {
19354873663cSMatt Jacob 		int retval = CMD_COMPLETE;
19364873663cSMatt Jacob 		if (mp->error == MUSHERR_NOQENTRIES) {
19374873663cSMatt Jacob 			retval = CMD_EAGAIN;
19384873663cSMatt Jacob 		} else if (mp->error == EFBIG) {
19390a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_REQ_TOO_BIG);
1940d720e6d5SJustin T. Gibbs 		} else if (mp->error == EINVAL) {
19410a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_REQ_INVALID);
1942d720e6d5SJustin T. Gibbs 		} else {
19430a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_UNREC_HBA_ERROR);
1944d720e6d5SJustin T. Gibbs 		}
19454873663cSMatt Jacob 		return (retval);
19460a5f7e8bSMatt Jacob 	}
19474873663cSMatt Jacob 	return (CMD_QUEUED);
1948d720e6d5SJustin T. Gibbs }
1949d720e6d5SJustin T. Gibbs 
1950d720e6d5SJustin T. Gibbs static void
19513bda7a83SMatt Jacob isp_pci_reset0(ispsoftc_t *isp)
19523bda7a83SMatt Jacob {
19533bda7a83SMatt Jacob 	ISP_DISABLE_INTS(isp);
19543bda7a83SMatt Jacob }
19553bda7a83SMatt Jacob 
19563bda7a83SMatt Jacob static void
19579cd7268eSMatt Jacob isp_pci_reset1(ispsoftc_t *isp)
195865adb54cSMatt Jacob {
195910365e5aSMatt Jacob 	if (!IS_24XX(isp)) {
196065adb54cSMatt Jacob 		/* Make sure the BIOS is disabled */
196165adb54cSMatt Jacob 		isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS);
196210365e5aSMatt Jacob 	}
1963469b6b9eSMatt Jacob 	/* and enable interrupts */
196410365e5aSMatt Jacob 	ISP_ENABLE_INTS(isp);
196565adb54cSMatt Jacob }
196665adb54cSMatt Jacob 
196765adb54cSMatt Jacob static void
19689cd7268eSMatt Jacob isp_pci_dumpregs(ispsoftc_t *isp, const char *msg)
196965adb54cSMatt Jacob {
19701923f739SMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp;
1971d02373f1SMatt Jacob 	if (msg)
19726e5c5328SMatt Jacob 		printf("%s: %s\n", device_get_nameunit(isp->isp_dev), msg);
19736e5c5328SMatt Jacob 	else
19746e5c5328SMatt Jacob 		printf("%s:\n", device_get_nameunit(isp->isp_dev));
1975d02373f1SMatt Jacob 	if (IS_SCSI(isp))
1976d02373f1SMatt Jacob 		printf("    biu_conf1=%x", ISP_READ(isp, BIU_CONF1));
1977d02373f1SMatt Jacob 	else
1978d02373f1SMatt Jacob 		printf("    biu_csr=%x", ISP_READ(isp, BIU2100_CSR));
1979d02373f1SMatt Jacob 	printf(" biu_icr=%x biu_isr=%x biu_sema=%x ", ISP_READ(isp, BIU_ICR),
1980d02373f1SMatt Jacob 	    ISP_READ(isp, BIU_ISR), ISP_READ(isp, BIU_SEMA));
1981d02373f1SMatt Jacob 	printf("risc_hccr=%x\n", ISP_READ(isp, HCCR));
1982d02373f1SMatt Jacob 
1983d02373f1SMatt Jacob 
1984d02373f1SMatt Jacob 	if (IS_SCSI(isp)) {
1985d02373f1SMatt Jacob 		ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE);
1986d02373f1SMatt Jacob 		printf("    cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n",
1987d02373f1SMatt Jacob 			ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS),
1988d02373f1SMatt Jacob 			ISP_READ(isp, CDMA_FIFO_STS));
1989d02373f1SMatt Jacob 		printf("    ddma_conf=%x ddma_sts=%x ddma_fifostat=%x\n",
1990d02373f1SMatt Jacob 			ISP_READ(isp, DDMA_CONF), ISP_READ(isp, DDMA_STATUS),
1991d02373f1SMatt Jacob 			ISP_READ(isp, DDMA_FIFO_STS));
1992d02373f1SMatt Jacob 		printf("    sxp_int=%x sxp_gross=%x sxp(scsi_ctrl)=%x\n",
1993d02373f1SMatt Jacob 			ISP_READ(isp, SXP_INTERRUPT),
1994d02373f1SMatt Jacob 			ISP_READ(isp, SXP_GROSS_ERR),
1995d02373f1SMatt Jacob 			ISP_READ(isp, SXP_PINS_CTRL));
1996d02373f1SMatt Jacob 		ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE);
1997d02373f1SMatt Jacob 	}
1998d02373f1SMatt Jacob 	printf("    mbox regs: %x %x %x %x %x\n",
1999d02373f1SMatt Jacob 	    ISP_READ(isp, OUTMAILBOX0), ISP_READ(isp, OUTMAILBOX1),
2000d02373f1SMatt Jacob 	    ISP_READ(isp, OUTMAILBOX2), ISP_READ(isp, OUTMAILBOX3),
2001d02373f1SMatt Jacob 	    ISP_READ(isp, OUTMAILBOX4));
2002d02373f1SMatt Jacob 	printf("    PCI Status Command/Status=%x\n",
20031923f739SMatt Jacob 	    pci_read_config(pcs->pci_dev, PCIR_COMMAND, 1));
200465adb54cSMatt Jacob }
2005