xref: /freebsd/sys/dev/isp/isp_pci.c (revision 9e11e5bea2e6314f70f7e6e32c88868f35d921ab)
1c3aac50fSPeter Wemm /* $FreeBSD$ */
265adb54cSMatt Jacob /*
365adb54cSMatt Jacob  * PCI specific probe and attach routines for Qlogic ISP SCSI adapters.
465adb54cSMatt Jacob  * FreeBSD Version.
565adb54cSMatt Jacob  *
665adb54cSMatt Jacob  *---------------------------------------
7222bb542SMatt Jacob  * Copyright (c) 1997, 1998, 1999 by Matthew Jacob
865adb54cSMatt Jacob  * NASA/Ames Research Center
965adb54cSMatt Jacob  * All rights reserved.
1065adb54cSMatt Jacob  *---------------------------------------
1165adb54cSMatt Jacob  *
1265adb54cSMatt Jacob  * Redistribution and use in source and binary forms, with or without
1365adb54cSMatt Jacob  * modification, are permitted provided that the following conditions
1465adb54cSMatt Jacob  * are met:
1565adb54cSMatt Jacob  * 1. Redistributions of source code must retain the above copyright
1665adb54cSMatt Jacob  *    notice immediately at the beginning of the file, without modification,
1765adb54cSMatt Jacob  *    this list of conditions, and the following disclaimer.
1865adb54cSMatt Jacob  * 2. Redistributions in binary form must reproduce the above copyright
1965adb54cSMatt Jacob  *    notice, this list of conditions and the following disclaimer in the
2065adb54cSMatt Jacob  *    documentation and/or other materials provided with the distribution.
2165adb54cSMatt Jacob  * 3. The name of the author may not be used to endorse or promote products
2265adb54cSMatt Jacob  *    derived from this software without specific prior written permission.
2365adb54cSMatt Jacob  *
2465adb54cSMatt Jacob  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2565adb54cSMatt Jacob  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2665adb54cSMatt Jacob  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2765adb54cSMatt Jacob  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2865adb54cSMatt Jacob  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2965adb54cSMatt Jacob  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3065adb54cSMatt Jacob  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3165adb54cSMatt Jacob  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3265adb54cSMatt Jacob  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3365adb54cSMatt Jacob  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3465adb54cSMatt Jacob  * SUCH DAMAGE.
3565adb54cSMatt Jacob  */
3665adb54cSMatt Jacob #include <dev/isp/isp_freebsd.h>
3765adb54cSMatt Jacob #include <dev/isp/asm_pci.h>
38d720e6d5SJustin T. Gibbs #include <sys/malloc.h>
39d720e6d5SJustin T. Gibbs #include <vm/vm.h>
40d720e6d5SJustin T. Gibbs #include <vm/pmap.h>
41d720e6d5SJustin T. Gibbs 
4265adb54cSMatt Jacob 
4365adb54cSMatt Jacob #include <pci/pcireg.h>
4465adb54cSMatt Jacob #include <pci/pcivar.h>
4565adb54cSMatt Jacob 
46d720e6d5SJustin T. Gibbs #include <machine/bus_memio.h>
47d720e6d5SJustin T. Gibbs #include <machine/bus_pio.h>
48d720e6d5SJustin T. Gibbs #include <machine/bus.h>
49a95ae193SMatt Jacob #include <machine/md_var.h>
50d59bd469SMatt Jacob 
5165adb54cSMatt Jacob static u_int16_t isp_pci_rd_reg __P((struct ispsoftc *, int));
5265adb54cSMatt Jacob static void isp_pci_wr_reg __P((struct ispsoftc *, int, u_int16_t));
53d59bd469SMatt Jacob #ifndef ISP_DISABLE_1080_SUPPORT
54d59bd469SMatt Jacob static u_int16_t isp_pci_rd_reg_1080 __P((struct ispsoftc *, int));
55d59bd469SMatt Jacob static void isp_pci_wr_reg_1080 __P((struct ispsoftc *, int, u_int16_t));
56d59bd469SMatt Jacob #endif
5765adb54cSMatt Jacob static int isp_pci_mbxdma __P((struct ispsoftc *));
5865adb54cSMatt Jacob static int isp_pci_dmasetup __P((struct ispsoftc *, ISP_SCSI_XFER_T *,
599637d68cSMatt Jacob 	ispreq_t *, u_int16_t *, u_int16_t));
60d720e6d5SJustin T. Gibbs static void
61d720e6d5SJustin T. Gibbs isp_pci_dmateardown __P((struct ispsoftc *, ISP_SCSI_XFER_T *, u_int32_t));
6265adb54cSMatt Jacob 
6365adb54cSMatt Jacob static void isp_pci_reset1 __P((struct ispsoftc *));
6465adb54cSMatt Jacob static void isp_pci_dumpregs __P((struct ispsoftc *));
6565adb54cSMatt Jacob 
66fed92c47SMatt Jacob #ifndef	ISP_CODE_ORG
67fed92c47SMatt Jacob #define	ISP_CODE_ORG		0x1000
68fed92c47SMatt Jacob #endif
69fed92c47SMatt Jacob #ifndef	ISP_1040_RISC_CODE
70fed92c47SMatt Jacob #define	ISP_1040_RISC_CODE	NULL
71fed92c47SMatt Jacob #endif
72fed92c47SMatt Jacob #ifndef	ISP_1080_RISC_CODE
73fed92c47SMatt Jacob #define	ISP_1080_RISC_CODE	NULL
74fed92c47SMatt Jacob #endif
75fed92c47SMatt Jacob #ifndef	ISP_2100_RISC_CODE
76fed92c47SMatt Jacob #define	ISP_2100_RISC_CODE	NULL
77fed92c47SMatt Jacob #endif
78fed92c47SMatt Jacob #ifndef	ISP_2200_RISC_CODE
79fed92c47SMatt Jacob #define	ISP_2200_RISC_CODE	NULL
80fed92c47SMatt Jacob #endif
81fed92c47SMatt Jacob 
82d59bd469SMatt Jacob #ifndef ISP_DISABLE_1020_SUPPORT
8365adb54cSMatt Jacob static struct ispmdvec mdvec = {
8465adb54cSMatt Jacob 	isp_pci_rd_reg,
8565adb54cSMatt Jacob 	isp_pci_wr_reg,
8665adb54cSMatt Jacob 	isp_pci_mbxdma,
8765adb54cSMatt Jacob 	isp_pci_dmasetup,
88d720e6d5SJustin T. Gibbs 	isp_pci_dmateardown,
8965adb54cSMatt Jacob 	NULL,
9065adb54cSMatt Jacob 	isp_pci_reset1,
9165adb54cSMatt Jacob 	isp_pci_dumpregs,
92fed92c47SMatt Jacob 	ISP_1040_RISC_CODE,
93fed92c47SMatt Jacob 	0,
9465adb54cSMatt Jacob 	ISP_CODE_ORG,
95a95ae193SMatt Jacob 	0,
96285e230dSMatt Jacob 	BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64,
97d720e6d5SJustin T. Gibbs 	0
9865adb54cSMatt Jacob };
99d59bd469SMatt Jacob #endif
10065adb54cSMatt Jacob 
101d59bd469SMatt Jacob #ifndef ISP_DISABLE_1080_SUPPORT
102d59bd469SMatt Jacob static struct ispmdvec mdvec_1080 = {
103d59bd469SMatt Jacob 	isp_pci_rd_reg_1080,
104d59bd469SMatt Jacob 	isp_pci_wr_reg_1080,
105d59bd469SMatt Jacob 	isp_pci_mbxdma,
106d59bd469SMatt Jacob 	isp_pci_dmasetup,
107d59bd469SMatt Jacob 	isp_pci_dmateardown,
108d59bd469SMatt Jacob 	NULL,
109d59bd469SMatt Jacob 	isp_pci_reset1,
110d59bd469SMatt Jacob 	isp_pci_dumpregs,
111fed92c47SMatt Jacob 	ISP_1080_RISC_CODE,
112fed92c47SMatt Jacob 	0,
113fed92c47SMatt Jacob 	ISP_CODE_ORG,
114a95ae193SMatt Jacob 	0,
115d59bd469SMatt Jacob 	BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64,
116d59bd469SMatt Jacob 	0
117d59bd469SMatt Jacob };
118d59bd469SMatt Jacob #endif
119d59bd469SMatt Jacob 
120d59bd469SMatt Jacob #ifndef ISP_DISABLE_2100_SUPPORT
12165adb54cSMatt Jacob static struct ispmdvec mdvec_2100 = {
12265adb54cSMatt Jacob 	isp_pci_rd_reg,
12365adb54cSMatt Jacob 	isp_pci_wr_reg,
12465adb54cSMatt Jacob 	isp_pci_mbxdma,
12565adb54cSMatt Jacob 	isp_pci_dmasetup,
126d720e6d5SJustin T. Gibbs 	isp_pci_dmateardown,
12765adb54cSMatt Jacob 	NULL,
12865adb54cSMatt Jacob 	isp_pci_reset1,
12965adb54cSMatt Jacob 	isp_pci_dumpregs,
130fed92c47SMatt Jacob 	ISP_2100_RISC_CODE,
131fed92c47SMatt Jacob 	0,
132fed92c47SMatt Jacob 	ISP_CODE_ORG,
133a95ae193SMatt Jacob 	0,
134a95ae193SMatt Jacob 	0,
135d720e6d5SJustin T. Gibbs 	0
13665adb54cSMatt Jacob };
1375542fe4bSMatt Jacob #endif
138222bb542SMatt Jacob 
13986cb5d6bSMatt Jacob #ifndef	ISP_DISABLE_2200_SUPPORT
140222bb542SMatt Jacob static struct ispmdvec mdvec_2200 = {
141222bb542SMatt Jacob 	isp_pci_rd_reg,
142222bb542SMatt Jacob 	isp_pci_wr_reg,
143222bb542SMatt Jacob 	isp_pci_mbxdma,
144222bb542SMatt Jacob 	isp_pci_dmasetup,
145222bb542SMatt Jacob 	isp_pci_dmateardown,
146222bb542SMatt Jacob 	NULL,
147222bb542SMatt Jacob 	isp_pci_reset1,
148222bb542SMatt Jacob 	isp_pci_dumpregs,
149fed92c47SMatt Jacob 	ISP_2200_RISC_CODE,
150fed92c47SMatt Jacob 	0,
151fed92c47SMatt Jacob 	ISP_CODE_ORG,
152a95ae193SMatt Jacob 	0,
153222bb542SMatt Jacob 	0,
154222bb542SMatt Jacob 	0
155222bb542SMatt Jacob };
156d59bd469SMatt Jacob #endif
15765adb54cSMatt Jacob 
158d951bbcaSMatt Jacob #ifndef	SCSI_ISP_PREFER_MEM_MAP
159d951bbcaSMatt Jacob #define	SCSI_ISP_PREFER_MEM_MAP	0
160d951bbcaSMatt Jacob #endif
161d951bbcaSMatt Jacob 
16265adb54cSMatt Jacob #ifndef	PCIM_CMD_INVEN
16365adb54cSMatt Jacob #define	PCIM_CMD_INVEN			0x10
16465adb54cSMatt Jacob #endif
16565adb54cSMatt Jacob #ifndef	PCIM_CMD_BUSMASTEREN
16665adb54cSMatt Jacob #define	PCIM_CMD_BUSMASTEREN		0x0004
16765adb54cSMatt Jacob #endif
168d951bbcaSMatt Jacob #ifndef	PCIM_CMD_PERRESPEN
169d951bbcaSMatt Jacob #define	PCIM_CMD_PERRESPEN		0x0040
170d951bbcaSMatt Jacob #endif
171d951bbcaSMatt Jacob #ifndef	PCIM_CMD_SEREN
172d951bbcaSMatt Jacob #define	PCIM_CMD_SEREN			0x0100
173d951bbcaSMatt Jacob #endif
174d951bbcaSMatt Jacob 
175d951bbcaSMatt Jacob #ifndef	PCIR_COMMAND
176d951bbcaSMatt Jacob #define	PCIR_COMMAND			0x04
177d951bbcaSMatt Jacob #endif
178d951bbcaSMatt Jacob 
179d951bbcaSMatt Jacob #ifndef	PCIR_CACHELNSZ
180d951bbcaSMatt Jacob #define	PCIR_CACHELNSZ			0x0c
181d951bbcaSMatt Jacob #endif
182d951bbcaSMatt Jacob 
183d951bbcaSMatt Jacob #ifndef	PCIR_LATTIMER
184d951bbcaSMatt Jacob #define	PCIR_LATTIMER			0x0d
185d951bbcaSMatt Jacob #endif
186d951bbcaSMatt Jacob 
187ab6d0040SMatt Jacob #ifndef	PCIR_ROMADDR
188ab6d0040SMatt Jacob #define	PCIR_ROMADDR			0x30
189ab6d0040SMatt Jacob #endif
190ab6d0040SMatt Jacob 
19165adb54cSMatt Jacob #ifndef	PCI_VENDOR_QLOGIC
19265adb54cSMatt Jacob #define	PCI_VENDOR_QLOGIC	0x1077
19365adb54cSMatt Jacob #endif
19465adb54cSMatt Jacob 
19565adb54cSMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1020
19665adb54cSMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1020	0x1020
19765adb54cSMatt Jacob #endif
19865adb54cSMatt Jacob 
199d59bd469SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1080
200d59bd469SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1080	0x1080
201d59bd469SMatt Jacob #endif
202d59bd469SMatt Jacob 
203d59bd469SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1240
204d59bd469SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1240	0x1240
205d59bd469SMatt Jacob #endif
20665adb54cSMatt Jacob 
20722e1dc85SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1280
20822e1dc85SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1280	0x1280
20922e1dc85SMatt Jacob #endif
21022e1dc85SMatt Jacob 
21165adb54cSMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP2100
21265adb54cSMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2100	0x2100
21365adb54cSMatt Jacob #endif
21465adb54cSMatt Jacob 
215222bb542SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP2200
216222bb542SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2200	0x2200
217222bb542SMatt Jacob #endif
218222bb542SMatt Jacob 
219d59bd469SMatt Jacob #define	PCI_QLOGIC_ISP	((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC)
220d59bd469SMatt Jacob 
221d59bd469SMatt Jacob #define	PCI_QLOGIC_ISP1080	\
222d59bd469SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC)
223d59bd469SMatt Jacob 
224d59bd469SMatt Jacob #define	PCI_QLOGIC_ISP1240	\
225d59bd469SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC)
226d59bd469SMatt Jacob 
22722e1dc85SMatt Jacob #define	PCI_QLOGIC_ISP1280	\
22822e1dc85SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1280 << 16) | PCI_VENDOR_QLOGIC)
22922e1dc85SMatt Jacob 
23065adb54cSMatt Jacob #define	PCI_QLOGIC_ISP2100	\
23165adb54cSMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC)
23265adb54cSMatt Jacob 
233222bb542SMatt Jacob #define	PCI_QLOGIC_ISP2200	\
234222bb542SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2200 << 16) | PCI_VENDOR_QLOGIC)
235222bb542SMatt Jacob 
23665adb54cSMatt Jacob #define	IO_MAP_REG	0x10
23765adb54cSMatt Jacob #define	MEM_MAP_REG	0x14
23865adb54cSMatt Jacob 
239d951bbcaSMatt Jacob #define	PCI_DFLT_LTNCY	0x40
240d951bbcaSMatt Jacob #define	PCI_DFLT_LNSZ	0x10
24165adb54cSMatt Jacob 
242222bb542SMatt Jacob static const char *isp_pci_probe __P((pcici_t tag, pcidi_t type));
24365adb54cSMatt Jacob static void isp_pci_attach __P((pcici_t config_d, int unit));
24465adb54cSMatt Jacob 
245d720e6d5SJustin T. Gibbs /* This distinguishing define is not right, but it does work */
246a185f9b1SMatt Jacob #ifdef __alpha__
247a185f9b1SMatt Jacob #define IO_SPACE_MAPPING	ALPHA_BUS_SPACE_IO
248a185f9b1SMatt Jacob #define MEM_SPACE_MAPPING	ALPHA_BUS_SPACE_MEM
249a185f9b1SMatt Jacob #else
250a185f9b1SMatt Jacob #define IO_SPACE_MAPPING	I386_BUS_SPACE_IO
251a185f9b1SMatt Jacob #define MEM_SPACE_MAPPING	I386_BUS_SPACE_MEM
252a185f9b1SMatt Jacob #endif
25365adb54cSMatt Jacob 
25465adb54cSMatt Jacob struct isp_pcisoftc {
25565adb54cSMatt Jacob 	struct ispsoftc			pci_isp;
25665adb54cSMatt Jacob         pcici_t				pci_id;
25765adb54cSMatt Jacob 	bus_space_tag_t			pci_st;
25865adb54cSMatt Jacob 	bus_space_handle_t		pci_sh;
259d59bd469SMatt Jacob 	int16_t				pci_poff[_NREG_BLKS];
260d720e6d5SJustin T. Gibbs 	bus_dma_tag_t			parent_dmat;
261d720e6d5SJustin T. Gibbs 	bus_dma_tag_t			cntrol_dmat;
262d720e6d5SJustin T. Gibbs 	bus_dmamap_t			cntrol_dmap;
263a95ae193SMatt Jacob 	bus_dmamap_t			*dmaps;
26465adb54cSMatt Jacob };
26565adb54cSMatt Jacob 
266d720e6d5SJustin T. Gibbs static u_long ispunit;
26765adb54cSMatt Jacob 
26866235db5SEivind Eklund static struct pci_device isp_pci_driver = {
26965adb54cSMatt Jacob 	"isp",
27065adb54cSMatt Jacob 	isp_pci_probe,
27165adb54cSMatt Jacob 	isp_pci_attach,
272d720e6d5SJustin T. Gibbs 	&ispunit,
27365adb54cSMatt Jacob 	NULL
27465adb54cSMatt Jacob };
27596b3554eSPeter Wemm COMPAT_PCI_DRIVER (isp_pci, isp_pci_driver);
27665adb54cSMatt Jacob 
27765adb54cSMatt Jacob 
278222bb542SMatt Jacob static const char *
27917e318c6SMatt Jacob isp_pci_probe(pcici_t tag, pcidi_t type)
28065adb54cSMatt Jacob {
28165adb54cSMatt Jacob 	static int oneshot = 1;
28265adb54cSMatt Jacob 	char *x;
28365adb54cSMatt Jacob 
28465adb54cSMatt Jacob         switch (type) {
285d59bd469SMatt Jacob #ifndef	ISP_DISABLE_1020_SUPPORT
28665adb54cSMatt Jacob 	case PCI_QLOGIC_ISP:
287d59bd469SMatt Jacob 		x = "Qlogic ISP 1020/1040 PCI SCSI Adapter";
28865adb54cSMatt Jacob 		break;
289d59bd469SMatt Jacob #endif
290d59bd469SMatt Jacob #ifndef	ISP_DISABLE_1080_SUPPORT
291d59bd469SMatt Jacob 	case PCI_QLOGIC_ISP1080:
292c6608df3SMatt Jacob 		x = "Qlogic ISP 1080 PCI SCSI Adapter";
293c6608df3SMatt Jacob 		break;
294c6608df3SMatt Jacob 	case PCI_QLOGIC_ISP1240:
295c6608df3SMatt Jacob 		x = "Qlogic ISP 1240 PCI SCSI Adapter";
296d59bd469SMatt Jacob 		break;
29722e1dc85SMatt Jacob 	case PCI_QLOGIC_ISP1280:
29822e1dc85SMatt Jacob 		x = "Qlogic ISP 1280 PCI SCSI Adapter";
29922e1dc85SMatt Jacob 		break;
300d59bd469SMatt Jacob #endif
301d59bd469SMatt Jacob #ifndef	ISP_DISABLE_2100_SUPPORT
30265adb54cSMatt Jacob 	case PCI_QLOGIC_ISP2100:
30365adb54cSMatt Jacob 		x = "Qlogic ISP 2100 PCI FC-AL Adapter";
30465adb54cSMatt Jacob 		break;
305d59bd469SMatt Jacob #endif
3065542fe4bSMatt Jacob #ifndef	ISP_DISABLE_2200_SUPPORT
3075542fe4bSMatt Jacob 	case PCI_QLOGIC_ISP2200:
3085542fe4bSMatt Jacob 		x = "Qlogic ISP 2200 PCI FC-AL Adapter";
3095542fe4bSMatt Jacob 		break;
3105542fe4bSMatt Jacob #endif
31165adb54cSMatt Jacob 	default:
31265adb54cSMatt Jacob 		return (NULL);
31365adb54cSMatt Jacob 	}
31465adb54cSMatt Jacob 	if (oneshot) {
31565adb54cSMatt Jacob 		oneshot = 0;
316a95ae193SMatt Jacob 		CFGPRINTF("Qlogic ISP Driver, FreeBSD Version %d.%d, "
317a95ae193SMatt Jacob 		    "Core Version %d.%d\n",
318d720e6d5SJustin T. Gibbs 		    ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR,
319d720e6d5SJustin T. Gibbs 		    ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR);
32065adb54cSMatt Jacob 	}
32165adb54cSMatt Jacob 	return (x);
32265adb54cSMatt Jacob }
32365adb54cSMatt Jacob 
32465adb54cSMatt Jacob static void
325222bb542SMatt Jacob isp_pci_attach(pcici_t cfid, int unit)
32665adb54cSMatt Jacob {
3279637d68cSMatt Jacob #ifdef	SCSI_ISP_WWN
3289637d68cSMatt Jacob 	const char *name = SCSI_ISP_WWN;
3299637d68cSMatt Jacob 	char *vtp = NULL;
3309637d68cSMatt Jacob #endif
331222bb542SMatt Jacob 	int mapped, prefer_mem_map, bitmap;
332a185f9b1SMatt Jacob 	pci_port_t io_port;
3339637d68cSMatt Jacob 	u_int32_t data, rev, linesz, psize, basetype;
33465adb54cSMatt Jacob 	struct isp_pcisoftc *pcs;
33565adb54cSMatt Jacob 	struct ispsoftc *isp;
33665adb54cSMatt Jacob 	vm_offset_t vaddr, paddr;
337c6608df3SMatt Jacob 	struct ispmdvec *mdvp;
338222bb542SMatt Jacob 	bus_size_t lim;
33965adb54cSMatt Jacob 	ISP_LOCKVAL_DECL;
34065adb54cSMatt Jacob 
34165adb54cSMatt Jacob 	pcs = malloc(sizeof (struct isp_pcisoftc), M_DEVBUF, M_NOWAIT);
34265adb54cSMatt Jacob 	if (pcs == NULL) {
3439bffbcd4SBruce Evans 		printf("isp%d: cannot allocate softc\n", unit);
34465adb54cSMatt Jacob 		return;
34565adb54cSMatt Jacob 	}
34665adb54cSMatt Jacob 	bzero(pcs, sizeof (struct isp_pcisoftc));
34765adb54cSMatt Jacob 
348222bb542SMatt Jacob 	/*
3499ba86737SMatt Jacob 	 * Figure out if we're supposed to skip this one.
3509ba86737SMatt Jacob 	 */
3519ba86737SMatt Jacob 	if (getenv_int("isp_disable", &bitmap)) {
3529ba86737SMatt Jacob 		if (bitmap & (1 << unit)) {
3539ba86737SMatt Jacob 			printf("isp%d: not configuring\n", unit);
3549ba86737SMatt Jacob 			return;
3559ba86737SMatt Jacob 		}
3569ba86737SMatt Jacob 	}
3579ba86737SMatt Jacob 
3589ba86737SMatt Jacob 	/*
359222bb542SMatt Jacob 	 * Figure out which we should try first - memory mapping or i/o mapping?
360222bb542SMatt Jacob 	 */
361222bb542SMatt Jacob #if	SCSI_ISP_PREFER_MEM_MAP == 1
362222bb542SMatt Jacob 	prefer_mem_map = 1;
363222bb542SMatt Jacob #else
364222bb542SMatt Jacob 	prefer_mem_map = 0;
365222bb542SMatt Jacob #endif
366222bb542SMatt Jacob 	bitmap = 0;
367222bb542SMatt Jacob 	if (getenv_int("isp_mem_map", &bitmap)) {
368222bb542SMatt Jacob 		if (bitmap & (1 << unit))
369222bb542SMatt Jacob 			prefer_mem_map = 1;
370222bb542SMatt Jacob 	}
371222bb542SMatt Jacob 	bitmap = 0;
372222bb542SMatt Jacob 	if (getenv_int("isp_io_map", &bitmap)) {
373222bb542SMatt Jacob 		if (bitmap & (1 << unit))
374222bb542SMatt Jacob 			prefer_mem_map = 0;
375222bb542SMatt Jacob 	}
376222bb542SMatt Jacob 
37765adb54cSMatt Jacob 	vaddr = paddr = NULL;
37865adb54cSMatt Jacob 	mapped = 0;
379ab6d0040SMatt Jacob 	linesz = PCI_DFLT_LNSZ;
380d951bbcaSMatt Jacob 	/*
381d951bbcaSMatt Jacob 	 * Note that pci_conf_read is a 32 bit word aligned function.
382d951bbcaSMatt Jacob 	 */
383222bb542SMatt Jacob 	data = pci_conf_read(cfid, PCIR_COMMAND);
384222bb542SMatt Jacob 	if (prefer_mem_map) {
385222bb542SMatt Jacob 		if (data & PCI_COMMAND_MEM_ENABLE) {
386222bb542SMatt Jacob 			if (pci_map_mem(cfid, MEM_MAP_REG, &vaddr, &paddr)) {
387a185f9b1SMatt Jacob 				pcs->pci_st = MEM_SPACE_MAPPING;
388a185f9b1SMatt Jacob 				pcs->pci_sh = vaddr;
38965adb54cSMatt Jacob 				mapped++;
39065adb54cSMatt Jacob 			}
39165adb54cSMatt Jacob 		}
392a185f9b1SMatt Jacob 		if (mapped == 0 && (data & PCI_COMMAND_IO_ENABLE)) {
393222bb542SMatt Jacob 			if (pci_map_port(cfid, PCI_MAP_REG_START, &io_port)) {
394a185f9b1SMatt Jacob 				pcs->pci_st = IO_SPACE_MAPPING;
395a185f9b1SMatt Jacob 				pcs->pci_sh = io_port;
39665adb54cSMatt Jacob 				mapped++;
39765adb54cSMatt Jacob 			}
39865adb54cSMatt Jacob 		}
399222bb542SMatt Jacob 	} else {
400222bb542SMatt Jacob 		if (data & PCI_COMMAND_IO_ENABLE) {
401222bb542SMatt Jacob 			if (pci_map_port(cfid, PCI_MAP_REG_START, &io_port)) {
402d951bbcaSMatt Jacob 				pcs->pci_st = IO_SPACE_MAPPING;
403d951bbcaSMatt Jacob 				pcs->pci_sh = io_port;
404d951bbcaSMatt Jacob 				mapped++;
405d951bbcaSMatt Jacob 			}
406d951bbcaSMatt Jacob 		}
407d951bbcaSMatt Jacob 		if (mapped == 0 && (data & PCI_COMMAND_MEM_ENABLE)) {
408222bb542SMatt Jacob 			if (pci_map_mem(cfid, MEM_MAP_REG, &vaddr, &paddr)) {
409d951bbcaSMatt Jacob 				pcs->pci_st = MEM_SPACE_MAPPING;
410d951bbcaSMatt Jacob 				pcs->pci_sh = vaddr;
411d951bbcaSMatt Jacob 				mapped++;
412d951bbcaSMatt Jacob 			}
413d951bbcaSMatt Jacob 		}
414222bb542SMatt Jacob 	}
41565adb54cSMatt Jacob 	if (mapped == 0) {
4169bffbcd4SBruce Evans 		printf("isp%d: unable to map any ports!\n", unit);
41765adb54cSMatt Jacob 		free(pcs, M_DEVBUF);
41865adb54cSMatt Jacob 		return;
41965adb54cSMatt Jacob 	}
420222bb542SMatt Jacob 	if (bootverbose)
42165adb54cSMatt Jacob 		printf("isp%d: using %s space register mapping\n", unit,
422a185f9b1SMatt Jacob 		    pcs->pci_st == IO_SPACE_MAPPING? "I/O" : "Memory");
42365adb54cSMatt Jacob 
424222bb542SMatt Jacob 	data = pci_conf_read(cfid, PCI_ID_REG);
4259637d68cSMatt Jacob 	rev = pci_conf_read(cfid, PCI_CLASS_REG) & 0xff;	/* revision */
426d59bd469SMatt Jacob 	pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF;
427d59bd469SMatt Jacob 	pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF;
428d59bd469SMatt Jacob 	pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF;
429d59bd469SMatt Jacob 	pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF;
430d59bd469SMatt Jacob 	pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF;
431c6608df3SMatt Jacob 	/*
432c6608df3SMatt Jacob  	 * GCC!
433c6608df3SMatt Jacob 	 */
434c6608df3SMatt Jacob 	mdvp = &mdvec;
435c6608df3SMatt Jacob 	basetype = ISP_HA_SCSI_UNKNOWN;
436c6608df3SMatt Jacob 	psize = sizeof (sdparam);
437222bb542SMatt Jacob 	lim = BUS_SPACE_MAXSIZE_32BIT;
438d59bd469SMatt Jacob #ifndef	ISP_DISABLE_1020_SUPPORT
43965adb54cSMatt Jacob 	if (data == PCI_QLOGIC_ISP) {
440c6608df3SMatt Jacob 		mdvp = &mdvec;
441c6608df3SMatt Jacob 		basetype = ISP_HA_SCSI_UNKNOWN;
442c6608df3SMatt Jacob 		psize = sizeof (sdparam);
443222bb542SMatt Jacob 		lim = BUS_SPACE_MAXSIZE_24BIT;
444d59bd469SMatt Jacob 	}
445d59bd469SMatt Jacob #endif
446d59bd469SMatt Jacob #ifndef	ISP_DISABLE_1080_SUPPORT
447c6608df3SMatt Jacob 	if (data == PCI_QLOGIC_ISP1080) {
448c6608df3SMatt Jacob 		mdvp = &mdvec_1080;
449c6608df3SMatt Jacob 		basetype = ISP_HA_SCSI_1080;
450c6608df3SMatt Jacob 		psize = sizeof (sdparam);
451c6608df3SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
452c6608df3SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
453c6608df3SMatt Jacob 	}
454c6608df3SMatt Jacob 	if (data == PCI_QLOGIC_ISP1240) {
455c6608df3SMatt Jacob 		mdvp = &mdvec_1080;
45622e1dc85SMatt Jacob 		basetype = ISP_HA_SCSI_1240;
45722e1dc85SMatt Jacob 		psize = 2 * sizeof (sdparam);
45822e1dc85SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
45922e1dc85SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
46022e1dc85SMatt Jacob 	}
46122e1dc85SMatt Jacob 	if (data == PCI_QLOGIC_ISP1280) {
46222e1dc85SMatt Jacob 		mdvp = &mdvec_1080;
46322e1dc85SMatt Jacob 		basetype = ISP_HA_SCSI_1280;
464c6608df3SMatt Jacob 		psize = 2 * sizeof (sdparam);
465d59bd469SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
466d59bd469SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
467d59bd469SMatt Jacob 	}
468d59bd469SMatt Jacob #endif
469d59bd469SMatt Jacob #ifndef	ISP_DISABLE_2100_SUPPORT
470d59bd469SMatt Jacob 	if (data == PCI_QLOGIC_ISP2100) {
471c6608df3SMatt Jacob 		mdvp = &mdvec_2100;
472c6608df3SMatt Jacob 		basetype = ISP_HA_FC_2100;
473c6608df3SMatt Jacob 		psize = sizeof (fcparam);
474d59bd469SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
475d59bd469SMatt Jacob 		    PCI_MBOX_REGS2100_OFF;
4769637d68cSMatt Jacob 		if (rev < 3) {
477ab6d0040SMatt Jacob 			/*
478ab6d0040SMatt Jacob 			 * XXX: Need to get the actual revision
479ab6d0040SMatt Jacob 			 * XXX: number of the 2100 FB. At any rate,
480ab6d0040SMatt Jacob 			 * XXX: lower cache line size for early revision
481ab6d0040SMatt Jacob 			 * XXX; boards.
482ab6d0040SMatt Jacob 			 */
483ab6d0040SMatt Jacob 			linesz = 1;
484ab6d0040SMatt Jacob 		}
48565adb54cSMatt Jacob 	}
4865542fe4bSMatt Jacob #endif
4875542fe4bSMatt Jacob #ifndef	ISP_DISABLE_2200_SUPPORT
488222bb542SMatt Jacob 	if (data == PCI_QLOGIC_ISP2200) {
489222bb542SMatt Jacob 		mdvp = &mdvec_2200;
490222bb542SMatt Jacob 		basetype = ISP_HA_FC_2200;
491222bb542SMatt Jacob 		psize = sizeof (fcparam);
492222bb542SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
493222bb542SMatt Jacob 		    PCI_MBOX_REGS2100_OFF;
494222bb542SMatt Jacob 	}
495d59bd469SMatt Jacob #endif
496c6608df3SMatt Jacob 	isp = &pcs->pci_isp;
497c6608df3SMatt Jacob 	isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT);
498c6608df3SMatt Jacob 	if (isp->isp_param == NULL) {
499c6608df3SMatt Jacob 		printf("isp%d: cannot allocate parameter data\n", unit);
500c6608df3SMatt Jacob 		return;
501c6608df3SMatt Jacob 	}
502c6608df3SMatt Jacob 	bzero(isp->isp_param, psize);
503c6608df3SMatt Jacob 	isp->isp_mdvec = mdvp;
504c6608df3SMatt Jacob 	isp->isp_type = basetype;
5059637d68cSMatt Jacob 	isp->isp_revision = rev;
506c6608df3SMatt Jacob 	(void) snprintf(isp->isp_name, sizeof (isp->isp_name), "isp%d", unit);
507c6608df3SMatt Jacob 	isp->isp_osinfo.unit = unit;
50865adb54cSMatt Jacob 
509d951bbcaSMatt Jacob 	ISP_LOCK(isp);
510ab6d0040SMatt Jacob 
511d951bbcaSMatt Jacob 	/*
512d951bbcaSMatt Jacob 	 * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER
513d951bbcaSMatt Jacob 	 * are set.
514d951bbcaSMatt Jacob 	 */
515222bb542SMatt Jacob 	data = pci_cfgread(cfid, PCIR_COMMAND, 2);
516d951bbcaSMatt Jacob 	data |=	PCIM_CMD_SEREN		|
517d951bbcaSMatt Jacob 		PCIM_CMD_PERRESPEN	|
518d951bbcaSMatt Jacob 		PCIM_CMD_BUSMASTEREN	|
519d951bbcaSMatt Jacob 		PCIM_CMD_INVEN;
520222bb542SMatt Jacob 	pci_cfgwrite(cfid, PCIR_COMMAND, 2, data);
521ab6d0040SMatt Jacob 
522d951bbcaSMatt Jacob 	/*
523222bb542SMatt Jacob 	 * Make sure the Cache Line Size register is set sensibly.
524d951bbcaSMatt Jacob 	 */
525222bb542SMatt Jacob 	data = pci_cfgread(cfid, PCIR_CACHELNSZ, 1);
526ab6d0040SMatt Jacob 	if (data != linesz) {
527d951bbcaSMatt Jacob 		data = PCI_DFLT_LNSZ;
528a95ae193SMatt Jacob 		CFGPRINTF("%s: set PCI line size to %d\n", isp->isp_name, data);
529222bb542SMatt Jacob 		pci_cfgwrite(cfid, PCIR_CACHELNSZ, data, 1);
530d951bbcaSMatt Jacob 	}
531ab6d0040SMatt Jacob 
532d951bbcaSMatt Jacob 	/*
533d951bbcaSMatt Jacob 	 * Make sure the Latency Timer is sane.
534d951bbcaSMatt Jacob 	 */
535222bb542SMatt Jacob 	data = pci_cfgread(cfid, PCIR_LATTIMER, 1);
536d951bbcaSMatt Jacob 	if (data < PCI_DFLT_LTNCY) {
537d951bbcaSMatt Jacob 		data = PCI_DFLT_LTNCY;
538a95ae193SMatt Jacob 		CFGPRINTF("%s: set PCI latency to %d\n", isp->isp_name, data);
539222bb542SMatt Jacob 		pci_cfgwrite(cfid, PCIR_LATTIMER, data, 1);
540d951bbcaSMatt Jacob 	}
541ab6d0040SMatt Jacob 
542ab6d0040SMatt Jacob 	/*
543ab6d0040SMatt Jacob 	 * Make sure we've disabled the ROM.
544ab6d0040SMatt Jacob 	 */
545222bb542SMatt Jacob 	data = pci_cfgread(cfid, PCIR_ROMADDR, 4);
546ab6d0040SMatt Jacob 	data &= ~1;
547222bb542SMatt Jacob 	pci_cfgwrite(cfid, PCIR_ROMADDR, data, 4);
548d951bbcaSMatt Jacob 	ISP_UNLOCK(isp);
549d951bbcaSMatt Jacob 
550086646f7SJustin T. Gibbs 	if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
551222bb542SMatt Jacob 	    BUS_SPACE_MAXADDR, NULL, NULL, lim + 1,
552222bb542SMatt Jacob 	    255, lim, 0, &pcs->parent_dmat) != 0) {
553d720e6d5SJustin T. Gibbs 		printf("%s: could not create master dma tag\n", isp->isp_name);
554d720e6d5SJustin T. Gibbs 		free(pcs, M_DEVBUF);
555d720e6d5SJustin T. Gibbs 		return;
556d720e6d5SJustin T. Gibbs 	}
557222bb542SMatt Jacob 	if (pci_map_int(cfid, (void (*)(void *))isp_intr,
55865adb54cSMatt Jacob 	    (void *)isp, &IMASK) == 0) {
5599bffbcd4SBruce Evans 		printf("%s: could not map interrupt\n", isp->isp_name);
56065adb54cSMatt Jacob 		free(pcs, M_DEVBUF);
56165adb54cSMatt Jacob 		return;
56265adb54cSMatt Jacob 	}
56365adb54cSMatt Jacob 
564222bb542SMatt Jacob 	pcs->pci_id = cfid;
565d951bbcaSMatt Jacob #ifdef	SCSI_ISP_NO_FWLOAD_MASK
566d951bbcaSMatt Jacob 	if (SCSI_ISP_NO_FWLOAD_MASK && (SCSI_ISP_NO_FWLOAD_MASK & (1 << unit)))
567d951bbcaSMatt Jacob 		isp->isp_confopts |= ISP_CFG_NORELOAD;
568d951bbcaSMatt Jacob #endif
569222bb542SMatt Jacob 	if (getenv_int("isp_no_fwload", &bitmap)) {
570222bb542SMatt Jacob 		if (bitmap & (1 << unit))
571222bb542SMatt Jacob 			isp->isp_confopts |= ISP_CFG_NORELOAD;
572222bb542SMatt Jacob 	}
573222bb542SMatt Jacob 	if (getenv_int("isp_fwload", &bitmap)) {
574222bb542SMatt Jacob 		if (bitmap & (1 << unit))
575222bb542SMatt Jacob 			isp->isp_confopts &= ~ISP_CFG_NORELOAD;
576222bb542SMatt Jacob 	}
577222bb542SMatt Jacob 
578d951bbcaSMatt Jacob #ifdef	SCSI_ISP_NO_NVRAM_MASK
579ab6d0040SMatt Jacob 	if (SCSI_ISP_NO_NVRAM_MASK && (SCSI_ISP_NO_NVRAM_MASK & (1 << unit))) {
580ab6d0040SMatt Jacob 		printf("%s: ignoring NVRAM\n", isp->isp_name);
581d951bbcaSMatt Jacob 		isp->isp_confopts |= ISP_CFG_NONVRAM;
582ab6d0040SMatt Jacob 	}
583d951bbcaSMatt Jacob #endif
584222bb542SMatt Jacob 	if (getenv_int("isp_no_nvram", &bitmap)) {
585222bb542SMatt Jacob 		if (bitmap & (1 << unit))
586222bb542SMatt Jacob 			isp->isp_confopts |= ISP_CFG_NONVRAM;
587222bb542SMatt Jacob 	}
588222bb542SMatt Jacob 	if (getenv_int("isp_nvram", &bitmap)) {
589222bb542SMatt Jacob 		if (bitmap & (1 << unit))
590222bb542SMatt Jacob 			isp->isp_confopts &= ~ISP_CFG_NONVRAM;
591222bb542SMatt Jacob 	}
592222bb542SMatt Jacob 
593222bb542SMatt Jacob #ifdef	SCSI_ISP_FCDUPLEX
594222bb542SMatt Jacob 	if (IS_FC(isp)) {
595222bb542SMatt Jacob 		if (SCSI_ISP_FCDUPLEX && (SCSI_ISP_FCDUPLEX & (1 << unit))) {
596222bb542SMatt Jacob 			isp->isp_confopts |= ISP_CFG_FULL_DUPLEX;
597222bb542SMatt Jacob 		}
598222bb542SMatt Jacob 	}
599222bb542SMatt Jacob #endif
600222bb542SMatt Jacob 	if (getenv_int("isp_fcduplex", &bitmap)) {
601222bb542SMatt Jacob 		if (bitmap & (1 << unit))
602222bb542SMatt Jacob 			isp->isp_confopts |= ISP_CFG_FULL_DUPLEX;
603222bb542SMatt Jacob 	}
604222bb542SMatt Jacob 	if (getenv_int("isp_no_fcduplex", &bitmap)) {
605222bb542SMatt Jacob 		if (bitmap & (1 << unit))
606222bb542SMatt Jacob 			isp->isp_confopts &= ~ISP_CFG_FULL_DUPLEX;
607222bb542SMatt Jacob 	}
608222bb542SMatt Jacob 	/*
6099637d68cSMatt Jacob 	 * Look for overriding WWN. This is a Node WWN so it binds to
6109637d68cSMatt Jacob 	 * all FC instances. A Port WWN will be constructed from it
6119637d68cSMatt Jacob 	 * as appropriate.
612222bb542SMatt Jacob 	 */
6139637d68cSMatt Jacob #ifdef	SCSI_ISP_WWN
6149637d68cSMatt Jacob 	isp->isp_osinfo.default_wwn = strtoq(name, &vtp, 16);
6159637d68cSMatt Jacob 	if (vtp != name && *vtp == 0) {
6169637d68cSMatt Jacob 		isp->isp_confopts |= ISP_CFG_OWNWWN;
6179637d68cSMatt Jacob 	} else
6189637d68cSMatt Jacob #endif
6199637d68cSMatt Jacob 	if (!getenv_quad("isp_wwn", (quad_t *) &isp->isp_osinfo.default_wwn)) {
6209637d68cSMatt Jacob 		int i;
6219637d68cSMatt Jacob 		u_int64_t seed = (u_int64_t) (intptr_t) isp;
622222bb542SMatt Jacob 
6239637d68cSMatt Jacob 		seed <<= 16;
6249637d68cSMatt Jacob 		seed &= ((1LL << 48) - 1LL);
625222bb542SMatt Jacob 		/*
626222bb542SMatt Jacob 		 * This isn't very random, but it's the best we can do for
6279637d68cSMatt Jacob 		 * the real edge case of cards that don't have WWNs. If
6289637d68cSMatt Jacob 		 * you recompile a new vers.c, you'll get a different WWN.
629222bb542SMatt Jacob 		 */
6309637d68cSMatt Jacob 		for (i = 0; version[i] != 0; i++) {
6319637d68cSMatt Jacob 			seed += version[i];
6329637d68cSMatt Jacob 		}
6339637d68cSMatt Jacob 		/*
6349637d68cSMatt Jacob 		 * Make sure the top nibble has something vaguely sensible.
6359637d68cSMatt Jacob 		 */
6369637d68cSMatt Jacob 		isp->isp_osinfo.default_wwn |= (4LL << 60) | seed;
6379637d68cSMatt Jacob 	} else {
6389637d68cSMatt Jacob 		isp->isp_confopts |= ISP_CFG_OWNWWN;
639222bb542SMatt Jacob 	}
640a95ae193SMatt Jacob 	(void) getenv_int("isp_debug", &isp_debug);
641d720e6d5SJustin T. Gibbs 	ISP_LOCK(isp);
64265adb54cSMatt Jacob 	isp_reset(isp);
64365adb54cSMatt Jacob 	if (isp->isp_state != ISP_RESETSTATE) {
644222bb542SMatt Jacob 		(void) pci_unmap_int(cfid);
645d720e6d5SJustin T. Gibbs 		ISP_UNLOCK(isp);
64665adb54cSMatt Jacob 		free(pcs, M_DEVBUF);
64765adb54cSMatt Jacob 		return;
64865adb54cSMatt Jacob 	}
64965adb54cSMatt Jacob 	isp_init(isp);
65065adb54cSMatt Jacob 	if (isp->isp_state != ISP_INITSTATE) {
651d59bd469SMatt Jacob 		/* If we're a Fibre Channel Card, we allow deferred attach */
652222bb542SMatt Jacob 		if (IS_SCSI(isp)) {
65365adb54cSMatt Jacob 			isp_uninit(isp);
654222bb542SMatt Jacob 			(void) pci_unmap_int(cfid); /* Does nothing */
655c6608df3SMatt Jacob 			ISP_UNLOCK(isp);
65665adb54cSMatt Jacob 			free(pcs, M_DEVBUF);
657c6608df3SMatt Jacob 			return;
658d59bd469SMatt Jacob 		}
65965adb54cSMatt Jacob 	}
66065adb54cSMatt Jacob 	isp_attach(isp);
66165adb54cSMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE) {
662d59bd469SMatt Jacob 		/* If we're a Fibre Channel Card, we allow deferred attach */
66392c49d78SMatt Jacob 		if (IS_SCSI(isp)) {
66465adb54cSMatt Jacob 			isp_uninit(isp);
665222bb542SMatt Jacob 			(void) pci_unmap_int(cfid); /* Does nothing */
666c6608df3SMatt Jacob 			ISP_UNLOCK(isp);
66765adb54cSMatt Jacob 			free(pcs, M_DEVBUF);
668c6608df3SMatt Jacob 			return;
66965adb54cSMatt Jacob 		}
670d59bd469SMatt Jacob 	}
671d720e6d5SJustin T. Gibbs 	ISP_UNLOCK(isp);
67265adb54cSMatt Jacob }
67365adb54cSMatt Jacob 
67465adb54cSMatt Jacob static u_int16_t
675d59bd469SMatt Jacob isp_pci_rd_reg(isp, regoff)
676d59bd469SMatt Jacob 	struct ispsoftc *isp;
677d59bd469SMatt Jacob 	int regoff;
67865adb54cSMatt Jacob {
67965adb54cSMatt Jacob 	u_int16_t rv;
68065adb54cSMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
681d59bd469SMatt Jacob 	int offset, oldconf = 0;
68265adb54cSMatt Jacob 
683d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
68465adb54cSMatt Jacob 		/*
68565adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
68665adb54cSMatt Jacob 		 */
687d59bd469SMatt Jacob 		oldconf = isp_pci_rd_reg(isp, BIU_CONF1);
688d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP);
68965adb54cSMatt Jacob 	}
690d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
691d59bd469SMatt Jacob 	offset += (regoff & 0xff);
69265adb54cSMatt Jacob 	rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset);
693d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
694d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf);
69565adb54cSMatt Jacob 	}
69665adb54cSMatt Jacob 	return (rv);
69765adb54cSMatt Jacob }
69865adb54cSMatt Jacob 
69965adb54cSMatt Jacob static void
700d59bd469SMatt Jacob isp_pci_wr_reg(isp, regoff, val)
701d59bd469SMatt Jacob 	struct ispsoftc *isp;
702d59bd469SMatt Jacob 	int regoff;
703d59bd469SMatt Jacob 	u_int16_t val;
70465adb54cSMatt Jacob {
70565adb54cSMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
706d59bd469SMatt Jacob 	int offset, oldconf = 0;
707d59bd469SMatt Jacob 
708d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
70965adb54cSMatt Jacob 		/*
71065adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
71165adb54cSMatt Jacob 		 */
712d59bd469SMatt Jacob 		oldconf = isp_pci_rd_reg(isp, BIU_CONF1);
713d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP);
71465adb54cSMatt Jacob 	}
715d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
716d59bd469SMatt Jacob 	offset += (regoff & 0xff);
71765adb54cSMatt Jacob 	bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val);
718d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
719d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf);
72065adb54cSMatt Jacob 	}
72165adb54cSMatt Jacob }
72265adb54cSMatt Jacob 
723d59bd469SMatt Jacob #ifndef	ISP_DISABLE_1080_SUPPORT
724d59bd469SMatt Jacob static u_int16_t
725d59bd469SMatt Jacob isp_pci_rd_reg_1080(isp, regoff)
726d59bd469SMatt Jacob 	struct ispsoftc *isp;
727d59bd469SMatt Jacob 	int regoff;
728d59bd469SMatt Jacob {
72922e1dc85SMatt Jacob 	u_int16_t rv, oc = 0;
730d59bd469SMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
73122e1dc85SMatt Jacob 	int offset;
732d59bd469SMatt Jacob 
73322e1dc85SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
73422e1dc85SMatt Jacob 	    (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
73522e1dc85SMatt Jacob 		u_int16_t tc;
736d59bd469SMatt Jacob 		/*
737d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
738d59bd469SMatt Jacob 		 */
739d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
74022e1dc85SMatt Jacob 		tc = oc & ~BIU_PCI1080_CONF1_DMA;
74122e1dc85SMatt Jacob 		if (regoff & SXP_BANK1_SELECT)
74222e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP1;
74322e1dc85SMatt Jacob 		else
74422e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP0;
74522e1dc85SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, tc);
746d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
747d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
748d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA);
749d59bd469SMatt Jacob 	}
750d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
751d59bd469SMatt Jacob 	offset += (regoff & 0xff);
752d59bd469SMatt Jacob 	rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset);
75322e1dc85SMatt Jacob 	if (oc) {
754d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc);
755d59bd469SMatt Jacob 	}
756d59bd469SMatt Jacob 	return (rv);
757d59bd469SMatt Jacob }
758d59bd469SMatt Jacob 
759d59bd469SMatt Jacob static void
760d59bd469SMatt Jacob isp_pci_wr_reg_1080(isp, regoff, val)
761d59bd469SMatt Jacob 	struct ispsoftc *isp;
762d59bd469SMatt Jacob 	int regoff;
763d59bd469SMatt Jacob 	u_int16_t val;
764d59bd469SMatt Jacob {
765d59bd469SMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
766d59bd469SMatt Jacob 	int offset, oc = 0;
767d59bd469SMatt Jacob 
76822e1dc85SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
76922e1dc85SMatt Jacob 	    (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
77022e1dc85SMatt Jacob 		u_int16_t tc;
771d59bd469SMatt Jacob 		/*
772d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
773d59bd469SMatt Jacob 		 */
774d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
77522e1dc85SMatt Jacob 		tc = oc & ~BIU_PCI1080_CONF1_DMA;
77622e1dc85SMatt Jacob 		if (regoff & SXP_BANK1_SELECT)
77722e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP1;
77822e1dc85SMatt Jacob 		else
77922e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP0;
78022e1dc85SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, tc);
781d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
782d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
783d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA);
784d59bd469SMatt Jacob 	}
785d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
786d59bd469SMatt Jacob 	offset += (regoff & 0xff);
787d59bd469SMatt Jacob 	bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val);
78822e1dc85SMatt Jacob 	if (oc) {
789d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc);
790d59bd469SMatt Jacob 	}
791d59bd469SMatt Jacob }
792d59bd469SMatt Jacob #endif
793d59bd469SMatt Jacob 
794d59bd469SMatt Jacob 
795d720e6d5SJustin T. Gibbs static void isp_map_rquest __P((void *, bus_dma_segment_t *, int, int));
796d720e6d5SJustin T. Gibbs static void isp_map_result __P((void *, bus_dma_segment_t *, int, int));
797d720e6d5SJustin T. Gibbs static void isp_map_fcscrt __P((void *, bus_dma_segment_t *, int, int));
798d720e6d5SJustin T. Gibbs 
799222bb542SMatt Jacob struct imush {
800222bb542SMatt Jacob 	struct ispsoftc *isp;
801222bb542SMatt Jacob 	int error;
802222bb542SMatt Jacob };
803222bb542SMatt Jacob 
804d720e6d5SJustin T. Gibbs static void
80517e318c6SMatt Jacob isp_map_rquest(void *arg, bus_dma_segment_t *segs, int nseg, int error)
806d720e6d5SJustin T. Gibbs {
807222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
808222bb542SMatt Jacob 	if (error) {
809222bb542SMatt Jacob 		imushp->error = error;
810222bb542SMatt Jacob 	} else {
811222bb542SMatt Jacob 		imushp->isp->isp_rquest_dma = segs->ds_addr;
812222bb542SMatt Jacob 	}
813d720e6d5SJustin T. Gibbs }
814d720e6d5SJustin T. Gibbs 
815d720e6d5SJustin T. Gibbs static void
81617e318c6SMatt Jacob isp_map_result(void *arg, bus_dma_segment_t *segs, int nseg, int error)
817d720e6d5SJustin T. Gibbs {
818222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
819222bb542SMatt Jacob 	if (error) {
820222bb542SMatt Jacob 		imushp->error = error;
821222bb542SMatt Jacob 	} else {
822222bb542SMatt Jacob 		imushp->isp->isp_result_dma = segs->ds_addr;
823222bb542SMatt Jacob 	}
824d720e6d5SJustin T. Gibbs }
825d720e6d5SJustin T. Gibbs 
826d720e6d5SJustin T. Gibbs static void
82717e318c6SMatt Jacob isp_map_fcscrt(void *arg, bus_dma_segment_t *segs, int nseg, int error)
828d720e6d5SJustin T. Gibbs {
829222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
830222bb542SMatt Jacob 	if (error) {
831222bb542SMatt Jacob 		imushp->error = error;
832222bb542SMatt Jacob 	} else {
833222bb542SMatt Jacob 		fcparam *fcp = imushp->isp->isp_param;
834d720e6d5SJustin T. Gibbs 		fcp->isp_scdma = segs->ds_addr;
835d720e6d5SJustin T. Gibbs 	}
836222bb542SMatt Jacob }
837d720e6d5SJustin T. Gibbs 
838d720e6d5SJustin T. Gibbs static int
83917e318c6SMatt Jacob isp_pci_mbxdma(struct ispsoftc *isp)
840d720e6d5SJustin T. Gibbs {
841d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
842d720e6d5SJustin T. Gibbs 	caddr_t base;
843d720e6d5SJustin T. Gibbs 	u_int32_t len;
844d720e6d5SJustin T. Gibbs 	int i, error;
845222bb542SMatt Jacob 	bus_size_t lim;
846222bb542SMatt Jacob 	struct imush im;
847222bb542SMatt Jacob 
848222bb542SMatt Jacob 
849a95ae193SMatt Jacob 	/*
850a95ae193SMatt Jacob 	 * Already been here? If so, leave...
851a95ae193SMatt Jacob 	 */
852a95ae193SMatt Jacob 	if (isp->isp_rquest) {
853a95ae193SMatt Jacob 		return (0);
854a95ae193SMatt Jacob 	}
855a95ae193SMatt Jacob 
856a95ae193SMatt Jacob 	len = sizeof (ISP_SCSI_XFER_T **) * isp->isp_maxcmds;
857a95ae193SMatt Jacob 	isp->isp_xflist = (ISP_SCSI_XFER_T **) malloc(len, M_DEVBUF, M_WAITOK);
858a95ae193SMatt Jacob 	if (isp->isp_xflist == NULL) {
859a95ae193SMatt Jacob 		printf("%s: can't alloc xflist array\n", isp->isp_name);
860a95ae193SMatt Jacob 		return (1);
861a95ae193SMatt Jacob 	}
862a95ae193SMatt Jacob 	bzero(isp->isp_xflist, len);
863a95ae193SMatt Jacob 	len = sizeof (bus_dmamap_t) * isp->isp_maxcmds;
864a95ae193SMatt Jacob 	pci->dmaps = (bus_dmamap_t *) malloc(len, M_DEVBUF,  M_WAITOK);
865a95ae193SMatt Jacob 	if (pci->dmaps == NULL) {
866a95ae193SMatt Jacob 		printf("%s: can't alloc dma maps\n", isp->isp_name);
867a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
868a95ae193SMatt Jacob 		return (1);
869a95ae193SMatt Jacob 	}
870a95ae193SMatt Jacob 
87122e1dc85SMatt Jacob 	if (IS_FC(isp) || IS_ULTRA2(isp))
872222bb542SMatt Jacob 		lim = BUS_SPACE_MAXADDR + 1;
873222bb542SMatt Jacob 	else
874222bb542SMatt Jacob 		lim = BUS_SPACE_MAXADDR_24BIT + 1;
875d720e6d5SJustin T. Gibbs 
876d720e6d5SJustin T. Gibbs 	/*
877d720e6d5SJustin T. Gibbs 	 * Allocate and map the request, result queues, plus FC scratch area.
878d720e6d5SJustin T. Gibbs 	 */
879d720e6d5SJustin T. Gibbs 	len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN);
880d720e6d5SJustin T. Gibbs 	len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN);
881222bb542SMatt Jacob 	if (IS_FC(isp)) {
882d720e6d5SJustin T. Gibbs 		len += ISP2100_SCRLEN;
883d720e6d5SJustin T. Gibbs 	}
884222bb542SMatt Jacob 	if (bus_dma_tag_create(pci->parent_dmat, PAGE_SIZE, lim,
885222bb542SMatt Jacob 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, len, 1,
886222bb542SMatt Jacob 	    BUS_SPACE_MAXSIZE_32BIT, 0, &pci->cntrol_dmat) != 0) {
887d720e6d5SJustin T. Gibbs 		printf("%s: cannot create a dma tag for control spaces\n",
888d720e6d5SJustin T. Gibbs 		    isp->isp_name);
889a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
890a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
891d720e6d5SJustin T. Gibbs 		return (1);
892d720e6d5SJustin T. Gibbs 	}
893d720e6d5SJustin T. Gibbs 	if (bus_dmamem_alloc(pci->cntrol_dmat, (void **)&base,
894d720e6d5SJustin T. Gibbs 	    BUS_DMA_NOWAIT, &pci->cntrol_dmap) != 0) {
8954873663cSMatt Jacob 		printf("%s: cannot allocate %d bytes of CCB memory\n",
8964873663cSMatt Jacob 		    isp->isp_name, len);
897a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
898a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
899d720e6d5SJustin T. Gibbs 		return (1);
900d720e6d5SJustin T. Gibbs 	}
901d720e6d5SJustin T. Gibbs 
902d720e6d5SJustin T. Gibbs 	isp->isp_rquest = base;
903222bb542SMatt Jacob 	im.isp = isp;
904222bb542SMatt Jacob 	im.error = 0;
905d720e6d5SJustin T. Gibbs 	bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_rquest,
906222bb542SMatt Jacob 	    ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN), isp_map_rquest, &im, 0);
907222bb542SMatt Jacob 	if (im.error) {
908222bb542SMatt Jacob 		printf("%s: error %d loading dma map for DMA request queue\n",
909222bb542SMatt Jacob 		    isp->isp_name, im.error);
910a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
911a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
912a95ae193SMatt Jacob 		isp->isp_rquest = NULL;
913222bb542SMatt Jacob 		return (1);
914222bb542SMatt Jacob 	}
915d720e6d5SJustin T. Gibbs 	isp->isp_result = base + ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN);
916222bb542SMatt Jacob 	im.error = 0;
917d720e6d5SJustin T. Gibbs 	bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_result,
918222bb542SMatt Jacob 	    ISP_QUEUE_SIZE(RESULT_QUEUE_LEN), isp_map_result, &im, 0);
919222bb542SMatt Jacob 	if (im.error) {
920222bb542SMatt Jacob 		printf("%s: error %d loading dma map for DMA result queue\n",
921222bb542SMatt Jacob 		    isp->isp_name, im.error);
922a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
923a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
924a95ae193SMatt Jacob 		isp->isp_rquest = NULL;
925222bb542SMatt Jacob 		return (1);
926222bb542SMatt Jacob 	}
927d720e6d5SJustin T. Gibbs 
928a95ae193SMatt Jacob 	for (i = 0; i < isp->isp_maxcmds; i++) {
929d720e6d5SJustin T. Gibbs 		error = bus_dmamap_create(pci->parent_dmat, 0, &pci->dmaps[i]);
930d720e6d5SJustin T. Gibbs 		if (error) {
931a95ae193SMatt Jacob 			printf("%s: error %d creating per-cmd DMA maps\n",
932d720e6d5SJustin T. Gibbs 			    isp->isp_name, error);
933a95ae193SMatt Jacob 			free(isp->isp_xflist, M_DEVBUF);
934a95ae193SMatt Jacob 			free(pci->dmaps, M_DEVBUF);
935a95ae193SMatt Jacob 			isp->isp_rquest = NULL;
936d720e6d5SJustin T. Gibbs 			return (1);
937d720e6d5SJustin T. Gibbs 		}
938d720e6d5SJustin T. Gibbs 	}
939a95ae193SMatt Jacob 
940222bb542SMatt Jacob 	if (IS_FC(isp)) {
94192c49d78SMatt Jacob 		fcparam *fcp = (fcparam *) isp->isp_param;
94292c49d78SMatt Jacob 		fcp->isp_scratch = base +
94392c49d78SMatt Jacob 			ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN) +
94492c49d78SMatt Jacob 			ISP_QUEUE_SIZE(RESULT_QUEUE_LEN);
945222bb542SMatt Jacob 		im.error = 0;
94692c49d78SMatt Jacob 		bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap,
947222bb542SMatt Jacob 		    fcp->isp_scratch, ISP2100_SCRLEN, isp_map_fcscrt, &im, 0);
948222bb542SMatt Jacob 		if (im.error) {
949222bb542SMatt Jacob 			printf("%s: error %d loading FC scratch area\n",
950222bb542SMatt Jacob 			    isp->isp_name, im.error);
951a95ae193SMatt Jacob 			free(isp->isp_xflist, M_DEVBUF);
952a95ae193SMatt Jacob 			free(pci->dmaps, M_DEVBUF);
953a95ae193SMatt Jacob 			isp->isp_rquest = NULL;
954222bb542SMatt Jacob 			return (1);
955222bb542SMatt Jacob 		}
95692c49d78SMatt Jacob 	}
957d720e6d5SJustin T. Gibbs 	return (0);
958d720e6d5SJustin T. Gibbs }
959d720e6d5SJustin T. Gibbs 
960d720e6d5SJustin T. Gibbs typedef struct {
961d720e6d5SJustin T. Gibbs 	struct ispsoftc *isp;
9629e11e5beSMatt Jacob 	void *cmd_token;
9639e11e5beSMatt Jacob 	void *rq;
9649637d68cSMatt Jacob 	u_int16_t *iptrp;
9659637d68cSMatt Jacob 	u_int16_t optr;
966d720e6d5SJustin T. Gibbs 	u_int error;
967d720e6d5SJustin T. Gibbs } mush_t;
968d720e6d5SJustin T. Gibbs 
9694873663cSMatt Jacob #define	MUSHERR_NOQENTRIES	-2
9704873663cSMatt Jacob 
9719e11e5beSMatt Jacob #ifdef	ISP_TARGET_MODE
9729e11e5beSMatt Jacob /*
9739e11e5beSMatt Jacob  * We need to handle DMA for target mode differently from initiator mode.
9749e11e5beSMatt Jacob  *
9759e11e5beSMatt Jacob  * DMA mapping and construction and submission of CTIO Request Entries
9769e11e5beSMatt Jacob  * and rendevous for completion are very tightly coupled because we start
9779e11e5beSMatt Jacob  * out by knowing (per platform) how much data we have to move, but we
9789e11e5beSMatt Jacob  * don't know, up front, how many DMA mapping segments will have to be used
9799e11e5beSMatt Jacob  * cover that data, so we don't know how many CTIO Request Entries we
9809e11e5beSMatt Jacob  * will end up using. Further, for performance reasons we may want to
9819e11e5beSMatt Jacob  * (on the last CTIO for Fibre Channel), send status too (if all went well).
9829e11e5beSMatt Jacob  *
9839e11e5beSMatt Jacob  * The standard vector still goes through isp_pci_dmasetup, but the callback
9849e11e5beSMatt Jacob  * for the DMA mapping routines comes here instead with the whole transfer
9859e11e5beSMatt Jacob  * mapped and a pointer to a partially filled in already allocated request
9869e11e5beSMatt Jacob  * queue entry. We finish the job.
9879e11e5beSMatt Jacob  */
9889e11e5beSMatt Jacob static void dma2_tgt __P((void *, bus_dma_segment_t *, int, int));
9899e11e5beSMatt Jacob static void dma2_tgt_fc __P((void *, bus_dma_segment_t *, int, int));
9909e11e5beSMatt Jacob 
991d720e6d5SJustin T. Gibbs static void
9929e11e5beSMatt Jacob dma2_tgt(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
993d720e6d5SJustin T. Gibbs {
994d720e6d5SJustin T. Gibbs 	mush_t *mp;
9959e11e5beSMatt Jacob 	struct ccb_scsiio *csio;
996d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci;
997d720e6d5SJustin T. Gibbs 	bus_dmamap_t *dp;
9989e11e5beSMatt Jacob 	u_int8_t scsi_status, send_status;
9999e11e5beSMatt Jacob 	ct_entry_t *cto;
10009e11e5beSMatt Jacob 	u_int32_t handle;
10019e11e5beSMatt Jacob 	int nctios;
1002d720e6d5SJustin T. Gibbs 
1003d720e6d5SJustin T. Gibbs 	mp = (mush_t *) arg;
1004d720e6d5SJustin T. Gibbs 	if (error) {
1005d720e6d5SJustin T. Gibbs 		mp->error = error;
1006d720e6d5SJustin T. Gibbs 		return;
1007d720e6d5SJustin T. Gibbs 	}
1008d720e6d5SJustin T. Gibbs 
1009d720e6d5SJustin T. Gibbs 	if (nseg < 1) {
10109e11e5beSMatt Jacob 		printf("%s: bad segment count (%d)\n", mp->isp->isp_name, nseg);
1011d720e6d5SJustin T. Gibbs 		mp->error = EFAULT;
1012d720e6d5SJustin T. Gibbs 		return;
1013d720e6d5SJustin T. Gibbs 	}
1014a95ae193SMatt Jacob 
10159e11e5beSMatt Jacob 	csio = mp->cmd_token;
10169e11e5beSMatt Jacob 	cto = mp->rq;
10179e11e5beSMatt Jacob 
10189e11e5beSMatt Jacob 	/*
10199e11e5beSMatt Jacob 	 * Save handle, and potentially any SCSI status, which
10209e11e5beSMatt Jacob 	 * we'll reinsert on the last CTIO we're going to send.
10219e11e5beSMatt Jacob 	 */
10229e11e5beSMatt Jacob 	handle = cto->ct_reserved;
10239e11e5beSMatt Jacob 	cto->ct_reserved = 0;
10249e11e5beSMatt Jacob 	scsi_status = cto->ct_scsi_status;
10259e11e5beSMatt Jacob 	cto->ct_scsi_status = 0;
10269e11e5beSMatt Jacob 	send_status = cto->ct_flags & CT_SENDSTATUS;
10279e11e5beSMatt Jacob 	cto->ct_flags &= ~CT_SENDSTATUS;
10289e11e5beSMatt Jacob 
10299e11e5beSMatt Jacob 	pci = (struct isp_pcisoftc *)mp->isp;
10309e11e5beSMatt Jacob 	dp = &pci->dmaps[handle - 1];
10319e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1032d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
1033d720e6d5SJustin T. Gibbs 	} else {
1034d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
1035d720e6d5SJustin T. Gibbs 	}
1036d720e6d5SJustin T. Gibbs 
10379e11e5beSMatt Jacob 	nctios = nseg / ISP_RQDSEG;
10389e11e5beSMatt Jacob 	if (nseg % ISP_RQDSEG) {
10399e11e5beSMatt Jacob 		nctios++;
10409e11e5beSMatt Jacob 	}
10419e11e5beSMatt Jacob 
10429e11e5beSMatt Jacob 	cto->ct_xfrlen = 0;
10439e11e5beSMatt Jacob 	cto->ct_resid = 0;
10449e11e5beSMatt Jacob 	cto->ct_seg_count = 0;
10459e11e5beSMatt Jacob 	bzero(cto->ct_dataseg, sizeof (cto->ct_dataseg));
10469e11e5beSMatt Jacob 
10479e11e5beSMatt Jacob 	while (nctios--) {
10489e11e5beSMatt Jacob 		int seg, seglim;
10499e11e5beSMatt Jacob 
10509e11e5beSMatt Jacob 		seglim = nseg;
10519e11e5beSMatt Jacob 		if (seglim > ISP_RQDSEG)
10529e11e5beSMatt Jacob 			seglim = ISP_RQDSEG;
10539e11e5beSMatt Jacob 
10549e11e5beSMatt Jacob 		for (seg = 0; seg < seglim; seg++) {
10559e11e5beSMatt Jacob 			cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr;
10569e11e5beSMatt Jacob 			cto->ct_dataseg[seg].ds_count = dm_segs->ds_len;
10579e11e5beSMatt Jacob 			cto->ct_xfrlen += dm_segs->ds_len;
10589e11e5beSMatt Jacob 			dm_segs++;
10599e11e5beSMatt Jacob 		}
10609e11e5beSMatt Jacob 
10619e11e5beSMatt Jacob 		cto->ct_seg_count = seg;
10629e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
10639e11e5beSMatt Jacob 			cto->ct_flags |= CT_DATA_IN;
10649e11e5beSMatt Jacob 		} else {
10659e11e5beSMatt Jacob 			cto->ct_flags |= CT_DATA_OUT;
10669e11e5beSMatt Jacob 		}
10679e11e5beSMatt Jacob 
10689e11e5beSMatt Jacob 		if (nctios == 0) {
10699e11e5beSMatt Jacob 			/*
10709e11e5beSMatt Jacob 			 * We're the last in a sequence of CTIOs, so mark this
10719e11e5beSMatt Jacob 			 * CTIO and save the handle to the CCB such that when
10729e11e5beSMatt Jacob 			 * this CTIO completes we can free dma resources and
10739e11e5beSMatt Jacob 			 * do whatever else we need to do to finish the rest
10749e11e5beSMatt Jacob 			 * of the command.
10759e11e5beSMatt Jacob 			 */
10769e11e5beSMatt Jacob 			cto->ct_header.rqs_seqno = 1;
10779e11e5beSMatt Jacob 			cto->ct_reserved = handle;
10789e11e5beSMatt Jacob 			cto->ct_scsi_status = scsi_status;
10799e11e5beSMatt Jacob 			cto->ct_flags |= send_status;
10809e11e5beSMatt Jacob 			ISP_TDQE(mp->isp, "last dma2_tgt", *mp->iptrp, cto);
10819e11e5beSMatt Jacob 		} else {
10829e11e5beSMatt Jacob 			ct_entry_t *octo = cto;
10839e11e5beSMatt Jacob 			cto->ct_reserved = 0;
10849e11e5beSMatt Jacob 			cto->ct_header.rqs_seqno = 0;
10859e11e5beSMatt Jacob 			ISP_TDQE(mp->isp, "dma2_tgt", *mp->iptrp, cto);
10869e11e5beSMatt Jacob 			cto = (ct_entry_t *)
10879e11e5beSMatt Jacob 			    ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
10889e11e5beSMatt Jacob 			*mp->iptrp =
10899e11e5beSMatt Jacob 			    ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN);
10909e11e5beSMatt Jacob 			if (*mp->iptrp == mp->optr) {
10919e11e5beSMatt Jacob 				printf("%s: Queue Overflow in dma2_tgt\n",
10929e11e5beSMatt Jacob 				    mp->isp->isp_name);
10939e11e5beSMatt Jacob 				mp->error = MUSHERR_NOQENTRIES;
10949e11e5beSMatt Jacob 				return;
10959e11e5beSMatt Jacob 			}
10969e11e5beSMatt Jacob 			/*
10979e11e5beSMatt Jacob 			 * Fill in the new CTIO with info from the old one.
10989e11e5beSMatt Jacob 			 */
10999e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
11009e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_count = 1;
11019e11e5beSMatt Jacob 			cto->ct_header.rqs_flags = 0;
11029e11e5beSMatt Jacob 			/* ct_header.rqs_seqno && ct_reserved filled in later */
11039e11e5beSMatt Jacob 			cto->ct_lun = octo->ct_lun;
11049e11e5beSMatt Jacob 			cto->ct_iid = octo->ct_iid;
11059e11e5beSMatt Jacob 			cto->ct_reserved2 = octo->ct_reserved2;
11069e11e5beSMatt Jacob 			cto->ct_tgt = octo->ct_tgt;
11079e11e5beSMatt Jacob 			cto->ct_flags = octo->ct_flags & ~CT_DATAMASK;
11089e11e5beSMatt Jacob 			cto->ct_status = 0;
11099e11e5beSMatt Jacob 			cto->ct_scsi_status = 0;
11109e11e5beSMatt Jacob 			cto->ct_tag_val = octo->ct_tag_val;
11119e11e5beSMatt Jacob 			cto->ct_tag_type = octo->ct_tag_type;
11129e11e5beSMatt Jacob 			cto->ct_xfrlen = 0;
11139e11e5beSMatt Jacob 			cto->ct_resid = 0;
11149e11e5beSMatt Jacob 			cto->ct_timeout = octo->ct_timeout;
11159e11e5beSMatt Jacob 			cto->ct_seg_count = 0;
11169e11e5beSMatt Jacob 			bzero(cto->ct_dataseg, sizeof (cto->ct_dataseg));
11179e11e5beSMatt Jacob 		}
11189e11e5beSMatt Jacob 	}
11199e11e5beSMatt Jacob }
11209e11e5beSMatt Jacob 
11219e11e5beSMatt Jacob static void
11229e11e5beSMatt Jacob dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
11239e11e5beSMatt Jacob {
11249e11e5beSMatt Jacob 	mush_t *mp;
11259e11e5beSMatt Jacob 	struct ccb_scsiio *csio;
11269e11e5beSMatt Jacob 	struct isp_pcisoftc *pci;
11279e11e5beSMatt Jacob 	bus_dmamap_t *dp;
11289e11e5beSMatt Jacob 	ct2_entry_t *cto;
11299e11e5beSMatt Jacob 	u_int16_t scsi_status, send_status;
11309e11e5beSMatt Jacob 	u_int32_t handle, reloff;
11319e11e5beSMatt Jacob 	int nctios;
11329e11e5beSMatt Jacob 
11339e11e5beSMatt Jacob 	mp = (mush_t *) arg;
11349e11e5beSMatt Jacob 	if (error) {
11359e11e5beSMatt Jacob 		mp->error = error;
11369e11e5beSMatt Jacob 		return;
11379e11e5beSMatt Jacob 	}
11389e11e5beSMatt Jacob 
11399e11e5beSMatt Jacob 	if (nseg < 1) {
11409e11e5beSMatt Jacob 		printf("%s: bad segment count (%d)\n", mp->isp->isp_name, nseg);
11419e11e5beSMatt Jacob 		mp->error = EFAULT;
11429e11e5beSMatt Jacob 		return;
11439e11e5beSMatt Jacob 	}
11449e11e5beSMatt Jacob 
11459e11e5beSMatt Jacob 	csio = mp->cmd_token;
11469e11e5beSMatt Jacob 	cto = mp->rq;
11479e11e5beSMatt Jacob 	/*
11489e11e5beSMatt Jacob 	 * Save handle, and potentially any SCSI status, which
11499e11e5beSMatt Jacob 	 * we'll reinsert on the last CTIO we're going to send.
11509e11e5beSMatt Jacob 	 */
11519e11e5beSMatt Jacob 	handle = cto->ct_reserved;
11529e11e5beSMatt Jacob 	cto->ct_reserved = 0;
11539e11e5beSMatt Jacob 	scsi_status = cto->rsp.m0.ct_scsi_status;
11549e11e5beSMatt Jacob 	cto->rsp.m0.ct_scsi_status = 0;
11559e11e5beSMatt Jacob 	send_status = cto->ct_flags & CT2_SENDSTATUS;
11569e11e5beSMatt Jacob 	cto->ct_flags &= ~CT2_SENDSTATUS;
11579e11e5beSMatt Jacob 
11589e11e5beSMatt Jacob 	pci = (struct isp_pcisoftc *)mp->isp;
11599e11e5beSMatt Jacob 	dp = &pci->dmaps[handle - 1];
11609e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
11619e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
11629e11e5beSMatt Jacob 	} else {
11639e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
11649e11e5beSMatt Jacob 	}
11659e11e5beSMatt Jacob 
11669e11e5beSMatt Jacob 	nctios = nseg / ISP_RQDSEG_T2;
11679e11e5beSMatt Jacob 	if (nseg % ISP_RQDSEG_T2) {
11689e11e5beSMatt Jacob 		nctios++;
11699e11e5beSMatt Jacob 	}
11709e11e5beSMatt Jacob 
11719e11e5beSMatt Jacob 	cto->ct_reloff = 0;
11729e11e5beSMatt Jacob 	cto->ct_resid = 0;
11739e11e5beSMatt Jacob 	cto->ct_seg_count = 0;
11749e11e5beSMatt Jacob 	cto->ct_reloff = reloff = 0;
11759e11e5beSMatt Jacob 	bzero(&cto->rsp, sizeof (cto->rsp));
11769e11e5beSMatt Jacob 
11779e11e5beSMatt Jacob 	while (nctios--) {
11789e11e5beSMatt Jacob 		int seg, seglim;
11799e11e5beSMatt Jacob 
11809e11e5beSMatt Jacob 		seglim = nseg;
11819e11e5beSMatt Jacob 		if (seglim > ISP_RQDSEG_T2)
11829e11e5beSMatt Jacob 			seglim = ISP_RQDSEG_T2;
11839e11e5beSMatt Jacob 
11849e11e5beSMatt Jacob 		for (seg = 0; seg < seglim; seg++) {
11859e11e5beSMatt Jacob 			cto->rsp.m0.ct_dataseg[seg].ds_base = dm_segs->ds_addr;
11869e11e5beSMatt Jacob 			cto->rsp.m0.ct_dataseg[seg].ds_count = dm_segs->ds_len;
11879e11e5beSMatt Jacob 			cto->rsp.m0.ct_xfrlen += dm_segs->ds_len;
11889e11e5beSMatt Jacob 			reloff += dm_segs->ds_len;
11899e11e5beSMatt Jacob 			dm_segs++;
11909e11e5beSMatt Jacob 		}
11919e11e5beSMatt Jacob 
11929e11e5beSMatt Jacob 		cto->ct_seg_count = seg;
11939e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
11949e11e5beSMatt Jacob 			cto->ct_flags |= CT2_DATA_IN;
11959e11e5beSMatt Jacob 		} else {
11969e11e5beSMatt Jacob 			cto->ct_flags |= CT2_DATA_OUT;
11979e11e5beSMatt Jacob 		}
11989e11e5beSMatt Jacob 
11999e11e5beSMatt Jacob 		if (nctios == 0) {
12009e11e5beSMatt Jacob 			/*
12019e11e5beSMatt Jacob 			 * We're the last in a sequence of CTIOs, so mark this
12029e11e5beSMatt Jacob 			 * CTIO and save the handle to the CCB such that when
12039e11e5beSMatt Jacob 			 * this CTIO completes we can free dma resources and
12049e11e5beSMatt Jacob 			 * do whatever else we need to do to finish the rest
12059e11e5beSMatt Jacob 			 * of the command.
12069e11e5beSMatt Jacob 			 */
12079e11e5beSMatt Jacob 			cto->ct_header.rqs_seqno = 1;
12089e11e5beSMatt Jacob 			cto->ct_reserved = handle;
12099e11e5beSMatt Jacob 			cto->rsp.m0.ct_scsi_status = scsi_status;
12109e11e5beSMatt Jacob 			cto->ct_flags |= send_status;
12119e11e5beSMatt Jacob 			ISP_TDQE(mp->isp, "last dma2_tgt_fc", *mp->iptrp, cto);
12129e11e5beSMatt Jacob 		} else {
12139e11e5beSMatt Jacob 			ct2_entry_t *octo = cto;
12149e11e5beSMatt Jacob 			cto->ct_reserved = 0;
12159e11e5beSMatt Jacob 			cto->ct_header.rqs_seqno = 0;
12169e11e5beSMatt Jacob 			ISP_TDQE(mp->isp, "dma2_tgt_fc", *mp->iptrp, cto);
12179e11e5beSMatt Jacob 			cto = (ct2_entry_t *)
12189e11e5beSMatt Jacob 			    ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
12199e11e5beSMatt Jacob 			*mp->iptrp =
12209e11e5beSMatt Jacob 			    ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN);
12219e11e5beSMatt Jacob 			if (*mp->iptrp == mp->optr) {
12229e11e5beSMatt Jacob 				printf("%s: Queue Overflow in dma2_tgt_fc\n",
12239e11e5beSMatt Jacob 				    mp->isp->isp_name);
12249e11e5beSMatt Jacob 				mp->error = MUSHERR_NOQENTRIES;
12259e11e5beSMatt Jacob 				return;
12269e11e5beSMatt Jacob 			}
12279e11e5beSMatt Jacob 			/*
12289e11e5beSMatt Jacob 			 * Fill in the new CTIO with info from the old one.
12299e11e5beSMatt Jacob 			 */
12309e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
12319e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_count = 1;
12329e11e5beSMatt Jacob 			cto->ct_header.rqs_flags = 0;
12339e11e5beSMatt Jacob 			/* ct_header.rqs_seqno && ct_reserved filled in later */
12349e11e5beSMatt Jacob 			cto->ct_lun = octo->ct_lun;
12359e11e5beSMatt Jacob 			cto->ct_iid = octo->ct_iid;
12369e11e5beSMatt Jacob 			cto->ct_rxid = octo->ct_rxid;
12379e11e5beSMatt Jacob 			cto->ct_flags = octo->ct_flags & ~CT2_DATAMASK;
12389e11e5beSMatt Jacob 			cto->ct_status = 0;
12399e11e5beSMatt Jacob 			cto->ct_resid = 0;
12409e11e5beSMatt Jacob 			cto->ct_timeout = octo->ct_timeout;
12419e11e5beSMatt Jacob 			cto->ct_seg_count = 0;
12429e11e5beSMatt Jacob 			cto->ct_reloff = reloff;
12439e11e5beSMatt Jacob 			bzero(&cto->rsp, sizeof (cto->rsp));
12449e11e5beSMatt Jacob 		}
12459e11e5beSMatt Jacob 	}
12469e11e5beSMatt Jacob }
12479e11e5beSMatt Jacob #endif
12489e11e5beSMatt Jacob 
12499e11e5beSMatt Jacob static void dma2 __P((void *, bus_dma_segment_t *, int, int));
12509e11e5beSMatt Jacob 
12519e11e5beSMatt Jacob static void
12529e11e5beSMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
12539e11e5beSMatt Jacob {
12549e11e5beSMatt Jacob 	mush_t *mp;
12559e11e5beSMatt Jacob 	struct ccb_scsiio *csio;
12569e11e5beSMatt Jacob 	struct isp_pcisoftc *pci;
12579e11e5beSMatt Jacob 	bus_dmamap_t *dp;
12589e11e5beSMatt Jacob 	bus_dma_segment_t *eseg;
12599e11e5beSMatt Jacob 	ispreq_t *rq;
12609e11e5beSMatt Jacob 	ispcontreq_t *crq;
12619e11e5beSMatt Jacob 	int seglim, datalen;
12629e11e5beSMatt Jacob 
12639e11e5beSMatt Jacob 	mp = (mush_t *) arg;
12649e11e5beSMatt Jacob 	if (error) {
12659e11e5beSMatt Jacob 		mp->error = error;
12669e11e5beSMatt Jacob 		return;
12679e11e5beSMatt Jacob 	}
12689e11e5beSMatt Jacob 
12699e11e5beSMatt Jacob 	if (nseg < 1) {
12709e11e5beSMatt Jacob 		printf("%s: bad segment count (%d)\n", mp->isp->isp_name, nseg);
12719e11e5beSMatt Jacob 		mp->error = EFAULT;
12729e11e5beSMatt Jacob 		return;
12739e11e5beSMatt Jacob 	}
12749e11e5beSMatt Jacob 	csio = mp->cmd_token;
12759e11e5beSMatt Jacob 	rq = mp->rq;
12769e11e5beSMatt Jacob 	pci = (struct isp_pcisoftc *)mp->isp;
12779e11e5beSMatt Jacob 	dp = &pci->dmaps[rq->req_handle - 1];
12789e11e5beSMatt Jacob 
12799e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
12809e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
12819e11e5beSMatt Jacob 	} else {
12829e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
12839e11e5beSMatt Jacob 	}
12849e11e5beSMatt Jacob 
12859e11e5beSMatt Jacob 	datalen = XS_XFRLEN(csio);
12869e11e5beSMatt Jacob 
12879e11e5beSMatt Jacob 	/*
12889e11e5beSMatt Jacob 	 * We're passed an initial partially filled in entry that
12899e11e5beSMatt Jacob 	 * has most fields filled in except for data transfer
12909e11e5beSMatt Jacob 	 * related values.
12919e11e5beSMatt Jacob 	 *
12929e11e5beSMatt Jacob 	 * Our job is to fill in the initial request queue entry and
12939e11e5beSMatt Jacob 	 * then to start allocating and filling in continuation entries
12949e11e5beSMatt Jacob 	 * until we've covered the entire transfer.
12959e11e5beSMatt Jacob 	 */
12969e11e5beSMatt Jacob 
12979e11e5beSMatt Jacob 	if (IS_FC(mp->isp)) {
1298d720e6d5SJustin T. Gibbs 		seglim = ISP_RQDSEG_T2;
1299d720e6d5SJustin T. Gibbs 		((ispreqt2_t *)rq)->req_totalcnt = datalen;
13009e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
13019e11e5beSMatt Jacob 			((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_IN;
13029e11e5beSMatt Jacob 		} else {
13039e11e5beSMatt Jacob 			((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_OUT;
13049e11e5beSMatt Jacob 		}
1305d720e6d5SJustin T. Gibbs 	} else {
1306d720e6d5SJustin T. Gibbs 		seglim = ISP_RQDSEG;
13079e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
13089e11e5beSMatt Jacob 			rq->req_flags |= REQFLAG_DATA_IN;
13099e11e5beSMatt Jacob 		} else {
13109e11e5beSMatt Jacob 			rq->req_flags |= REQFLAG_DATA_OUT;
13119e11e5beSMatt Jacob 		}
1312d720e6d5SJustin T. Gibbs 	}
1313d720e6d5SJustin T. Gibbs 
1314d720e6d5SJustin T. Gibbs 	eseg = dm_segs + nseg;
1315d720e6d5SJustin T. Gibbs 
1316d720e6d5SJustin T. Gibbs 	while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) {
13179e11e5beSMatt Jacob 		if (IS_FC(mp->isp)) {
1318d720e6d5SJustin T. Gibbs 			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
1319d720e6d5SJustin T. Gibbs 			rq2->req_dataseg[rq2->req_seg_count].ds_base =
1320d720e6d5SJustin T. Gibbs 			    dm_segs->ds_addr;
1321d720e6d5SJustin T. Gibbs 			rq2->req_dataseg[rq2->req_seg_count].ds_count =
1322d720e6d5SJustin T. Gibbs 			    dm_segs->ds_len;
1323d720e6d5SJustin T. Gibbs 		} else {
1324d720e6d5SJustin T. Gibbs 			rq->req_dataseg[rq->req_seg_count].ds_base =
1325d720e6d5SJustin T. Gibbs 				dm_segs->ds_addr;
1326d720e6d5SJustin T. Gibbs 			rq->req_dataseg[rq->req_seg_count].ds_count =
1327d720e6d5SJustin T. Gibbs 				dm_segs->ds_len;
1328d720e6d5SJustin T. Gibbs 		}
1329d720e6d5SJustin T. Gibbs 		datalen -= dm_segs->ds_len;
1330d720e6d5SJustin T. Gibbs #if	0
13319e11e5beSMatt Jacob 		if (IS_FC(mp->isp)) {
1332d720e6d5SJustin T. Gibbs 			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
1333d720e6d5SJustin T. Gibbs 			printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n",
13349e11e5beSMatt Jacob 			    mp->isp->isp_name, rq->req_seg_count,
1335d720e6d5SJustin T. Gibbs 			    rq2->req_dataseg[rq2->req_seg_count].ds_count,
1336d720e6d5SJustin T. Gibbs 			    rq2->req_dataseg[rq2->req_seg_count].ds_base);
1337d720e6d5SJustin T. Gibbs 		} else {
1338d720e6d5SJustin T. Gibbs 			printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n",
13399e11e5beSMatt Jacob 			    mp->isp->isp_name, rq->req_seg_count,
1340d720e6d5SJustin T. Gibbs 			    rq->req_dataseg[rq->req_seg_count].ds_count,
1341d720e6d5SJustin T. Gibbs 			    rq->req_dataseg[rq->req_seg_count].ds_base);
1342d720e6d5SJustin T. Gibbs 		}
1343d720e6d5SJustin T. Gibbs #endif
1344d720e6d5SJustin T. Gibbs 		rq->req_seg_count++;
1345d720e6d5SJustin T. Gibbs 		dm_segs++;
1346d720e6d5SJustin T. Gibbs 	}
1347d720e6d5SJustin T. Gibbs 
1348d720e6d5SJustin T. Gibbs 	while (datalen > 0 && dm_segs != eseg) {
13499e11e5beSMatt Jacob 		crq = (ispcontreq_t *)
13509e11e5beSMatt Jacob 		    ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
13519e11e5beSMatt Jacob 		*mp->iptrp = ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN);
13529e11e5beSMatt Jacob 		if (*mp->iptrp == mp->optr) {
13534873663cSMatt Jacob #if	0
13549e11e5beSMatt Jacob 			printf("%s: Request Queue Overflow++\n",
13559e11e5beSMatt Jacob 			    mp->isp->isp_name);
13564873663cSMatt Jacob #endif
13574873663cSMatt Jacob 			mp->error = MUSHERR_NOQENTRIES;
1358d720e6d5SJustin T. Gibbs 			return;
1359d720e6d5SJustin T. Gibbs 		}
1360d720e6d5SJustin T. Gibbs 		rq->req_header.rqs_entry_count++;
1361d720e6d5SJustin T. Gibbs 		bzero((void *)crq, sizeof (*crq));
1362d720e6d5SJustin T. Gibbs 		crq->req_header.rqs_entry_count = 1;
1363d720e6d5SJustin T. Gibbs 		crq->req_header.rqs_entry_type = RQSTYPE_DATASEG;
1364d720e6d5SJustin T. Gibbs 
1365d720e6d5SJustin T. Gibbs 		seglim = 0;
1366d720e6d5SJustin T. Gibbs 		while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) {
1367d720e6d5SJustin T. Gibbs 			crq->req_dataseg[seglim].ds_base =
1368d720e6d5SJustin T. Gibbs 			    dm_segs->ds_addr;
1369d720e6d5SJustin T. Gibbs 			crq->req_dataseg[seglim].ds_count =
1370d720e6d5SJustin T. Gibbs 			    dm_segs->ds_len;
1371d720e6d5SJustin T. Gibbs #if	0
1372d720e6d5SJustin T. Gibbs 			printf("%s: seg%d[%d] cnt 0x%x paddr 0x%08x\n",
13739e11e5beSMatt Jacob 			    mp->isp->isp_name, rq->req_header.rqs_entry_count-1,
1374d720e6d5SJustin T. Gibbs 			    seglim, crq->req_dataseg[seglim].ds_count,
1375d720e6d5SJustin T. Gibbs 			    crq->req_dataseg[seglim].ds_base);
1376d720e6d5SJustin T. Gibbs #endif
1377d720e6d5SJustin T. Gibbs 			rq->req_seg_count++;
1378d720e6d5SJustin T. Gibbs 			dm_segs++;
1379d720e6d5SJustin T. Gibbs 			seglim++;
1380d720e6d5SJustin T. Gibbs 			datalen -= dm_segs->ds_len;
1381d720e6d5SJustin T. Gibbs 		}
1382d720e6d5SJustin T. Gibbs 	}
1383d720e6d5SJustin T. Gibbs }
1384d720e6d5SJustin T. Gibbs 
1385d720e6d5SJustin T. Gibbs static int
13869e11e5beSMatt Jacob isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq,
13879637d68cSMatt Jacob 	u_int16_t *iptrp, u_int16_t optr)
1388d720e6d5SJustin T. Gibbs {
1389d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
13900a5f7e8bSMatt Jacob 	bus_dmamap_t *dp = NULL;
1391d720e6d5SJustin T. Gibbs 	mush_t mush, *mp;
13929e11e5beSMatt Jacob 	void (*eptr) __P((void *, bus_dma_segment_t *, int, int));
1393d720e6d5SJustin T. Gibbs 
13949e11e5beSMatt Jacob #ifdef	ISP_TARGET_MODE
13959e11e5beSMatt Jacob 	if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) {
13969e11e5beSMatt Jacob 		if (IS_FC(isp)) {
13979e11e5beSMatt Jacob 			eptr = dma2_tgt_fc;
13989e11e5beSMatt Jacob 		} else {
13999e11e5beSMatt Jacob 			eptr = dma2_tgt;
14009e11e5beSMatt Jacob 		}
14019e11e5beSMatt Jacob 	} else
14029e11e5beSMatt Jacob #endif
14039e11e5beSMatt Jacob 	eptr = dma2;
1404d720e6d5SJustin T. Gibbs 
14059e11e5beSMatt Jacob 	/*
14069e11e5beSMatt Jacob 	 * NB: if we need to do request queue entry swizzling,
14079e11e5beSMatt Jacob 	 * NB: this is where it would need to be done for cmds
14089e11e5beSMatt Jacob 	 * NB: that move no data. For commands that move data,
14099e11e5beSMatt Jacob 	 * NB: swizzling would take place in those functions.
14109e11e5beSMatt Jacob 	 */
14119e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) {
1412d720e6d5SJustin T. Gibbs 		rq->req_seg_count = 1;
14134873663cSMatt Jacob 		return (CMD_QUEUED);
1414d720e6d5SJustin T. Gibbs 	}
1415d720e6d5SJustin T. Gibbs 
1416d720e6d5SJustin T. Gibbs 	/*
1417d720e6d5SJustin T. Gibbs 	 * Do a virtual grapevine step to collect info for
14184873663cSMatt Jacob 	 * the callback dma allocation that we have to use...
1419d720e6d5SJustin T. Gibbs 	 */
1420d720e6d5SJustin T. Gibbs 	mp = &mush;
1421d720e6d5SJustin T. Gibbs 	mp->isp = isp;
14229e11e5beSMatt Jacob 	mp->cmd_token = csio;
1423d720e6d5SJustin T. Gibbs 	mp->rq = rq;
1424d720e6d5SJustin T. Gibbs 	mp->iptrp = iptrp;
1425d720e6d5SJustin T. Gibbs 	mp->optr = optr;
1426d720e6d5SJustin T. Gibbs 	mp->error = 0;
1427d720e6d5SJustin T. Gibbs 
14289e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
14299e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) {
14304873663cSMatt Jacob 			int error, s;
14310a5f7e8bSMatt Jacob 			dp = &pci->dmaps[rq->req_handle - 1];
1432d720e6d5SJustin T. Gibbs 			s = splsoftvm();
1433d720e6d5SJustin T. Gibbs 			error = bus_dmamap_load(pci->parent_dmat, *dp,
14349e11e5beSMatt Jacob 			    csio->data_ptr, csio->dxfer_len, eptr, mp, 0);
1435d720e6d5SJustin T. Gibbs 			if (error == EINPROGRESS) {
1436d720e6d5SJustin T. Gibbs 				bus_dmamap_unload(pci->parent_dmat, *dp);
1437d720e6d5SJustin T. Gibbs 				mp->error = EINVAL;
14384873663cSMatt Jacob 				printf("%s: deferred dma allocation not "
14394873663cSMatt Jacob 				    "supported\n", isp->isp_name);
1440d720e6d5SJustin T. Gibbs 			} else if (error && mp->error == 0) {
14410a5f7e8bSMatt Jacob #ifdef	DIAGNOSTIC
14420a5f7e8bSMatt Jacob 				printf("%s: error %d in dma mapping code\n",
14430a5f7e8bSMatt Jacob 				    isp->isp_name, error);
14440a5f7e8bSMatt Jacob #endif
1445d720e6d5SJustin T. Gibbs 				mp->error = error;
1446d720e6d5SJustin T. Gibbs 			}
14474873663cSMatt Jacob 			splx(s);
1448d720e6d5SJustin T. Gibbs 		} else {
1449d720e6d5SJustin T. Gibbs 			/* Pointer to physical buffer */
1450d720e6d5SJustin T. Gibbs 			struct bus_dma_segment seg;
1451d720e6d5SJustin T. Gibbs 			seg.ds_addr = (bus_addr_t)csio->data_ptr;
1452d720e6d5SJustin T. Gibbs 			seg.ds_len = csio->dxfer_len;
14539e11e5beSMatt Jacob 			(*eptr)(mp, &seg, 1, 0);
1454d720e6d5SJustin T. Gibbs 		}
1455d720e6d5SJustin T. Gibbs 	} else {
1456d720e6d5SJustin T. Gibbs 		struct bus_dma_segment *segs;
1457d720e6d5SJustin T. Gibbs 
14589e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) {
1459d720e6d5SJustin T. Gibbs 			printf("%s: Physical segment pointers unsupported",
1460d720e6d5SJustin T. Gibbs 				isp->isp_name);
1461d720e6d5SJustin T. Gibbs 			mp->error = EINVAL;
14629e11e5beSMatt Jacob 		} else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) {
1463d720e6d5SJustin T. Gibbs 			printf("%s: Virtual segment addresses unsupported",
1464d720e6d5SJustin T. Gibbs 				isp->isp_name);
1465d720e6d5SJustin T. Gibbs 			mp->error = EINVAL;
1466d720e6d5SJustin T. Gibbs 		} else {
1467d720e6d5SJustin T. Gibbs 			/* Just use the segments provided */
1468d720e6d5SJustin T. Gibbs 			segs = (struct bus_dma_segment *) csio->data_ptr;
14699e11e5beSMatt Jacob 			(*eptr)(mp, segs, csio->sglist_cnt, 0);
1470d720e6d5SJustin T. Gibbs 		}
1471d720e6d5SJustin T. Gibbs 	}
1472d720e6d5SJustin T. Gibbs 	if (mp->error) {
14734873663cSMatt Jacob 		int retval = CMD_COMPLETE;
14744873663cSMatt Jacob 		if (mp->error == MUSHERR_NOQENTRIES) {
14754873663cSMatt Jacob 			retval = CMD_EAGAIN;
14764873663cSMatt Jacob 		} else if (mp->error == EFBIG) {
14770a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_REQ_TOO_BIG);
1478d720e6d5SJustin T. Gibbs 		} else if (mp->error == EINVAL) {
14790a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_REQ_INVALID);
1480d720e6d5SJustin T. Gibbs 		} else {
14810a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_UNREC_HBA_ERROR);
1482d720e6d5SJustin T. Gibbs 		}
14834873663cSMatt Jacob 		return (retval);
14844873663cSMatt Jacob 	} else {
14850a5f7e8bSMatt Jacob 		/*
14860a5f7e8bSMatt Jacob 		 * Check to see if we weren't cancelled while sleeping on
14870a5f7e8bSMatt Jacob 		 * getting DMA resources...
14880a5f7e8bSMatt Jacob 		 */
14899e11e5beSMatt Jacob 		if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
14900a5f7e8bSMatt Jacob 			if (dp) {
14910a5f7e8bSMatt Jacob 				bus_dmamap_unload(pci->parent_dmat, *dp);
14920a5f7e8bSMatt Jacob 			}
14930a5f7e8bSMatt Jacob 			return (CMD_COMPLETE);
14940a5f7e8bSMatt Jacob 		}
14954873663cSMatt Jacob 		return (CMD_QUEUED);
1496d720e6d5SJustin T. Gibbs 	}
1497d720e6d5SJustin T. Gibbs }
1498d720e6d5SJustin T. Gibbs 
1499d720e6d5SJustin T. Gibbs static void
1500a95ae193SMatt Jacob isp_pci_dmateardown(struct ispsoftc *isp, ISP_SCSI_XFER_T *xs, u_int32_t handle)
1501d720e6d5SJustin T. Gibbs {
1502d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
1503a95ae193SMatt Jacob 	bus_dmamap_t *dp = &pci->dmaps[handle - 1];
1504a95ae193SMatt Jacob 	KASSERT((handle > 0 && handle <= isp->isp_maxcmds),
1505a95ae193SMatt Jacob 	    ("bad handle in isp_pci_dmateardonw"));
1506a95ae193SMatt Jacob 	if ((xs->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1507d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTREAD);
1508d720e6d5SJustin T. Gibbs 	} else {
1509d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTWRITE);
1510d720e6d5SJustin T. Gibbs 	}
1511d720e6d5SJustin T. Gibbs 	bus_dmamap_unload(pci->parent_dmat, *dp);
1512d720e6d5SJustin T. Gibbs }
1513d720e6d5SJustin T. Gibbs 
151465adb54cSMatt Jacob 
151565adb54cSMatt Jacob static void
151617e318c6SMatt Jacob isp_pci_reset1(struct ispsoftc *isp)
151765adb54cSMatt Jacob {
151865adb54cSMatt Jacob 	/* Make sure the BIOS is disabled */
151965adb54cSMatt Jacob 	isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS);
152065adb54cSMatt Jacob }
152165adb54cSMatt Jacob 
152265adb54cSMatt Jacob static void
152317e318c6SMatt Jacob isp_pci_dumpregs(struct ispsoftc *isp)
152465adb54cSMatt Jacob {
152565adb54cSMatt Jacob 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
15269bffbcd4SBruce Evans 	printf("%s: PCI Status Command/Status=%lx\n", pci->pci_isp.isp_name,
1527d951bbcaSMatt Jacob 	    pci_conf_read(pci->pci_id, PCIR_COMMAND));
152865adb54cSMatt Jacob }
1529