xref: /freebsd/sys/dev/isp/isp_pci.c (revision d8d5f2adc5b00838b0470e6a78706a9298df4ce8)
1c3aac50fSPeter Wemm /* $FreeBSD$ */
265adb54cSMatt Jacob /*
365adb54cSMatt Jacob  * PCI specific probe and attach routines for Qlogic ISP SCSI adapters.
465adb54cSMatt Jacob  * FreeBSD Version.
565adb54cSMatt Jacob  *
65f5aafe1SMatt Jacob  * Copyright (c) 1997, 1998, 1999, 2000, 2001 by Matthew Jacob
765adb54cSMatt Jacob  *
865adb54cSMatt Jacob  * Redistribution and use in source and binary forms, with or without
965adb54cSMatt Jacob  * modification, are permitted provided that the following conditions
1065adb54cSMatt Jacob  * are met:
1165adb54cSMatt Jacob  * 1. Redistributions of source code must retain the above copyright
1265adb54cSMatt Jacob  *    notice immediately at the beginning of the file, without modification,
1365adb54cSMatt Jacob  *    this list of conditions, and the following disclaimer.
14aa57fd6fSMatt Jacob  * 2. The name of the author may not be used to endorse or promote products
15aa57fd6fSMatt Jacob  *    derived from this software without specific prior written permission.
1665adb54cSMatt Jacob  *
1765adb54cSMatt Jacob  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1865adb54cSMatt Jacob  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1965adb54cSMatt Jacob  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2065adb54cSMatt Jacob  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2165adb54cSMatt Jacob  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2265adb54cSMatt Jacob  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2365adb54cSMatt Jacob  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2465adb54cSMatt Jacob  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2565adb54cSMatt Jacob  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2665adb54cSMatt Jacob  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2765adb54cSMatt Jacob  * SUCH DAMAGE.
2865adb54cSMatt Jacob  */
29d720e6d5SJustin T. Gibbs 
30960f6939SMatt Jacob #include <sys/param.h>
31960f6939SMatt Jacob #include <sys/systm.h>
32960f6939SMatt Jacob #include <sys/kernel.h>
33960f6939SMatt Jacob #include <sys/module.h>
34960f6939SMatt Jacob #include <sys/bus.h>
3565adb54cSMatt Jacob 
3665adb54cSMatt Jacob #include <pci/pcireg.h>
3765adb54cSMatt Jacob #include <pci/pcivar.h>
3865adb54cSMatt Jacob 
39d720e6d5SJustin T. Gibbs #include <machine/bus_memio.h>
40d720e6d5SJustin T. Gibbs #include <machine/bus_pio.h>
41d720e6d5SJustin T. Gibbs #include <machine/bus.h>
42960f6939SMatt Jacob #include <machine/resource.h>
43960f6939SMatt Jacob #include <sys/rman.h>
44960f6939SMatt Jacob #include <sys/malloc.h>
45960f6939SMatt Jacob 
46960f6939SMatt Jacob #include <dev/isp/isp_freebsd.h>
47d59bd469SMatt Jacob 
4865adb54cSMatt Jacob static u_int16_t isp_pci_rd_reg __P((struct ispsoftc *, int));
4965adb54cSMatt Jacob static void isp_pci_wr_reg __P((struct ispsoftc *, int, u_int16_t));
50d59bd469SMatt Jacob static u_int16_t isp_pci_rd_reg_1080 __P((struct ispsoftc *, int));
51d59bd469SMatt Jacob static void isp_pci_wr_reg_1080 __P((struct ispsoftc *, int, u_int16_t));
5265adb54cSMatt Jacob static int isp_pci_mbxdma __P((struct ispsoftc *));
53d02373f1SMatt Jacob static int isp_pci_dmasetup __P((struct ispsoftc *, XS_T *,
549637d68cSMatt Jacob 	ispreq_t *, u_int16_t *, u_int16_t));
55d720e6d5SJustin T. Gibbs static void
56d8d5f2adSMatt Jacob isp_pci_dmateardown __P((struct ispsoftc *, XS_T *, u_int16_t));
5765adb54cSMatt Jacob 
5865adb54cSMatt Jacob static void isp_pci_reset1 __P((struct ispsoftc *));
59d02373f1SMatt Jacob static void isp_pci_dumpregs __P((struct ispsoftc *, const char *));
6065adb54cSMatt Jacob 
61fed92c47SMatt Jacob #ifndef	ISP_CODE_ORG
62fed92c47SMatt Jacob #define	ISP_CODE_ORG		0x1000
63fed92c47SMatt Jacob #endif
64fed92c47SMatt Jacob 
6565adb54cSMatt Jacob static struct ispmdvec mdvec = {
6665adb54cSMatt Jacob 	isp_pci_rd_reg,
6765adb54cSMatt Jacob 	isp_pci_wr_reg,
6865adb54cSMatt Jacob 	isp_pci_mbxdma,
6965adb54cSMatt Jacob 	isp_pci_dmasetup,
70d720e6d5SJustin T. Gibbs 	isp_pci_dmateardown,
7165adb54cSMatt Jacob 	NULL,
7265adb54cSMatt Jacob 	isp_pci_reset1,
7365adb54cSMatt Jacob 	isp_pci_dumpregs,
7456aef503SMatt Jacob 	NULL,
75d02373f1SMatt Jacob 	BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64
7665adb54cSMatt Jacob };
7765adb54cSMatt Jacob 
78d59bd469SMatt Jacob static struct ispmdvec mdvec_1080 = {
79d59bd469SMatt Jacob 	isp_pci_rd_reg_1080,
80d59bd469SMatt Jacob 	isp_pci_wr_reg_1080,
81d59bd469SMatt Jacob 	isp_pci_mbxdma,
82d59bd469SMatt Jacob 	isp_pci_dmasetup,
83d59bd469SMatt Jacob 	isp_pci_dmateardown,
84d59bd469SMatt Jacob 	NULL,
85d59bd469SMatt Jacob 	isp_pci_reset1,
86d59bd469SMatt Jacob 	isp_pci_dumpregs,
8756aef503SMatt Jacob 	NULL,
88d02373f1SMatt Jacob 	BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64
89d59bd469SMatt Jacob };
90d59bd469SMatt Jacob 
91960f6939SMatt Jacob static struct ispmdvec mdvec_12160 = {
92960f6939SMatt Jacob 	isp_pci_rd_reg_1080,
93960f6939SMatt Jacob 	isp_pci_wr_reg_1080,
94960f6939SMatt Jacob 	isp_pci_mbxdma,
95960f6939SMatt Jacob 	isp_pci_dmasetup,
96960f6939SMatt Jacob 	isp_pci_dmateardown,
97960f6939SMatt Jacob 	NULL,
98960f6939SMatt Jacob 	isp_pci_reset1,
99960f6939SMatt Jacob 	isp_pci_dumpregs,
10056aef503SMatt Jacob 	NULL,
101d02373f1SMatt Jacob 	BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64
102960f6939SMatt Jacob };
103960f6939SMatt Jacob 
10465adb54cSMatt Jacob static struct ispmdvec mdvec_2100 = {
10565adb54cSMatt Jacob 	isp_pci_rd_reg,
10665adb54cSMatt Jacob 	isp_pci_wr_reg,
10765adb54cSMatt Jacob 	isp_pci_mbxdma,
10865adb54cSMatt Jacob 	isp_pci_dmasetup,
109d720e6d5SJustin T. Gibbs 	isp_pci_dmateardown,
11065adb54cSMatt Jacob 	NULL,
11165adb54cSMatt Jacob 	isp_pci_reset1,
112d02373f1SMatt Jacob 	isp_pci_dumpregs
11365adb54cSMatt Jacob };
114222bb542SMatt Jacob 
115222bb542SMatt Jacob static struct ispmdvec mdvec_2200 = {
116222bb542SMatt Jacob 	isp_pci_rd_reg,
117222bb542SMatt Jacob 	isp_pci_wr_reg,
118222bb542SMatt Jacob 	isp_pci_mbxdma,
119222bb542SMatt Jacob 	isp_pci_dmasetup,
120222bb542SMatt Jacob 	isp_pci_dmateardown,
121222bb542SMatt Jacob 	NULL,
122222bb542SMatt Jacob 	isp_pci_reset1,
123d02373f1SMatt Jacob 	isp_pci_dumpregs
124222bb542SMatt Jacob };
125d951bbcaSMatt Jacob 
12665adb54cSMatt Jacob #ifndef	PCIM_CMD_INVEN
12765adb54cSMatt Jacob #define	PCIM_CMD_INVEN			0x10
12865adb54cSMatt Jacob #endif
12965adb54cSMatt Jacob #ifndef	PCIM_CMD_BUSMASTEREN
13065adb54cSMatt Jacob #define	PCIM_CMD_BUSMASTEREN		0x0004
13165adb54cSMatt Jacob #endif
132d951bbcaSMatt Jacob #ifndef	PCIM_CMD_PERRESPEN
133d951bbcaSMatt Jacob #define	PCIM_CMD_PERRESPEN		0x0040
134d951bbcaSMatt Jacob #endif
135d951bbcaSMatt Jacob #ifndef	PCIM_CMD_SEREN
136d951bbcaSMatt Jacob #define	PCIM_CMD_SEREN			0x0100
137d951bbcaSMatt Jacob #endif
138d951bbcaSMatt Jacob 
139d951bbcaSMatt Jacob #ifndef	PCIR_COMMAND
140d951bbcaSMatt Jacob #define	PCIR_COMMAND			0x04
141d951bbcaSMatt Jacob #endif
142d951bbcaSMatt Jacob 
143d951bbcaSMatt Jacob #ifndef	PCIR_CACHELNSZ
144d951bbcaSMatt Jacob #define	PCIR_CACHELNSZ			0x0c
145d951bbcaSMatt Jacob #endif
146d951bbcaSMatt Jacob 
147d951bbcaSMatt Jacob #ifndef	PCIR_LATTIMER
148d951bbcaSMatt Jacob #define	PCIR_LATTIMER			0x0d
149d951bbcaSMatt Jacob #endif
150d951bbcaSMatt Jacob 
151ab6d0040SMatt Jacob #ifndef	PCIR_ROMADDR
152ab6d0040SMatt Jacob #define	PCIR_ROMADDR			0x30
153ab6d0040SMatt Jacob #endif
154ab6d0040SMatt Jacob 
15565adb54cSMatt Jacob #ifndef	PCI_VENDOR_QLOGIC
15665adb54cSMatt Jacob #define	PCI_VENDOR_QLOGIC		0x1077
15765adb54cSMatt Jacob #endif
15865adb54cSMatt Jacob 
15965adb54cSMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1020
16065adb54cSMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1020	0x1020
16165adb54cSMatt Jacob #endif
16265adb54cSMatt Jacob 
163d59bd469SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1080
164d59bd469SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1080	0x1080
165d59bd469SMatt Jacob #endif
166d59bd469SMatt Jacob 
167960f6939SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP12160
168960f6939SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP12160	0x1216
169960f6939SMatt Jacob #endif
170960f6939SMatt Jacob 
171d59bd469SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1240
172d59bd469SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1240	0x1240
173d59bd469SMatt Jacob #endif
17465adb54cSMatt Jacob 
17522e1dc85SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1280
17622e1dc85SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1280	0x1280
17722e1dc85SMatt Jacob #endif
17822e1dc85SMatt Jacob 
17965adb54cSMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP2100
18065adb54cSMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2100	0x2100
18165adb54cSMatt Jacob #endif
18265adb54cSMatt Jacob 
183222bb542SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP2200
184222bb542SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2200	0x2200
185222bb542SMatt Jacob #endif
186222bb542SMatt Jacob 
18756aef503SMatt Jacob #define	PCI_QLOGIC_ISP1020	\
18856aef503SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC)
189d59bd469SMatt Jacob 
190d59bd469SMatt Jacob #define	PCI_QLOGIC_ISP1080	\
191d59bd469SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC)
192d59bd469SMatt Jacob 
193960f6939SMatt Jacob #define	PCI_QLOGIC_ISP12160	\
194960f6939SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP12160 << 16) | PCI_VENDOR_QLOGIC)
195960f6939SMatt Jacob 
196d59bd469SMatt Jacob #define	PCI_QLOGIC_ISP1240	\
197d59bd469SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC)
198d59bd469SMatt Jacob 
19922e1dc85SMatt Jacob #define	PCI_QLOGIC_ISP1280	\
20022e1dc85SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1280 << 16) | PCI_VENDOR_QLOGIC)
20122e1dc85SMatt Jacob 
20265adb54cSMatt Jacob #define	PCI_QLOGIC_ISP2100	\
20365adb54cSMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC)
20465adb54cSMatt Jacob 
205222bb542SMatt Jacob #define	PCI_QLOGIC_ISP2200	\
206222bb542SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2200 << 16) | PCI_VENDOR_QLOGIC)
207222bb542SMatt Jacob 
208e11a1ee8SMatt Jacob /*
209e11a1ee8SMatt Jacob  * Odd case for some AMI raid cards... We need to *not* attach to this.
210e11a1ee8SMatt Jacob  */
211e11a1ee8SMatt Jacob #define	AMI_RAID_SUBVENDOR_ID	0x101e
212e11a1ee8SMatt Jacob 
21365adb54cSMatt Jacob #define	IO_MAP_REG	0x10
21465adb54cSMatt Jacob #define	MEM_MAP_REG	0x14
21565adb54cSMatt Jacob 
216d951bbcaSMatt Jacob #define	PCI_DFLT_LTNCY	0x40
217d951bbcaSMatt Jacob #define	PCI_DFLT_LNSZ	0x10
21865adb54cSMatt Jacob 
219960f6939SMatt Jacob static int isp_pci_probe (device_t);
220960f6939SMatt Jacob static int isp_pci_attach (device_t);
22165adb54cSMatt Jacob 
22265adb54cSMatt Jacob struct isp_pcisoftc {
22365adb54cSMatt Jacob 	struct ispsoftc			pci_isp;
224960f6939SMatt Jacob 	device_t			pci_dev;
225960f6939SMatt Jacob 	struct resource *		pci_reg;
22665adb54cSMatt Jacob 	bus_space_tag_t			pci_st;
22765adb54cSMatt Jacob 	bus_space_handle_t		pci_sh;
228960f6939SMatt Jacob 	void *				ih;
229d59bd469SMatt Jacob 	int16_t				pci_poff[_NREG_BLKS];
230d720e6d5SJustin T. Gibbs 	bus_dma_tag_t			parent_dmat;
231d720e6d5SJustin T. Gibbs 	bus_dma_tag_t			cntrol_dmat;
232d720e6d5SJustin T. Gibbs 	bus_dmamap_t			cntrol_dmap;
233a95ae193SMatt Jacob 	bus_dmamap_t			*dmaps;
23465adb54cSMatt Jacob };
23556aef503SMatt Jacob ispfwfunc *isp_get_firmware_p = NULL;
23665adb54cSMatt Jacob 
237960f6939SMatt Jacob static device_method_t isp_pci_methods[] = {
238960f6939SMatt Jacob 	/* Device interface */
239960f6939SMatt Jacob 	DEVMETHOD(device_probe,		isp_pci_probe),
240960f6939SMatt Jacob 	DEVMETHOD(device_attach,	isp_pci_attach),
241960f6939SMatt Jacob 	{ 0, 0 }
24265adb54cSMatt Jacob };
243f09b1922SMatt Jacob static void isp_pci_intr __P((void *));
24465adb54cSMatt Jacob 
245960f6939SMatt Jacob static driver_t isp_pci_driver = {
246960f6939SMatt Jacob 	"isp", isp_pci_methods, sizeof (struct isp_pcisoftc)
247960f6939SMatt Jacob };
248960f6939SMatt Jacob static devclass_t isp_devclass;
249960f6939SMatt Jacob DRIVER_MODULE(isp, pci, isp_pci_driver, isp_devclass, 0, 0);
25056aef503SMatt Jacob MODULE_VERSION(isp, 1);
25165adb54cSMatt Jacob 
252960f6939SMatt Jacob static int
253960f6939SMatt Jacob isp_pci_probe(device_t dev)
25465adb54cSMatt Jacob {
255960f6939SMatt Jacob         switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) {
25656aef503SMatt Jacob 	case PCI_QLOGIC_ISP1020:
257960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1020/1040 PCI SCSI Adapter");
25865adb54cSMatt Jacob 		break;
259d59bd469SMatt Jacob 	case PCI_QLOGIC_ISP1080:
260960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1080 PCI SCSI Adapter");
261c6608df3SMatt Jacob 		break;
262c6608df3SMatt Jacob 	case PCI_QLOGIC_ISP1240:
263960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1240 PCI SCSI Adapter");
264d59bd469SMatt Jacob 		break;
26522e1dc85SMatt Jacob 	case PCI_QLOGIC_ISP1280:
266960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1280 PCI SCSI Adapter");
267960f6939SMatt Jacob 		break;
268960f6939SMatt Jacob 	case PCI_QLOGIC_ISP12160:
269e11a1ee8SMatt Jacob 		if (pci_get_subvendor(dev) == AMI_RAID_SUBVENDOR_ID) {
270e11a1ee8SMatt Jacob 			return (ENXIO);
271e11a1ee8SMatt Jacob 		}
272960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 12160 PCI SCSI Adapter");
27322e1dc85SMatt Jacob 		break;
27465adb54cSMatt Jacob 	case PCI_QLOGIC_ISP2100:
275960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2100 PCI FC-AL Adapter");
27665adb54cSMatt Jacob 		break;
2775542fe4bSMatt Jacob 	case PCI_QLOGIC_ISP2200:
278960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2200 PCI FC-AL Adapter");
2795542fe4bSMatt Jacob 		break;
28065adb54cSMatt Jacob 	default:
281960f6939SMatt Jacob 		return (ENXIO);
28265adb54cSMatt Jacob 	}
283d02373f1SMatt Jacob 	if (device_get_unit(dev) == 0 && bootverbose) {
284d02373f1SMatt Jacob 		printf("Qlogic ISP Driver, FreeBSD Version %d.%d, "
285a95ae193SMatt Jacob 		    "Core Version %d.%d\n",
286d720e6d5SJustin T. Gibbs 		    ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR,
287d720e6d5SJustin T. Gibbs 		    ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR);
28865adb54cSMatt Jacob 	}
28956aef503SMatt Jacob 	/*
29056aef503SMatt Jacob 	 * XXXX: Here is where we might load the f/w module
29156aef503SMatt Jacob 	 * XXXX: (or increase a reference count to it).
29256aef503SMatt Jacob 	 */
293960f6939SMatt Jacob 	return (0);
29465adb54cSMatt Jacob }
29565adb54cSMatt Jacob 
296960f6939SMatt Jacob static int
297960f6939SMatt Jacob isp_pci_attach(device_t dev)
29865adb54cSMatt Jacob {
299960f6939SMatt Jacob 	struct resource *regs, *irq;
3006e5c5328SMatt Jacob 	int tval, rtp, rgd, iqd, m1, m2, isp_debug, role;
301960f6939SMatt Jacob 	u_int32_t data, cmd, linesz, psize, basetype;
30265adb54cSMatt Jacob 	struct isp_pcisoftc *pcs;
3033395b056SMatt Jacob 	struct ispsoftc *isp = NULL;
304c6608df3SMatt Jacob 	struct ispmdvec *mdvp;
305222bb542SMatt Jacob 	bus_size_t lim;
3066e5c5328SMatt Jacob 	char *sptr;
3073395b056SMatt Jacob #ifdef	ISP_SMPLOCK
3083395b056SMatt Jacob 	int locksetup = 0;
3093395b056SMatt Jacob #endif
31065adb54cSMatt Jacob 
311222bb542SMatt Jacob 	/*
3129ba86737SMatt Jacob 	 * Figure out if we're supposed to skip this one.
313b9b599feSMatt Jacob 	 * If we are, we actually go to ISP_ROLE_NONE.
3149ba86737SMatt Jacob 	 */
3156e5c5328SMatt Jacob 
3166e5c5328SMatt Jacob 	tval = 0;
3176e5c5328SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
3186e5c5328SMatt Jacob 	    "disable", &tval) == 0 && tval) {
319b9b599feSMatt Jacob 		device_printf(dev, "device is disabled\n");
320b9b599feSMatt Jacob 		/* but return 0 so the !$)$)*!$*) unit isn't reused */
321b9b599feSMatt Jacob 		return (0);
322b9b599feSMatt Jacob 	}
3236e5c5328SMatt Jacob 
3246e5c5328SMatt Jacob 	role = 0;
3256e5c5328SMatt Jacob 	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
3266e5c5328SMatt Jacob 	    "role", &role) == 0 &&
3276e5c5328SMatt Jacob 	    ((role & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) == 0)) {
3286e5c5328SMatt Jacob 		device_printf(dev, "setting role to 0x%x\n", role);
3296e5c5328SMatt Jacob 	} else {
330b9b599feSMatt Jacob #ifdef	ISP_TARGET_MODE
331b9b599feSMatt Jacob 		role = ISP_ROLE_INITIATOR|ISP_ROLE_TARGET;
332b9b599feSMatt Jacob #else
333b9b599feSMatt Jacob 		role = ISP_DEFAULT_ROLES;
334b9b599feSMatt Jacob #endif
3359ba86737SMatt Jacob 	}
3369ba86737SMatt Jacob 
3377cc0979fSDavid Malone 	pcs = malloc(sizeof (struct isp_pcisoftc), M_DEVBUF, M_NOWAIT | M_ZERO);
338960f6939SMatt Jacob 	if (pcs == NULL) {
339960f6939SMatt Jacob 		device_printf(dev, "cannot allocate softc\n");
340960f6939SMatt Jacob 		return (ENOMEM);
341960f6939SMatt Jacob 	}
342960f6939SMatt Jacob 
3439ba86737SMatt Jacob 	/*
344222bb542SMatt Jacob 	 * Figure out which we should try first - memory mapping or i/o mapping?
345222bb542SMatt Jacob 	 */
34656aef503SMatt Jacob #ifdef	__alpha__
347960f6939SMatt Jacob 	m1 = PCIM_CMD_MEMEN;
348960f6939SMatt Jacob 	m2 = PCIM_CMD_PORTEN;
349222bb542SMatt Jacob #else
350960f6939SMatt Jacob 	m1 = PCIM_CMD_PORTEN;
351960f6939SMatt Jacob 	m2 = PCIM_CMD_MEMEN;
352222bb542SMatt Jacob #endif
3536e5c5328SMatt Jacob 
3546e5c5328SMatt Jacob 	tval = 0;
3556e5c5328SMatt Jacob         if (resource_int_value(device_get_name(dev), device_get_unit(dev),
3566e5c5328SMatt Jacob             "prefer_iomap", &tval) == 0 && tval != 0) {
357960f6939SMatt Jacob 		m1 = PCIM_CMD_PORTEN;
358960f6939SMatt Jacob 		m2 = PCIM_CMD_MEMEN;
359960f6939SMatt Jacob 	}
3606e5c5328SMatt Jacob 	tval = 0;
3616e5c5328SMatt Jacob         if (resource_int_value(device_get_name(dev), device_get_unit(dev),
3626e5c5328SMatt Jacob             "prefer_memmap", &tval) == 0 && tval != 0) {
3636e5c5328SMatt Jacob 		m1 = PCIM_CMD_MEMEN;
3646e5c5328SMatt Jacob 		m2 = PCIM_CMD_PORTEN;
365222bb542SMatt Jacob 	}
366222bb542SMatt Jacob 
367ab6d0040SMatt Jacob 	linesz = PCI_DFLT_LNSZ;
368960f6939SMatt Jacob 	irq = regs = NULL;
369960f6939SMatt Jacob 	rgd = rtp = iqd = 0;
370960f6939SMatt Jacob 
371960f6939SMatt Jacob 	cmd = pci_read_config(dev, PCIR_COMMAND, 1);
372960f6939SMatt Jacob 	if (cmd & m1) {
373960f6939SMatt Jacob 		rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT;
374960f6939SMatt Jacob 		rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG;
375960f6939SMatt Jacob 		regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE);
37665adb54cSMatt Jacob 	}
377960f6939SMatt Jacob 	if (regs == NULL && (cmd & m2)) {
378960f6939SMatt Jacob 		rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT;
379960f6939SMatt Jacob 		rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG;
380960f6939SMatt Jacob 		regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE);
38165adb54cSMatt Jacob 	}
382960f6939SMatt Jacob 	if (regs == NULL) {
383960f6939SMatt Jacob 		device_printf(dev, "unable to map any ports\n");
384960f6939SMatt Jacob 		goto bad;
38565adb54cSMatt Jacob 	}
386222bb542SMatt Jacob 	if (bootverbose)
387f7dddf8aSMatt Jacob 		device_printf(dev, "using %s space register mapping\n",
388960f6939SMatt Jacob 		    (rgd == IO_MAP_REG)? "I/O" : "Memory");
389960f6939SMatt Jacob 	pcs->pci_dev = dev;
390960f6939SMatt Jacob 	pcs->pci_reg = regs;
391960f6939SMatt Jacob 	pcs->pci_st = rman_get_bustag(regs);
392960f6939SMatt Jacob 	pcs->pci_sh = rman_get_bushandle(regs);
39365adb54cSMatt Jacob 
394d59bd469SMatt Jacob 	pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF;
395d59bd469SMatt Jacob 	pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF;
396d59bd469SMatt Jacob 	pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF;
397d59bd469SMatt Jacob 	pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF;
398d59bd469SMatt Jacob 	pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF;
399c6608df3SMatt Jacob 	mdvp = &mdvec;
400c6608df3SMatt Jacob 	basetype = ISP_HA_SCSI_UNKNOWN;
401c6608df3SMatt Jacob 	psize = sizeof (sdparam);
402222bb542SMatt Jacob 	lim = BUS_SPACE_MAXSIZE_32BIT;
40356aef503SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP1020) {
404c6608df3SMatt Jacob 		mdvp = &mdvec;
405c6608df3SMatt Jacob 		basetype = ISP_HA_SCSI_UNKNOWN;
406c6608df3SMatt Jacob 		psize = sizeof (sdparam);
407222bb542SMatt Jacob 		lim = BUS_SPACE_MAXSIZE_24BIT;
408d59bd469SMatt Jacob 	}
409960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP1080) {
410c6608df3SMatt Jacob 		mdvp = &mdvec_1080;
411c6608df3SMatt Jacob 		basetype = ISP_HA_SCSI_1080;
412c6608df3SMatt Jacob 		psize = sizeof (sdparam);
413c6608df3SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
414c6608df3SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
415c6608df3SMatt Jacob 	}
416960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP1240) {
417c6608df3SMatt Jacob 		mdvp = &mdvec_1080;
41822e1dc85SMatt Jacob 		basetype = ISP_HA_SCSI_1240;
41922e1dc85SMatt Jacob 		psize = 2 * sizeof (sdparam);
42022e1dc85SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
42122e1dc85SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
42222e1dc85SMatt Jacob 	}
423960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP1280) {
42422e1dc85SMatt Jacob 		mdvp = &mdvec_1080;
42522e1dc85SMatt Jacob 		basetype = ISP_HA_SCSI_1280;
426c6608df3SMatt Jacob 		psize = 2 * sizeof (sdparam);
427d59bd469SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
428d59bd469SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
429d59bd469SMatt Jacob 	}
430960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP12160) {
431960f6939SMatt Jacob 		mdvp = &mdvec_12160;
432960f6939SMatt Jacob 		basetype = ISP_HA_SCSI_12160;
433960f6939SMatt Jacob 		psize = 2 * sizeof (sdparam);
434960f6939SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
435960f6939SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
436960f6939SMatt Jacob 	}
437960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP2100) {
438c6608df3SMatt Jacob 		mdvp = &mdvec_2100;
439c6608df3SMatt Jacob 		basetype = ISP_HA_FC_2100;
440c6608df3SMatt Jacob 		psize = sizeof (fcparam);
441d59bd469SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
442d59bd469SMatt Jacob 		    PCI_MBOX_REGS2100_OFF;
443960f6939SMatt Jacob 		if (pci_get_revid(dev) < 3) {
444ab6d0040SMatt Jacob 			/*
445ab6d0040SMatt Jacob 			 * XXX: Need to get the actual revision
446ab6d0040SMatt Jacob 			 * XXX: number of the 2100 FB. At any rate,
447ab6d0040SMatt Jacob 			 * XXX: lower cache line size for early revision
448ab6d0040SMatt Jacob 			 * XXX; boards.
449ab6d0040SMatt Jacob 			 */
450ab6d0040SMatt Jacob 			linesz = 1;
451ab6d0040SMatt Jacob 		}
45265adb54cSMatt Jacob 	}
453960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP2200) {
454222bb542SMatt Jacob 		mdvp = &mdvec_2200;
455222bb542SMatt Jacob 		basetype = ISP_HA_FC_2200;
456222bb542SMatt Jacob 		psize = sizeof (fcparam);
457222bb542SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
458222bb542SMatt Jacob 		    PCI_MBOX_REGS2100_OFF;
459222bb542SMatt Jacob 	}
460c6608df3SMatt Jacob 	isp = &pcs->pci_isp;
4617cc0979fSDavid Malone 	isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT | M_ZERO);
462c6608df3SMatt Jacob 	if (isp->isp_param == NULL) {
463960f6939SMatt Jacob 		device_printf(dev, "cannot allocate parameter data\n");
464960f6939SMatt Jacob 		goto bad;
465c6608df3SMatt Jacob 	}
466c6608df3SMatt Jacob 	isp->isp_mdvec = mdvp;
467c6608df3SMatt Jacob 	isp->isp_type = basetype;
468960f6939SMatt Jacob 	isp->isp_revision = pci_get_revid(dev);
469b9b599feSMatt Jacob 	isp->isp_role = role;
4706e5c5328SMatt Jacob 	isp->isp_dev = dev;
47165adb54cSMatt Jacob 
47256aef503SMatt Jacob 	/*
47356aef503SMatt Jacob 	 * Try and find firmware for this device.
47456aef503SMatt Jacob 	 */
47556aef503SMatt Jacob 
47656aef503SMatt Jacob 	if (isp_get_firmware_p) {
47756aef503SMatt Jacob 		int device = (int) pci_get_device(dev);
47856aef503SMatt Jacob #ifdef	ISP_TARGET_MODE
47956aef503SMatt Jacob 		(*isp_get_firmware_p)(0, 1, device, &mdvp->dv_ispfw);
48056aef503SMatt Jacob #else
48156aef503SMatt Jacob 		(*isp_get_firmware_p)(0, 0, device, &mdvp->dv_ispfw);
48256aef503SMatt Jacob #endif
48356aef503SMatt Jacob 	}
48456aef503SMatt Jacob 
48556aef503SMatt Jacob 	/*
486d951bbcaSMatt Jacob 	 * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER
487d951bbcaSMatt Jacob 	 * are set.
488d951bbcaSMatt Jacob 	 */
489960f6939SMatt Jacob 	cmd |= PCIM_CMD_SEREN | PCIM_CMD_PERRESPEN |
490960f6939SMatt Jacob 		PCIM_CMD_BUSMASTEREN | PCIM_CMD_INVEN;
491960f6939SMatt Jacob 	pci_write_config(dev, PCIR_COMMAND, cmd, 1);
492ab6d0040SMatt Jacob 
493d951bbcaSMatt Jacob 	/*
494222bb542SMatt Jacob 	 * Make sure the Cache Line Size register is set sensibly.
495d951bbcaSMatt Jacob 	 */
496960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_CACHELNSZ, 1);
497ab6d0040SMatt Jacob 	if (data != linesz) {
498d951bbcaSMatt Jacob 		data = PCI_DFLT_LNSZ;
499d02373f1SMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, "set PCI line size to %d", data);
500960f6939SMatt Jacob 		pci_write_config(dev, PCIR_CACHELNSZ, data, 1);
501d951bbcaSMatt Jacob 	}
502ab6d0040SMatt Jacob 
503d951bbcaSMatt Jacob 	/*
504d951bbcaSMatt Jacob 	 * Make sure the Latency Timer is sane.
505d951bbcaSMatt Jacob 	 */
506960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_LATTIMER, 1);
507d951bbcaSMatt Jacob 	if (data < PCI_DFLT_LTNCY) {
508d951bbcaSMatt Jacob 		data = PCI_DFLT_LTNCY;
509d02373f1SMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, "set PCI latency to %d", data);
510960f6939SMatt Jacob 		pci_write_config(dev, PCIR_LATTIMER, data, 1);
511d951bbcaSMatt Jacob 	}
512ab6d0040SMatt Jacob 
513ab6d0040SMatt Jacob 	/*
514ab6d0040SMatt Jacob 	 * Make sure we've disabled the ROM.
515ab6d0040SMatt Jacob 	 */
516960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_ROMADDR, 4);
517ab6d0040SMatt Jacob 	data &= ~1;
518960f6939SMatt Jacob 	pci_write_config(dev, PCIR_ROMADDR, data, 4);
51905fbcbb0SMatt Jacob 
520d951bbcaSMatt Jacob 
521086646f7SJustin T. Gibbs 	if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
522222bb542SMatt Jacob 	    BUS_SPACE_MAXADDR, NULL, NULL, lim + 1,
523222bb542SMatt Jacob 	    255, lim, 0, &pcs->parent_dmat) != 0) {
524f7dddf8aSMatt Jacob 		device_printf(dev, "could not create master dma tag\n");
525960f6939SMatt Jacob 		free(isp->isp_param, M_DEVBUF);
526d720e6d5SJustin T. Gibbs 		free(pcs, M_DEVBUF);
527960f6939SMatt Jacob 		return (ENXIO);
52865adb54cSMatt Jacob 	}
52965adb54cSMatt Jacob 
530960f6939SMatt Jacob 	iqd = 0;
531960f6939SMatt Jacob 	irq = bus_alloc_resource(dev, SYS_RES_IRQ, &iqd, 0, ~0,
532960f6939SMatt Jacob 	    1, RF_ACTIVE | RF_SHAREABLE);
533960f6939SMatt Jacob 	if (irq == NULL) {
534960f6939SMatt Jacob 		device_printf(dev, "could not allocate interrupt\n");
535960f6939SMatt Jacob 		goto bad;
536960f6939SMatt Jacob 	}
537960f6939SMatt Jacob 
5386e5c5328SMatt Jacob 	tval = 0;
5396e5c5328SMatt Jacob         if (resource_int_value(device_get_name(dev), device_get_unit(dev),
5406e5c5328SMatt Jacob             "fwload_disable", &tval) == 0 && tval != 0) {
541222bb542SMatt Jacob 		isp->isp_confopts |= ISP_CFG_NORELOAD;
542222bb542SMatt Jacob 	}
5436e5c5328SMatt Jacob 	tval = 0;
5446e5c5328SMatt Jacob         if (resource_int_value(device_get_name(dev), device_get_unit(dev),
5456e5c5328SMatt Jacob             "ignore_nvram", &tval) == 0 && tval != 0) {
546222bb542SMatt Jacob 		isp->isp_confopts |= ISP_CFG_NONVRAM;
547222bb542SMatt Jacob 	}
5486e5c5328SMatt Jacob 	tval = 0;
5496e5c5328SMatt Jacob         if (resource_int_value(device_get_name(dev), device_get_unit(dev),
5506e5c5328SMatt Jacob             "fullduplex", &tval) == 0 && tval != 0) {
551222bb542SMatt Jacob 		isp->isp_confopts |= ISP_CFG_FULL_DUPLEX;
552222bb542SMatt Jacob 	}
553222bb542SMatt Jacob 
5546e5c5328SMatt Jacob 	sptr = 0;
5556e5c5328SMatt Jacob         if (resource_string_value(device_get_name(dev), device_get_unit(dev),
5566e5c5328SMatt Jacob             "topology", &sptr) == 0 && sptr != 0) {
5576e5c5328SMatt Jacob 		if (strcmp(sptr, "lport") == 0) {
5586e5c5328SMatt Jacob 			isp->isp_confopts |= ISP_CFG_LPORT;
5596e5c5328SMatt Jacob 		} else if (strcmp(sptr, "nport") == 0) {
5606e5c5328SMatt Jacob 			isp->isp_confopts |= ISP_CFG_NPORT;
5616e5c5328SMatt Jacob 		} else if (strcmp(sptr, "lport-only") == 0) {
5626e5c5328SMatt Jacob 			isp->isp_confopts |= ISP_CFG_LPORT_ONLY;
5636e5c5328SMatt Jacob 		} else if (strcmp(sptr, "nport-only") == 0) {
5646e5c5328SMatt Jacob 			isp->isp_confopts |= ISP_CFG_NPORT_ONLY;
5659637d68cSMatt Jacob 		}
5666e5c5328SMatt Jacob 	}
5676e5c5328SMatt Jacob 
5689637d68cSMatt Jacob 	/*
5696e5c5328SMatt Jacob 	 * Because the resource_*_value functions can neither return
5706e5c5328SMatt Jacob 	 * 64 bit integer values, nor can they be directly coerced
5716e5c5328SMatt Jacob 	 * to interpret the right hand side of the assignment as
5726e5c5328SMatt Jacob 	 * you want them to interpret it, we have to force WWN
5736e5c5328SMatt Jacob 	 * hint replacement to specify WWN strings with a leading
5746e5c5328SMatt Jacob 	 * 'w' (e..g w50000000aaaa0001). Sigh.
5759637d68cSMatt Jacob 	 */
5766e5c5328SMatt Jacob 	sptr = 0;
5776e5c5328SMatt Jacob 	tval = resource_string_value(device_get_name(dev), device_get_unit(dev),
5786e5c5328SMatt Jacob             "portwwn", &sptr);
5796e5c5328SMatt Jacob 	if (tval == 0 && sptr != 0 && *sptr++ == 'w') {
5806e5c5328SMatt Jacob 		char *eptr = 0;
5816e5c5328SMatt Jacob 		isp->isp_osinfo.default_port_wwn = strtouq(sptr, &eptr, 16);
5826e5c5328SMatt Jacob 		if (eptr < sptr + 16 || isp->isp_osinfo.default_port_wwn == 0) {
5836e5c5328SMatt Jacob 			device_printf(dev, "mangled portwwn hint '%s'\n", sptr);
5846e5c5328SMatt Jacob 			isp->isp_osinfo.default_port_wwn = 0;
5859637d68cSMatt Jacob 		} else {
5869637d68cSMatt Jacob 			isp->isp_confopts |= ISP_CFG_OWNWWN;
587222bb542SMatt Jacob 		}
5886e5c5328SMatt Jacob 	}
5896e5c5328SMatt Jacob 	if (isp->isp_osinfo.default_port_wwn == 0) {
5906e5c5328SMatt Jacob 		isp->isp_osinfo.default_port_wwn = 0x400000007F000009ull;
5916e5c5328SMatt Jacob 	}
5926e5c5328SMatt Jacob 
5936e5c5328SMatt Jacob 	sptr = 0;
5946e5c5328SMatt Jacob 	tval = resource_string_value(device_get_name(dev), device_get_unit(dev),
5956e5c5328SMatt Jacob             "nodewwn", &sptr);
5966e5c5328SMatt Jacob 	if (tval == 0 && sptr != 0 && *sptr++ == 'w') {
5976e5c5328SMatt Jacob 		char *eptr = 0;
5986e5c5328SMatt Jacob 		isp->isp_osinfo.default_node_wwn = strtouq(sptr, &eptr, 16);
5996e5c5328SMatt Jacob 		if (eptr < sptr + 16 || isp->isp_osinfo.default_node_wwn == 0) {
6006e5c5328SMatt Jacob 			device_printf(dev, "mangled nodewwn hint '%s'\n", sptr);
6016e5c5328SMatt Jacob 			isp->isp_osinfo.default_node_wwn = 0;
6026e5c5328SMatt Jacob 		} else {
6036e5c5328SMatt Jacob 			isp->isp_confopts |= ISP_CFG_OWNWWN;
6046e5c5328SMatt Jacob 		}
6056e5c5328SMatt Jacob 	}
6066e5c5328SMatt Jacob 	if (isp->isp_osinfo.default_node_wwn == 0) {
6076e5c5328SMatt Jacob 		isp->isp_osinfo.default_node_wwn = 0x400000007F000009ull;
6086e5c5328SMatt Jacob 	}
6096e5c5328SMatt Jacob 
610d02373f1SMatt Jacob 	isp_debug = 0;
6116e5c5328SMatt Jacob         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
6126e5c5328SMatt Jacob             "debug", &isp_debug);
613f09b1922SMatt Jacob 
614f09b1922SMatt Jacob #ifdef	ISP_SMPLOCK
615f09b1922SMatt Jacob 	/* Make sure the lock is set up. */
616f09b1922SMatt Jacob 	mtx_init(&isp->isp_osinfo.lock, "isp", MTX_DEF);
617f09b1922SMatt Jacob 	locksetup++;
618f09b1922SMatt Jacob 
619ed34d0adSMark Murray 	if (bus_setup_intr(dev, irq, INTR_TYPE_CAM | INTR_MPSAFE | INTR_ENTROPY,
620f09b1922SMatt Jacob 	    isp_pci_intr, isp, &pcs->ih)) {
621960f6939SMatt Jacob 		device_printf(dev, "could not setup interrupt\n");
622960f6939SMatt Jacob 		goto bad;
623960f6939SMatt Jacob 	}
624f09b1922SMatt Jacob #else
625ed34d0adSMark Murray 	if (bus_setup_intr(dev, irq, INTR_TYPE_CAM | INTR_ENTROPY,
626f09b1922SMatt Jacob 	    isp_pci_intr, isp, &pcs->ih)) {
627f09b1922SMatt Jacob 		device_printf(dev, "could not setup interrupt\n");
628f09b1922SMatt Jacob 		goto bad;
629f09b1922SMatt Jacob 	}
630f09b1922SMatt Jacob #endif
631960f6939SMatt Jacob 
63205fbcbb0SMatt Jacob 	/*
633d02373f1SMatt Jacob 	 * Set up logging levels.
634d02373f1SMatt Jacob 	 */
635d02373f1SMatt Jacob 	if (isp_debug) {
636d02373f1SMatt Jacob 		isp->isp_dblev = isp_debug;
637d02373f1SMatt Jacob 	} else {
638d02373f1SMatt Jacob 		isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR;
639d02373f1SMatt Jacob 	}
640d02373f1SMatt Jacob 	if (bootverbose)
641f7dddf8aSMatt Jacob 		isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO;
642d02373f1SMatt Jacob 
643d02373f1SMatt Jacob 	/*
64405fbcbb0SMatt Jacob 	 * Make sure we're in reset state.
64505fbcbb0SMatt Jacob 	 */
6463395b056SMatt Jacob 	ISP_LOCK(isp);
64765adb54cSMatt Jacob 	isp_reset(isp);
64865adb54cSMatt Jacob 	if (isp->isp_state != ISP_RESETSTATE) {
6493395b056SMatt Jacob 		ISP_UNLOCK(isp);
650960f6939SMatt Jacob 		goto bad;
65165adb54cSMatt Jacob 	}
65265adb54cSMatt Jacob 	isp_init(isp);
653b9b599feSMatt Jacob 	if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_INITSTATE) {
65465adb54cSMatt Jacob 		isp_uninit(isp);
6553395b056SMatt Jacob 		ISP_UNLOCK(isp);
656960f6939SMatt Jacob 		goto bad;
657d59bd469SMatt Jacob 	}
65865adb54cSMatt Jacob 	isp_attach(isp);
659b9b599feSMatt Jacob 	if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_RUNSTATE) {
66065adb54cSMatt Jacob 		isp_uninit(isp);
6613395b056SMatt Jacob 		ISP_UNLOCK(isp);
662960f6939SMatt Jacob 		goto bad;
663960f6939SMatt Jacob 	}
66456aef503SMatt Jacob 	/*
66556aef503SMatt Jacob 	 * XXXX: Here is where we might unload the f/w module
66656aef503SMatt Jacob 	 * XXXX: (or decrease the reference count to it).
66756aef503SMatt Jacob 	 */
6683395b056SMatt Jacob 	ISP_UNLOCK(isp);
669960f6939SMatt Jacob 	return (0);
670960f6939SMatt Jacob 
671960f6939SMatt Jacob bad:
672960f6939SMatt Jacob 
673960f6939SMatt Jacob 	if (pcs && pcs->ih) {
674960f6939SMatt Jacob 		(void) bus_teardown_intr(dev, irq, pcs->ih);
675960f6939SMatt Jacob 	}
676960f6939SMatt Jacob 
6773395b056SMatt Jacob #ifdef	ISP_SMPLOCK
6783395b056SMatt Jacob 	if (locksetup && isp) {
6793395b056SMatt Jacob 		mtx_destroy(&isp->isp_osinfo.lock);
6803395b056SMatt Jacob 	}
6813395b056SMatt Jacob #endif
6823395b056SMatt Jacob 
683960f6939SMatt Jacob 	if (irq) {
684960f6939SMatt Jacob 		(void) bus_release_resource(dev, SYS_RES_IRQ, iqd, irq);
685960f6939SMatt Jacob 	}
6863395b056SMatt Jacob 
6873395b056SMatt Jacob 
688960f6939SMatt Jacob 	if (regs) {
689960f6939SMatt Jacob 		(void) bus_release_resource(dev, rtp, rgd, regs);
690960f6939SMatt Jacob 	}
6913395b056SMatt Jacob 
692960f6939SMatt Jacob 	if (pcs) {
693960f6939SMatt Jacob 		if (pcs->pci_isp.isp_param)
694960f6939SMatt Jacob 			free(pcs->pci_isp.isp_param, M_DEVBUF);
69565adb54cSMatt Jacob 		free(pcs, M_DEVBUF);
69665adb54cSMatt Jacob 	}
6973395b056SMatt Jacob 
69856aef503SMatt Jacob 	/*
69956aef503SMatt Jacob 	 * XXXX: Here is where we might unload the f/w module
70056aef503SMatt Jacob 	 * XXXX: (or decrease the reference count to it).
70156aef503SMatt Jacob 	 */
702960f6939SMatt Jacob 	return (ENXIO);
70365adb54cSMatt Jacob }
70465adb54cSMatt Jacob 
705f09b1922SMatt Jacob static void
706f09b1922SMatt Jacob isp_pci_intr(void *arg)
707f09b1922SMatt Jacob {
708f09b1922SMatt Jacob 	struct ispsoftc *isp = arg;
709f09b1922SMatt Jacob 	ISP_LOCK(isp);
710f09b1922SMatt Jacob 	(void) isp_intr(isp);
711f09b1922SMatt Jacob 	ISP_UNLOCK(isp);
712f09b1922SMatt Jacob }
713f09b1922SMatt Jacob 
71465adb54cSMatt Jacob static u_int16_t
715d59bd469SMatt Jacob isp_pci_rd_reg(isp, regoff)
716d59bd469SMatt Jacob 	struct ispsoftc *isp;
717d59bd469SMatt Jacob 	int regoff;
71865adb54cSMatt Jacob {
71965adb54cSMatt Jacob 	u_int16_t rv;
72065adb54cSMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
721d59bd469SMatt Jacob 	int offset, oldconf = 0;
72265adb54cSMatt Jacob 
723d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
72465adb54cSMatt Jacob 		/*
72565adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
72665adb54cSMatt Jacob 		 */
727d59bd469SMatt Jacob 		oldconf = isp_pci_rd_reg(isp, BIU_CONF1);
728d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP);
72965adb54cSMatt Jacob 	}
730d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
731d59bd469SMatt Jacob 	offset += (regoff & 0xff);
73265adb54cSMatt Jacob 	rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset);
733d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
734d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf);
73565adb54cSMatt Jacob 	}
73665adb54cSMatt Jacob 	return (rv);
73765adb54cSMatt Jacob }
73865adb54cSMatt Jacob 
73965adb54cSMatt Jacob static void
740d59bd469SMatt Jacob isp_pci_wr_reg(isp, regoff, val)
741d59bd469SMatt Jacob 	struct ispsoftc *isp;
742d59bd469SMatt Jacob 	int regoff;
743d59bd469SMatt Jacob 	u_int16_t val;
74465adb54cSMatt Jacob {
74565adb54cSMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
746d59bd469SMatt Jacob 	int offset, oldconf = 0;
747d59bd469SMatt Jacob 
748d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
74965adb54cSMatt Jacob 		/*
75065adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
75165adb54cSMatt Jacob 		 */
752d59bd469SMatt Jacob 		oldconf = isp_pci_rd_reg(isp, BIU_CONF1);
753d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP);
75465adb54cSMatt Jacob 	}
755d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
756d59bd469SMatt Jacob 	offset += (regoff & 0xff);
75765adb54cSMatt Jacob 	bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val);
758d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
759d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf);
76065adb54cSMatt Jacob 	}
76165adb54cSMatt Jacob }
76265adb54cSMatt Jacob 
763d59bd469SMatt Jacob static u_int16_t
764d59bd469SMatt Jacob isp_pci_rd_reg_1080(isp, regoff)
765d59bd469SMatt Jacob 	struct ispsoftc *isp;
766d59bd469SMatt Jacob 	int regoff;
767d59bd469SMatt Jacob {
76822e1dc85SMatt Jacob 	u_int16_t rv, oc = 0;
769d59bd469SMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
77022e1dc85SMatt Jacob 	int offset;
771d59bd469SMatt Jacob 
77222e1dc85SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
77322e1dc85SMatt Jacob 	    (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
77422e1dc85SMatt Jacob 		u_int16_t tc;
775d59bd469SMatt Jacob 		/*
776d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
777d59bd469SMatt Jacob 		 */
778d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
77922e1dc85SMatt Jacob 		tc = oc & ~BIU_PCI1080_CONF1_DMA;
78022e1dc85SMatt Jacob 		if (regoff & SXP_BANK1_SELECT)
78122e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP1;
78222e1dc85SMatt Jacob 		else
78322e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP0;
78422e1dc85SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, tc);
785d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
786d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
787d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA);
788d59bd469SMatt Jacob 	}
789d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
790d59bd469SMatt Jacob 	offset += (regoff & 0xff);
791d59bd469SMatt Jacob 	rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset);
79222e1dc85SMatt Jacob 	if (oc) {
793d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc);
794d59bd469SMatt Jacob 	}
795d59bd469SMatt Jacob 	return (rv);
796d59bd469SMatt Jacob }
797d59bd469SMatt Jacob 
798d59bd469SMatt Jacob static void
799d59bd469SMatt Jacob isp_pci_wr_reg_1080(isp, regoff, val)
800d59bd469SMatt Jacob 	struct ispsoftc *isp;
801d59bd469SMatt Jacob 	int regoff;
802d59bd469SMatt Jacob 	u_int16_t val;
803d59bd469SMatt Jacob {
804d59bd469SMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
805d59bd469SMatt Jacob 	int offset, oc = 0;
806d59bd469SMatt Jacob 
80722e1dc85SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
80822e1dc85SMatt Jacob 	    (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
80922e1dc85SMatt Jacob 		u_int16_t tc;
810d59bd469SMatt Jacob 		/*
811d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
812d59bd469SMatt Jacob 		 */
813d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
81422e1dc85SMatt Jacob 		tc = oc & ~BIU_PCI1080_CONF1_DMA;
81522e1dc85SMatt Jacob 		if (regoff & SXP_BANK1_SELECT)
81622e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP1;
81722e1dc85SMatt Jacob 		else
81822e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP0;
81922e1dc85SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, tc);
820d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
821d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
822d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA);
823d59bd469SMatt Jacob 	}
824d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
825d59bd469SMatt Jacob 	offset += (regoff & 0xff);
826d59bd469SMatt Jacob 	bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val);
82722e1dc85SMatt Jacob 	if (oc) {
828d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc);
829d59bd469SMatt Jacob 	}
830d59bd469SMatt Jacob }
831d59bd469SMatt Jacob 
832d720e6d5SJustin T. Gibbs static void isp_map_rquest __P((void *, bus_dma_segment_t *, int, int));
833d720e6d5SJustin T. Gibbs static void isp_map_result __P((void *, bus_dma_segment_t *, int, int));
834d720e6d5SJustin T. Gibbs static void isp_map_fcscrt __P((void *, bus_dma_segment_t *, int, int));
835d720e6d5SJustin T. Gibbs 
836222bb542SMatt Jacob struct imush {
837222bb542SMatt Jacob 	struct ispsoftc *isp;
838222bb542SMatt Jacob 	int error;
839222bb542SMatt Jacob };
840222bb542SMatt Jacob 
841d720e6d5SJustin T. Gibbs static void
84217e318c6SMatt Jacob isp_map_rquest(void *arg, bus_dma_segment_t *segs, int nseg, int error)
843d720e6d5SJustin T. Gibbs {
844222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
845222bb542SMatt Jacob 	if (error) {
846222bb542SMatt Jacob 		imushp->error = error;
847222bb542SMatt Jacob 	} else {
848222bb542SMatt Jacob 		imushp->isp->isp_rquest_dma = segs->ds_addr;
849222bb542SMatt Jacob 	}
850d720e6d5SJustin T. Gibbs }
851d720e6d5SJustin T. Gibbs 
852d720e6d5SJustin T. Gibbs static void
85317e318c6SMatt Jacob isp_map_result(void *arg, bus_dma_segment_t *segs, int nseg, int error)
854d720e6d5SJustin T. Gibbs {
855222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
856222bb542SMatt Jacob 	if (error) {
857222bb542SMatt Jacob 		imushp->error = error;
858222bb542SMatt Jacob 	} else {
859222bb542SMatt Jacob 		imushp->isp->isp_result_dma = segs->ds_addr;
860222bb542SMatt Jacob 	}
861d720e6d5SJustin T. Gibbs }
862d720e6d5SJustin T. Gibbs 
863d720e6d5SJustin T. Gibbs static void
86417e318c6SMatt Jacob isp_map_fcscrt(void *arg, bus_dma_segment_t *segs, int nseg, int error)
865d720e6d5SJustin T. Gibbs {
866222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
867222bb542SMatt Jacob 	if (error) {
868222bb542SMatt Jacob 		imushp->error = error;
869222bb542SMatt Jacob 	} else {
870222bb542SMatt Jacob 		fcparam *fcp = imushp->isp->isp_param;
871d720e6d5SJustin T. Gibbs 		fcp->isp_scdma = segs->ds_addr;
872d720e6d5SJustin T. Gibbs 	}
873222bb542SMatt Jacob }
874d720e6d5SJustin T. Gibbs 
875d720e6d5SJustin T. Gibbs static int
87617e318c6SMatt Jacob isp_pci_mbxdma(struct ispsoftc *isp)
877d720e6d5SJustin T. Gibbs {
878d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
879d720e6d5SJustin T. Gibbs 	caddr_t base;
880d720e6d5SJustin T. Gibbs 	u_int32_t len;
881d720e6d5SJustin T. Gibbs 	int i, error;
882222bb542SMatt Jacob 	bus_size_t lim;
883222bb542SMatt Jacob 	struct imush im;
884222bb542SMatt Jacob 
885222bb542SMatt Jacob 
886a95ae193SMatt Jacob 	/*
887a95ae193SMatt Jacob 	 * Already been here? If so, leave...
888a95ae193SMatt Jacob 	 */
889a95ae193SMatt Jacob 	if (isp->isp_rquest) {
890a95ae193SMatt Jacob 		return (0);
891a95ae193SMatt Jacob 	}
892a95ae193SMatt Jacob 
893d02373f1SMatt Jacob 	len = sizeof (XS_T **) * isp->isp_maxcmds;
8947cc0979fSDavid Malone 	isp->isp_xflist = (XS_T **) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
895a95ae193SMatt Jacob 	if (isp->isp_xflist == NULL) {
896d02373f1SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array");
897a95ae193SMatt Jacob 		return (1);
898a95ae193SMatt Jacob 	}
899a95ae193SMatt Jacob 	len = sizeof (bus_dmamap_t) * isp->isp_maxcmds;
900a95ae193SMatt Jacob 	pci->dmaps = (bus_dmamap_t *) malloc(len, M_DEVBUF,  M_WAITOK);
901a95ae193SMatt Jacob 	if (pci->dmaps == NULL) {
902d02373f1SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "can't alloc dma maps");
903a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
904a95ae193SMatt Jacob 		return (1);
905a95ae193SMatt Jacob 	}
906a95ae193SMatt Jacob 
90722e1dc85SMatt Jacob 	if (IS_FC(isp) || IS_ULTRA2(isp))
908222bb542SMatt Jacob 		lim = BUS_SPACE_MAXADDR + 1;
909222bb542SMatt Jacob 	else
910222bb542SMatt Jacob 		lim = BUS_SPACE_MAXADDR_24BIT + 1;
911d720e6d5SJustin T. Gibbs 
912d720e6d5SJustin T. Gibbs 	/*
913d720e6d5SJustin T. Gibbs 	 * Allocate and map the request, result queues, plus FC scratch area.
914d720e6d5SJustin T. Gibbs 	 */
915d02373f1SMatt Jacob 	len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
916d02373f1SMatt Jacob 	len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
917222bb542SMatt Jacob 	if (IS_FC(isp)) {
918d720e6d5SJustin T. Gibbs 		len += ISP2100_SCRLEN;
919d720e6d5SJustin T. Gibbs 	}
920222bb542SMatt Jacob 	if (bus_dma_tag_create(pci->parent_dmat, PAGE_SIZE, lim,
921222bb542SMatt Jacob 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, len, 1,
922222bb542SMatt Jacob 	    BUS_SPACE_MAXSIZE_32BIT, 0, &pci->cntrol_dmat) != 0) {
923f7dddf8aSMatt Jacob 		isp_prt(isp, ISP_LOGERR,
924f7dddf8aSMatt Jacob 		    "cannot create a dma tag for control spaces");
925a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
926a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
927d720e6d5SJustin T. Gibbs 		return (1);
928d720e6d5SJustin T. Gibbs 	}
929d720e6d5SJustin T. Gibbs 	if (bus_dmamem_alloc(pci->cntrol_dmat, (void **)&base,
930d720e6d5SJustin T. Gibbs 	    BUS_DMA_NOWAIT, &pci->cntrol_dmap) != 0) {
931f7dddf8aSMatt Jacob 		isp_prt(isp, ISP_LOGERR,
9323486bfe0SMatt Jacob 		    "cannot allocate %d bytes of CCB memory", len);
933a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
934a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
935d720e6d5SJustin T. Gibbs 		return (1);
936d720e6d5SJustin T. Gibbs 	}
937d720e6d5SJustin T. Gibbs 
938d720e6d5SJustin T. Gibbs 	isp->isp_rquest = base;
939222bb542SMatt Jacob 	im.isp = isp;
940222bb542SMatt Jacob 	im.error = 0;
941d720e6d5SJustin T. Gibbs 	bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_rquest,
942d02373f1SMatt Jacob 	    ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)), isp_map_rquest, &im, 0);
943222bb542SMatt Jacob 	if (im.error) {
944f7dddf8aSMatt Jacob 		isp_prt(isp, ISP_LOGERR,
945f7dddf8aSMatt Jacob 		    "error %d loading dma map for DMA request queue", im.error);
946a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
947a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
948a95ae193SMatt Jacob 		isp->isp_rquest = NULL;
949222bb542SMatt Jacob 		return (1);
950222bb542SMatt Jacob 	}
951d02373f1SMatt Jacob 	isp->isp_result = base + ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
952222bb542SMatt Jacob 	im.error = 0;
953d720e6d5SJustin T. Gibbs 	bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_result,
954d02373f1SMatt Jacob 	    ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)), isp_map_result, &im, 0);
955222bb542SMatt Jacob 	if (im.error) {
956f7dddf8aSMatt Jacob 		isp_prt(isp, ISP_LOGERR,
957f7dddf8aSMatt Jacob 		    "error %d loading dma map for DMA result queue", im.error);
958a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
959a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
960a95ae193SMatt Jacob 		isp->isp_rquest = NULL;
961222bb542SMatt Jacob 		return (1);
962222bb542SMatt Jacob 	}
963d720e6d5SJustin T. Gibbs 
964a95ae193SMatt Jacob 	for (i = 0; i < isp->isp_maxcmds; i++) {
965d720e6d5SJustin T. Gibbs 		error = bus_dmamap_create(pci->parent_dmat, 0, &pci->dmaps[i]);
966d720e6d5SJustin T. Gibbs 		if (error) {
967f7dddf8aSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
968f7dddf8aSMatt Jacob 			    "error %d creating per-cmd DMA maps", error);
969a95ae193SMatt Jacob 			free(isp->isp_xflist, M_DEVBUF);
970a95ae193SMatt Jacob 			free(pci->dmaps, M_DEVBUF);
971a95ae193SMatt Jacob 			isp->isp_rquest = NULL;
972d720e6d5SJustin T. Gibbs 			return (1);
973d720e6d5SJustin T. Gibbs 		}
974d720e6d5SJustin T. Gibbs 	}
975a95ae193SMatt Jacob 
976222bb542SMatt Jacob 	if (IS_FC(isp)) {
97792c49d78SMatt Jacob 		fcparam *fcp = (fcparam *) isp->isp_param;
97892c49d78SMatt Jacob 		fcp->isp_scratch = base +
979d02373f1SMatt Jacob 			ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)) +
980d02373f1SMatt Jacob 			ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
981222bb542SMatt Jacob 		im.error = 0;
98292c49d78SMatt Jacob 		bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap,
983222bb542SMatt Jacob 		    fcp->isp_scratch, ISP2100_SCRLEN, isp_map_fcscrt, &im, 0);
984222bb542SMatt Jacob 		if (im.error) {
985f7dddf8aSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
986f7dddf8aSMatt Jacob 			    "error %d loading FC scratch area", im.error);
987a95ae193SMatt Jacob 			free(isp->isp_xflist, M_DEVBUF);
988a95ae193SMatt Jacob 			free(pci->dmaps, M_DEVBUF);
989a95ae193SMatt Jacob 			isp->isp_rquest = NULL;
990222bb542SMatt Jacob 			return (1);
991222bb542SMatt Jacob 		}
99292c49d78SMatt Jacob 	}
993d720e6d5SJustin T. Gibbs 	return (0);
994d720e6d5SJustin T. Gibbs }
995d720e6d5SJustin T. Gibbs 
996d720e6d5SJustin T. Gibbs typedef struct {
997d720e6d5SJustin T. Gibbs 	struct ispsoftc *isp;
9989e11e5beSMatt Jacob 	void *cmd_token;
9999e11e5beSMatt Jacob 	void *rq;
10009637d68cSMatt Jacob 	u_int16_t *iptrp;
10019637d68cSMatt Jacob 	u_int16_t optr;
1002d720e6d5SJustin T. Gibbs 	u_int error;
1003d720e6d5SJustin T. Gibbs } mush_t;
1004d720e6d5SJustin T. Gibbs 
10054873663cSMatt Jacob #define	MUSHERR_NOQENTRIES	-2
10064873663cSMatt Jacob 
10079e11e5beSMatt Jacob #ifdef	ISP_TARGET_MODE
10089e11e5beSMatt Jacob /*
10099e11e5beSMatt Jacob  * We need to handle DMA for target mode differently from initiator mode.
10109e11e5beSMatt Jacob  *
10119e11e5beSMatt Jacob  * DMA mapping and construction and submission of CTIO Request Entries
10129e11e5beSMatt Jacob  * and rendevous for completion are very tightly coupled because we start
10139e11e5beSMatt Jacob  * out by knowing (per platform) how much data we have to move, but we
10149e11e5beSMatt Jacob  * don't know, up front, how many DMA mapping segments will have to be used
10159e11e5beSMatt Jacob  * cover that data, so we don't know how many CTIO Request Entries we
10169e11e5beSMatt Jacob  * will end up using. Further, for performance reasons we may want to
10179e11e5beSMatt Jacob  * (on the last CTIO for Fibre Channel), send status too (if all went well).
10189e11e5beSMatt Jacob  *
10199e11e5beSMatt Jacob  * The standard vector still goes through isp_pci_dmasetup, but the callback
10209e11e5beSMatt Jacob  * for the DMA mapping routines comes here instead with the whole transfer
10219e11e5beSMatt Jacob  * mapped and a pointer to a partially filled in already allocated request
10229e11e5beSMatt Jacob  * queue entry. We finish the job.
10239e11e5beSMatt Jacob  */
102405fbcbb0SMatt Jacob static void tdma_mk __P((void *, bus_dma_segment_t *, int, int));
102505fbcbb0SMatt Jacob static void tdma_mkfc __P((void *, bus_dma_segment_t *, int, int));
10269e11e5beSMatt Jacob 
1027d720e6d5SJustin T. Gibbs static void
102805fbcbb0SMatt Jacob tdma_mk(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
1029d720e6d5SJustin T. Gibbs {
1030d720e6d5SJustin T. Gibbs 	mush_t *mp;
10319e11e5beSMatt Jacob 	struct ccb_scsiio *csio;
1032d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci;
1033d720e6d5SJustin T. Gibbs 	bus_dmamap_t *dp;
103405fbcbb0SMatt Jacob 	u_int8_t scsi_status;
10359e11e5beSMatt Jacob 	ct_entry_t *cto;
10365f5aafe1SMatt Jacob 	u_int16_t handle;
10375f5aafe1SMatt Jacob 	u_int32_t totxfr, sflags;
103805fbcbb0SMatt Jacob 	int nctios, send_status;
103905fbcbb0SMatt Jacob 	int32_t resid;
1040d720e6d5SJustin T. Gibbs 
1041d720e6d5SJustin T. Gibbs 	mp = (mush_t *) arg;
1042d720e6d5SJustin T. Gibbs 	if (error) {
1043d720e6d5SJustin T. Gibbs 		mp->error = error;
1044d720e6d5SJustin T. Gibbs 		return;
1045d720e6d5SJustin T. Gibbs 	}
10469e11e5beSMatt Jacob 	csio = mp->cmd_token;
10479e11e5beSMatt Jacob 	cto = mp->rq;
10489e11e5beSMatt Jacob 
104965b024e1SMatt Jacob 	cto->ct_xfrlen = 0;
105065b024e1SMatt Jacob 	cto->ct_seg_count = 0;
105165b024e1SMatt Jacob 	cto->ct_header.rqs_entry_count = 1;
105205fbcbb0SMatt Jacob 	MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg));
105305fbcbb0SMatt Jacob 
105405fbcbb0SMatt Jacob 	if (nseg == 0) {
105505fbcbb0SMatt Jacob 		cto->ct_header.rqs_seqno = 1;
105605fbcbb0SMatt Jacob 		ISP_TDQE(mp->isp, "tdma_mk[no data]", *mp->iptrp, cto);
1057d02373f1SMatt Jacob 		isp_prt(mp->isp, ISP_LOGTDEBUG1,
10585f5aafe1SMatt Jacob 		    "CTIO[%x] lun%d->iid%d flgs 0x%x sts 0x%x ssts 0x%x res %d",
10595f5aafe1SMatt Jacob 		    cto->ct_fwhandle, csio->ccb_h.target_lun, cto->ct_iid,
10605f5aafe1SMatt Jacob 		    cto->ct_flags, cto->ct_status, cto->ct_scsi_status,
10615f5aafe1SMatt Jacob 		    cto->ct_resid);
106205fbcbb0SMatt Jacob 		ISP_SWIZ_CTIO(mp->isp, cto, cto);
106365b024e1SMatt Jacob 		return;
106465b024e1SMatt Jacob 	}
106565b024e1SMatt Jacob 
106665b024e1SMatt Jacob 	nctios = nseg / ISP_RQDSEG;
106765b024e1SMatt Jacob 	if (nseg % ISP_RQDSEG) {
106865b024e1SMatt Jacob 		nctios++;
106965b024e1SMatt Jacob 	}
107065b024e1SMatt Jacob 
107105fbcbb0SMatt Jacob 	/*
10725f5aafe1SMatt Jacob 	 * Save syshandle, and potentially any SCSI status, which we'll
10735f5aafe1SMatt Jacob 	 * reinsert on the last CTIO we're going to send.
107405fbcbb0SMatt Jacob 	 */
10755f5aafe1SMatt Jacob 	handle = cto->ct_syshandle;
10765f5aafe1SMatt Jacob 	cto->ct_syshandle = 0;
107705fbcbb0SMatt Jacob 	cto->ct_header.rqs_seqno = 0;
107805fbcbb0SMatt Jacob 	send_status = (cto->ct_flags & CT_SENDSTATUS) != 0;
107905fbcbb0SMatt Jacob 
108005fbcbb0SMatt Jacob 	if (send_status) {
108105fbcbb0SMatt Jacob 		sflags = cto->ct_flags & (CT_SENDSTATUS | CT_CCINCR);
108205fbcbb0SMatt Jacob 		cto->ct_flags &= ~(CT_SENDSTATUS | CT_CCINCR);
108305fbcbb0SMatt Jacob 		/*
108405fbcbb0SMatt Jacob 		 * Preserve residual.
108505fbcbb0SMatt Jacob 		 */
108605fbcbb0SMatt Jacob 		resid = cto->ct_resid;
108705fbcbb0SMatt Jacob 
108805fbcbb0SMatt Jacob 		/*
108905fbcbb0SMatt Jacob 		 * Save actual SCSI status.
109005fbcbb0SMatt Jacob 		 */
109105fbcbb0SMatt Jacob 		scsi_status = cto->ct_scsi_status;
109205fbcbb0SMatt Jacob 
109305fbcbb0SMatt Jacob 		/*
109405fbcbb0SMatt Jacob 		 * We can't do a status at the same time as a data CTIO, so
109505fbcbb0SMatt Jacob 		 * we need to synthesize an extra CTIO at this level.
109605fbcbb0SMatt Jacob 		 */
109705fbcbb0SMatt Jacob 		nctios++;
109805fbcbb0SMatt Jacob 	} else {
109905fbcbb0SMatt Jacob 		sflags = scsi_status = resid = 0;
110005fbcbb0SMatt Jacob 	}
110105fbcbb0SMatt Jacob 
110205fbcbb0SMatt Jacob 	totxfr = cto->ct_resid = 0;
110305fbcbb0SMatt Jacob 	cto->ct_scsi_status = 0;
110405fbcbb0SMatt Jacob 
11059e11e5beSMatt Jacob 	pci = (struct isp_pcisoftc *)mp->isp;
1106469b6b9eSMatt Jacob 	dp = &pci->dmaps[isp_handle_index(handle)];
11079e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1108d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
1109d720e6d5SJustin T. Gibbs 	} else {
1110d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
1111d720e6d5SJustin T. Gibbs 	}
1112d720e6d5SJustin T. Gibbs 
11139e11e5beSMatt Jacob 
11149e11e5beSMatt Jacob 	while (nctios--) {
111505fbcbb0SMatt Jacob 		int seglim;
11169e11e5beSMatt Jacob 
11179e11e5beSMatt Jacob 		seglim = nseg;
111805fbcbb0SMatt Jacob 		if (seglim) {
111905fbcbb0SMatt Jacob 			int seg;
112005fbcbb0SMatt Jacob 
11219e11e5beSMatt Jacob 			if (seglim > ISP_RQDSEG)
11229e11e5beSMatt Jacob 				seglim = ISP_RQDSEG;
11239e11e5beSMatt Jacob 
112405fbcbb0SMatt Jacob 			for (seg = 0; seg < seglim; seg++, nseg--) {
112505fbcbb0SMatt Jacob 				/*
112605fbcbb0SMatt Jacob 				 * Unlike normal initiator commands, we don't
112705fbcbb0SMatt Jacob 				 * do any swizzling here.
112805fbcbb0SMatt Jacob 				 */
11299e11e5beSMatt Jacob 				cto->ct_dataseg[seg].ds_count = dm_segs->ds_len;
113005fbcbb0SMatt Jacob 				cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr;
11319e11e5beSMatt Jacob 				cto->ct_xfrlen += dm_segs->ds_len;
113205fbcbb0SMatt Jacob 				totxfr += dm_segs->ds_len;
11339e11e5beSMatt Jacob 				dm_segs++;
11349e11e5beSMatt Jacob 			}
11359e11e5beSMatt Jacob 			cto->ct_seg_count = seg;
11369e11e5beSMatt Jacob 		} else {
113705fbcbb0SMatt Jacob 			/*
113805fbcbb0SMatt Jacob 			 * This case should only happen when we're sending an
113905fbcbb0SMatt Jacob 			 * extra CTIO with final status.
114005fbcbb0SMatt Jacob 			 */
114105fbcbb0SMatt Jacob 			if (send_status == 0) {
1142f7dddf8aSMatt Jacob 				isp_prt(mp->isp, ISP_LOGWARN,
1143f7dddf8aSMatt Jacob 				    "tdma_mk ran out of segments");
114405fbcbb0SMatt Jacob 				mp->error = EINVAL;
114505fbcbb0SMatt Jacob 				return;
11469e11e5beSMatt Jacob 			}
114705fbcbb0SMatt Jacob 		}
114805fbcbb0SMatt Jacob 
114905fbcbb0SMatt Jacob 		/*
115005fbcbb0SMatt Jacob 		 * At this point, the fields ct_lun, ct_iid, ct_tagval,
115105fbcbb0SMatt Jacob 		 * ct_tagtype, and ct_timeout have been carried over
115205fbcbb0SMatt Jacob 		 * unchanged from what our caller had set.
115305fbcbb0SMatt Jacob 		 *
115405fbcbb0SMatt Jacob 		 * The dataseg fields and the seg_count fields we just got
115505fbcbb0SMatt Jacob 		 * through setting. The data direction we've preserved all
115605fbcbb0SMatt Jacob 		 * along and only clear it if we're now sending status.
115705fbcbb0SMatt Jacob 		 */
11589e11e5beSMatt Jacob 
11599e11e5beSMatt Jacob 		if (nctios == 0) {
11609e11e5beSMatt Jacob 			/*
116105fbcbb0SMatt Jacob 			 * We're the last in a sequence of CTIOs, so mark
116205fbcbb0SMatt Jacob 			 * this CTIO and save the handle to the CCB such that
116305fbcbb0SMatt Jacob 			 * when this CTIO completes we can free dma resources
116405fbcbb0SMatt Jacob 			 * and do whatever else we need to do to finish the
116505fbcbb0SMatt Jacob 			 * rest of the command.
11669e11e5beSMatt Jacob 			 */
11675f5aafe1SMatt Jacob 			cto->ct_syshandle = handle;
116805fbcbb0SMatt Jacob 			cto->ct_header.rqs_seqno = 1;
116905fbcbb0SMatt Jacob 
117005fbcbb0SMatt Jacob 			if (send_status) {
11719e11e5beSMatt Jacob 				cto->ct_scsi_status = scsi_status;
117205fbcbb0SMatt Jacob 				cto->ct_flags |= sflags | CT_NO_DATA;;
117305fbcbb0SMatt Jacob 				cto->ct_resid = resid;
117442426921SMatt Jacob 			}
1175d02373f1SMatt Jacob 			if (send_status) {
1176d02373f1SMatt Jacob 				isp_prt(mp->isp, ISP_LOGTDEBUG1,
11775f5aafe1SMatt Jacob 				    "CTIO[%x] lun%d for ID %d ct_flags 0x%x "
11785f5aafe1SMatt Jacob 				    "scsi status %x resid %d",
11795f5aafe1SMatt Jacob 				    cto->ct_fwhandle, csio->ccb_h.target_lun,
118005fbcbb0SMatt Jacob 				    cto->ct_iid, cto->ct_flags,
118105fbcbb0SMatt Jacob 				    cto->ct_scsi_status, cto->ct_resid);
1182d02373f1SMatt Jacob 			} else {
1183d02373f1SMatt Jacob 				isp_prt(mp->isp, ISP_LOGTDEBUG1,
11845f5aafe1SMatt Jacob 				    "CTIO[%x] lun%d for ID%d ct_flags 0x%x",
11855f5aafe1SMatt Jacob 				    cto->ct_fwhandle, csio->ccb_h.target_lun,
118605fbcbb0SMatt Jacob 				    cto->ct_iid, cto->ct_flags);
118705fbcbb0SMatt Jacob 			}
118805fbcbb0SMatt Jacob 			ISP_TDQE(mp->isp, "last tdma_mk", *mp->iptrp, cto);
118905fbcbb0SMatt Jacob 			ISP_SWIZ_CTIO(mp->isp, cto, cto);
11909e11e5beSMatt Jacob 		} else {
11919e11e5beSMatt Jacob 			ct_entry_t     *octo = cto;
119205fbcbb0SMatt Jacob 
119305fbcbb0SMatt Jacob 			/*
11945f5aafe1SMatt Jacob 			 * Make sure syshandle fields are clean
119505fbcbb0SMatt Jacob 			 */
11965f5aafe1SMatt Jacob 			cto->ct_syshandle = 0;
11979e11e5beSMatt Jacob 			cto->ct_header.rqs_seqno = 0;
119805fbcbb0SMatt Jacob 
1199d02373f1SMatt Jacob 			isp_prt(mp->isp, ISP_LOGTDEBUG1,
12005f5aafe1SMatt Jacob 			    "CTIO[%x] lun%d for ID%d ct_flags 0x%x",
12015f5aafe1SMatt Jacob 			    cto->ct_fwhandle, csio->ccb_h.target_lun,
12025f5aafe1SMatt Jacob 			    cto->ct_iid, cto->ct_flags);
120305fbcbb0SMatt Jacob 			ISP_TDQE(mp->isp, "tdma_mk", *mp->iptrp, cto);
120405fbcbb0SMatt Jacob 
120505fbcbb0SMatt Jacob 			/*
120605fbcbb0SMatt Jacob 			 * Get a new CTIO
120705fbcbb0SMatt Jacob 			 */
12089e11e5beSMatt Jacob 			cto = (ct_entry_t *)
12099e11e5beSMatt Jacob 			    ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
12109e11e5beSMatt Jacob 			*mp->iptrp =
1211d02373f1SMatt Jacob 			    ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp));
12129e11e5beSMatt Jacob 			if (*mp->iptrp == mp->optr) {
12135f5aafe1SMatt Jacob 				isp_prt(mp->isp, ISP_LOGTDEBUG0,
1214f7dddf8aSMatt Jacob 				    "Queue Overflow in tdma_mk");
12159e11e5beSMatt Jacob 				mp->error = MUSHERR_NOQENTRIES;
12169e11e5beSMatt Jacob 				return;
12179e11e5beSMatt Jacob 			}
12189e11e5beSMatt Jacob 			/*
12199e11e5beSMatt Jacob 			 * Fill in the new CTIO with info from the old one.
12209e11e5beSMatt Jacob 			 */
12219e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
12229e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_count = 1;
12235f5aafe1SMatt Jacob 			cto->ct_fwhandle = octo->ct_fwhandle;
12249e11e5beSMatt Jacob 			cto->ct_header.rqs_flags = 0;
12259e11e5beSMatt Jacob 			cto->ct_lun = octo->ct_lun;
12269e11e5beSMatt Jacob 			cto->ct_iid = octo->ct_iid;
12279e11e5beSMatt Jacob 			cto->ct_reserved2 = octo->ct_reserved2;
12289e11e5beSMatt Jacob 			cto->ct_tgt = octo->ct_tgt;
122905fbcbb0SMatt Jacob 			cto->ct_flags = octo->ct_flags;
12309e11e5beSMatt Jacob 			cto->ct_status = 0;
12319e11e5beSMatt Jacob 			cto->ct_scsi_status = 0;
12329e11e5beSMatt Jacob 			cto->ct_tag_val = octo->ct_tag_val;
12339e11e5beSMatt Jacob 			cto->ct_tag_type = octo->ct_tag_type;
12349e11e5beSMatt Jacob 			cto->ct_xfrlen = 0;
12359e11e5beSMatt Jacob 			cto->ct_resid = 0;
12369e11e5beSMatt Jacob 			cto->ct_timeout = octo->ct_timeout;
12379e11e5beSMatt Jacob 			cto->ct_seg_count = 0;
123805fbcbb0SMatt Jacob 			MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg));
123905fbcbb0SMatt Jacob 			/*
124005fbcbb0SMatt Jacob 			 * Now swizzle the old one for the consumption of the
124105fbcbb0SMatt Jacob 			 * chip.
124205fbcbb0SMatt Jacob 			 */
124305fbcbb0SMatt Jacob 			ISP_SWIZ_CTIO(mp->isp, octo, octo);
12449e11e5beSMatt Jacob 		}
12459e11e5beSMatt Jacob 	}
12469e11e5beSMatt Jacob }
12479e11e5beSMatt Jacob 
12489e11e5beSMatt Jacob static void
124905fbcbb0SMatt Jacob tdma_mkfc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
12509e11e5beSMatt Jacob {
12519e11e5beSMatt Jacob 	mush_t *mp;
12529e11e5beSMatt Jacob 	struct ccb_scsiio *csio;
12539e11e5beSMatt Jacob 	struct isp_pcisoftc *pci;
12549e11e5beSMatt Jacob 	bus_dmamap_t *dp;
12559e11e5beSMatt Jacob 	ct2_entry_t *cto;
12565f5aafe1SMatt Jacob 	u_int16_t scsi_status, send_status, send_sense, handle;
12575f5aafe1SMatt Jacob 	u_int32_t totxfr, datalen;
125865b024e1SMatt Jacob 	u_int8_t sense[QLTM_SENSELEN];
12599e11e5beSMatt Jacob 	int nctios;
12609e11e5beSMatt Jacob 
12619e11e5beSMatt Jacob 	mp = (mush_t *) arg;
12629e11e5beSMatt Jacob 	if (error) {
12639e11e5beSMatt Jacob 		mp->error = error;
12649e11e5beSMatt Jacob 		return;
12659e11e5beSMatt Jacob 	}
12669e11e5beSMatt Jacob 
126765b024e1SMatt Jacob 	csio = mp->cmd_token;
126865b024e1SMatt Jacob 	cto = mp->rq;
126965b024e1SMatt Jacob 
127065b024e1SMatt Jacob 	if (nseg == 0) {
127165b024e1SMatt Jacob 		if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE1) {
1272f7dddf8aSMatt Jacob 			isp_prt(mp->isp, ISP_LOGWARN,
1273f7dddf8aSMatt Jacob 			    "dma2_tgt_fc, a status CTIO2 without MODE1 "
1274f7dddf8aSMatt Jacob 			    "set (0x%x)", cto->ct_flags);
127565b024e1SMatt Jacob 			mp->error = EINVAL;
127665b024e1SMatt Jacob 			return;
127765b024e1SMatt Jacob 		}
127865b024e1SMatt Jacob 	 	cto->ct_header.rqs_entry_count = 1;
127905fbcbb0SMatt Jacob 		cto->ct_header.rqs_seqno = 1;
12805f5aafe1SMatt Jacob 		/* ct_syshandle contains the handle set by caller */
128165b024e1SMatt Jacob 		/*
128265b024e1SMatt Jacob 		 * We preserve ct_lun, ct_iid, ct_rxid. We set the data
128365b024e1SMatt Jacob 		 * flags to NO DATA and clear relative offset flags.
128465b024e1SMatt Jacob 		 * We preserve the ct_resid and the response area.
128565b024e1SMatt Jacob 		 */
128665b024e1SMatt Jacob 		cto->ct_flags |= CT2_NO_DATA;
128705fbcbb0SMatt Jacob 		if (cto->ct_resid > 0)
128805fbcbb0SMatt Jacob 			cto->ct_flags |= CT2_DATA_UNDER;
128905fbcbb0SMatt Jacob 		else if (cto->ct_resid < 0)
129005fbcbb0SMatt Jacob 			cto->ct_flags |= CT2_DATA_OVER;
129165b024e1SMatt Jacob 		cto->ct_seg_count = 0;
129265b024e1SMatt Jacob 		cto->ct_reloff = 0;
129365b024e1SMatt Jacob 		ISP_TDQE(mp->isp, "dma2_tgt_fc[no data]", *mp->iptrp, cto);
1294d02373f1SMatt Jacob 		isp_prt(mp->isp, ISP_LOGTDEBUG1,
12955f5aafe1SMatt Jacob 		    "CTIO2[%x] lun %d->iid%d flgs 0x%x sts 0x%x ssts "
1296d02373f1SMatt Jacob 		    "0x%x res %d", cto->ct_rxid, csio->ccb_h.target_lun,
1297d02373f1SMatt Jacob 		    cto->ct_iid, cto->ct_flags, cto->ct_status,
129865b024e1SMatt Jacob 		    cto->rsp.m1.ct_scsi_status, cto->ct_resid);
129965b024e1SMatt Jacob 		ISP_SWIZ_CTIO2(isp, cto, cto);
13009e11e5beSMatt Jacob 		return;
13019e11e5beSMatt Jacob 	}
13029e11e5beSMatt Jacob 
130365b024e1SMatt Jacob 	if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE0) {
1304f7dddf8aSMatt Jacob 		isp_prt(mp->isp, ISP_LOGWARN,
1305f7dddf8aSMatt Jacob 		    "dma2_tgt_fc, a data CTIO2 without MODE0 set "
1306f7dddf8aSMatt Jacob 		    "(0x%x)", cto->ct_flags);
130765b024e1SMatt Jacob 		mp->error = EINVAL;
130865b024e1SMatt Jacob 		return;
130965b024e1SMatt Jacob 	}
131065b024e1SMatt Jacob 
131165b024e1SMatt Jacob 
131265b024e1SMatt Jacob 	nctios = nseg / ISP_RQDSEG_T2;
131365b024e1SMatt Jacob 	if (nseg % ISP_RQDSEG_T2) {
131465b024e1SMatt Jacob 		nctios++;
131565b024e1SMatt Jacob 	}
131665b024e1SMatt Jacob 
13179e11e5beSMatt Jacob 	/*
131865b024e1SMatt Jacob 	 * Save the handle, status, reloff, and residual. We'll reinsert the
131965b024e1SMatt Jacob 	 * handle into the last CTIO2 we're going to send, and reinsert status
132065b024e1SMatt Jacob 	 * and residual (and possibly sense data) if that's to be sent as well.
132165b024e1SMatt Jacob 	 *
132265b024e1SMatt Jacob 	 * We preserve ct_reloff and adjust it for each data CTIO2 we send past
132365b024e1SMatt Jacob 	 * the first one. This is needed so that the FCP DATA IUs being sent
132465b024e1SMatt Jacob 	 * out have the correct offset (they can arrive at the other end out
132565b024e1SMatt Jacob 	 * of order).
13269e11e5beSMatt Jacob 	 */
132765b024e1SMatt Jacob 
13285f5aafe1SMatt Jacob 	handle = cto->ct_syshandle;
13295f5aafe1SMatt Jacob 	cto->ct_syshandle = 0;
133065b024e1SMatt Jacob 
133165b024e1SMatt Jacob 	if ((send_status = (cto->ct_flags & CT2_SENDSTATUS)) != 0) {
13329e11e5beSMatt Jacob 		cto->ct_flags &= ~CT2_SENDSTATUS;
13339e11e5beSMatt Jacob 
133465b024e1SMatt Jacob 		/*
133505fbcbb0SMatt Jacob 		 * Preserve residual, which is actually the total count.
133665b024e1SMatt Jacob 		 */
133705fbcbb0SMatt Jacob 		datalen = cto->ct_resid;
133865b024e1SMatt Jacob 
133965b024e1SMatt Jacob 		/*
134065b024e1SMatt Jacob 		 * Save actual SCSI status. We'll reinsert the
134165b024e1SMatt Jacob 		 * CT2_SNSLEN_VALID later if appropriate.
134265b024e1SMatt Jacob 		 */
134365b024e1SMatt Jacob 		scsi_status = cto->rsp.m0.ct_scsi_status & 0xff;
134465b024e1SMatt Jacob 		send_sense = cto->rsp.m0.ct_scsi_status & CT2_SNSLEN_VALID;
134565b024e1SMatt Jacob 
134665b024e1SMatt Jacob 		/*
134765b024e1SMatt Jacob 		 * If we're sending status and have a CHECK CONDTION and
134865b024e1SMatt Jacob 		 * have sense data,  we send one more CTIO2 with just the
134965b024e1SMatt Jacob 		 * status and sense data. The upper layers have stashed
135065b024e1SMatt Jacob 		 * the sense data in the dataseg structure for us.
135165b024e1SMatt Jacob 		 */
135265b024e1SMatt Jacob 
135365b024e1SMatt Jacob 		if ((scsi_status & 0xf) == SCSI_STATUS_CHECK_COND &&
135465b024e1SMatt Jacob 		    send_sense) {
135565b024e1SMatt Jacob 			bcopy(cto->rsp.m0.ct_dataseg, sense, QLTM_SENSELEN);
135665b024e1SMatt Jacob 			nctios++;
135765b024e1SMatt Jacob 		}
135865b024e1SMatt Jacob 	} else {
135905fbcbb0SMatt Jacob 		scsi_status = send_sense = datalen = 0;
136065b024e1SMatt Jacob 	}
136165b024e1SMatt Jacob 
136265b024e1SMatt Jacob 	totxfr = cto->ct_resid = 0;
136365b024e1SMatt Jacob 	cto->rsp.m0.ct_scsi_status = 0;
136465b024e1SMatt Jacob 	bzero(&cto->rsp, sizeof (cto->rsp));
136565b024e1SMatt Jacob 
13669e11e5beSMatt Jacob 	pci = (struct isp_pcisoftc *)mp->isp;
1367469b6b9eSMatt Jacob 	dp = &pci->dmaps[isp_handle_index(handle)];
13689e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
13699e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
13709e11e5beSMatt Jacob 	} else {
13719e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
13729e11e5beSMatt Jacob 	}
13739e11e5beSMatt Jacob 
13749e11e5beSMatt Jacob 	while (nctios--) {
13759e11e5beSMatt Jacob 		int seg, seglim;
13769e11e5beSMatt Jacob 
13779e11e5beSMatt Jacob 		seglim = nseg;
137865b024e1SMatt Jacob 		if (seglim) {
13799e11e5beSMatt Jacob 			if (seglim > ISP_RQDSEG_T2)
13809e11e5beSMatt Jacob 				seglim = ISP_RQDSEG_T2;
13819e11e5beSMatt Jacob 
13829e11e5beSMatt Jacob 			for (seg = 0; seg < seglim; seg++) {
138365b024e1SMatt Jacob 				cto->rsp.m0.ct_dataseg[seg].ds_base =
138465b024e1SMatt Jacob 				    dm_segs->ds_addr;
138565b024e1SMatt Jacob 				cto->rsp.m0.ct_dataseg[seg].ds_count =
138665b024e1SMatt Jacob 				    dm_segs->ds_len;
13879e11e5beSMatt Jacob 				cto->rsp.m0.ct_xfrlen += dm_segs->ds_len;
138865b024e1SMatt Jacob 				totxfr += dm_segs->ds_len;
13899e11e5beSMatt Jacob 				dm_segs++;
13909e11e5beSMatt Jacob 			}
13919e11e5beSMatt Jacob 			cto->ct_seg_count = seg;
13929e11e5beSMatt Jacob 		} else {
139365b024e1SMatt Jacob 			/*
139465b024e1SMatt Jacob 			 * This case should only happen when we're sending a
139565b024e1SMatt Jacob 			 * synthesized MODE1 final status with sense data.
139665b024e1SMatt Jacob 			 */
139765b024e1SMatt Jacob 			if (send_sense == 0) {
1398f7dddf8aSMatt Jacob 				isp_prt(mp->isp, ISP_LOGWARN,
1399f7dddf8aSMatt Jacob 				    "dma2_tgt_fc ran out of segments, "
1400f7dddf8aSMatt Jacob 				    "no SENSE DATA");
140165b024e1SMatt Jacob 				mp->error = EINVAL;
140265b024e1SMatt Jacob 				return;
140365b024e1SMatt Jacob 			}
14049e11e5beSMatt Jacob 		}
14059e11e5beSMatt Jacob 
14069e11e5beSMatt Jacob 		/*
140765b024e1SMatt Jacob 		 * At this point, the fields ct_lun, ct_iid, ct_rxid,
140865b024e1SMatt Jacob 		 * ct_timeout have been carried over unchanged from what
140965b024e1SMatt Jacob 		 * our caller had set.
141065b024e1SMatt Jacob 		 *
141165b024e1SMatt Jacob 		 * The field ct_reloff is either what the caller set, or
141265b024e1SMatt Jacob 		 * what we've added to below.
141365b024e1SMatt Jacob 		 *
141465b024e1SMatt Jacob 		 * The dataseg fields and the seg_count fields we just got
141565b024e1SMatt Jacob 		 * through setting. The data direction we've preserved all
141665b024e1SMatt Jacob 		 * along and only clear it if we're sending a MODE1 status
141765b024e1SMatt Jacob 		 * as the last CTIO.
141865b024e1SMatt Jacob 		 *
141965b024e1SMatt Jacob 		 */
142065b024e1SMatt Jacob 
142165b024e1SMatt Jacob 		if (nctios == 0) {
142265b024e1SMatt Jacob 
142365b024e1SMatt Jacob 			/*
142465b024e1SMatt Jacob 			 * We're the last in a sequence of CTIO2s, so mark this
142565b024e1SMatt Jacob 			 * CTIO2 and save the handle to the CCB such that when
142665b024e1SMatt Jacob 			 * this CTIO2 completes we can free dma resources and
14279e11e5beSMatt Jacob 			 * do whatever else we need to do to finish the rest
14289e11e5beSMatt Jacob 			 * of the command.
14299e11e5beSMatt Jacob 			 */
143065b024e1SMatt Jacob 
14315f5aafe1SMatt Jacob 			cto->ct_syshandle = handle;
143265b024e1SMatt Jacob 			cto->ct_header.rqs_seqno = 1;
143365b024e1SMatt Jacob 
143465b024e1SMatt Jacob 			if (send_status) {
143565b024e1SMatt Jacob 				if (send_sense) {
143665b024e1SMatt Jacob 					bcopy(sense, cto->rsp.m1.ct_resp,
143765b024e1SMatt Jacob 					    QLTM_SENSELEN);
143865b024e1SMatt Jacob 					cto->rsp.m1.ct_senselen =
143965b024e1SMatt Jacob 					    QLTM_SENSELEN;
144065b024e1SMatt Jacob 					scsi_status |= CT2_SNSLEN_VALID;
144165b024e1SMatt Jacob 					cto->rsp.m1.ct_scsi_status =
144265b024e1SMatt Jacob 					    scsi_status;
144365b024e1SMatt Jacob 					cto->ct_flags &= CT2_FLAG_MMASK;
144465b024e1SMatt Jacob 					cto->ct_flags |= CT2_FLAG_MODE1 |
144565b024e1SMatt Jacob 					    CT2_NO_DATA| CT2_SENDSTATUS;
144665b024e1SMatt Jacob 				} else {
144765b024e1SMatt Jacob 					cto->rsp.m0.ct_scsi_status =
144865b024e1SMatt Jacob 					    scsi_status;
144965b024e1SMatt Jacob 					cto->ct_flags |= CT2_SENDSTATUS;
145065b024e1SMatt Jacob 				}
145105fbcbb0SMatt Jacob 				/*
145205fbcbb0SMatt Jacob 				 * Get 'real' residual and set flags based
145305fbcbb0SMatt Jacob 				 * on it.
145405fbcbb0SMatt Jacob 				 */
145505fbcbb0SMatt Jacob 				cto->ct_resid = datalen - totxfr;
145605fbcbb0SMatt Jacob 				if (cto->ct_resid > 0)
145705fbcbb0SMatt Jacob 					cto->ct_flags |= CT2_DATA_UNDER;
145805fbcbb0SMatt Jacob 				else if (cto->ct_resid < 0)
145905fbcbb0SMatt Jacob 					cto->ct_flags |= CT2_DATA_OVER;
146065b024e1SMatt Jacob 			}
14619e11e5beSMatt Jacob 			ISP_TDQE(mp->isp, "last dma2_tgt_fc", *mp->iptrp, cto);
1462d02373f1SMatt Jacob 			isp_prt(mp->isp, ISP_LOGTDEBUG1,
14635f5aafe1SMatt Jacob 			    "CTIO2[%x] lun %d->iid%d flgs 0x%x sts 0x%x"
1464d02373f1SMatt Jacob 			    " ssts 0x%x res %d", cto->ct_rxid,
146565b024e1SMatt Jacob 			    csio->ccb_h.target_lun, (int) cto->ct_iid,
146642426921SMatt Jacob 			    cto->ct_flags, cto->ct_status,
146765b024e1SMatt Jacob 			    cto->rsp.m1.ct_scsi_status, cto->ct_resid);
146865b024e1SMatt Jacob 			ISP_SWIZ_CTIO2(isp, cto, cto);
14699e11e5beSMatt Jacob 		} else {
14709e11e5beSMatt Jacob 			ct2_entry_t *octo = cto;
147165b024e1SMatt Jacob 
147265b024e1SMatt Jacob 			/*
147365b024e1SMatt Jacob 			 * Make sure handle fields are clean
147465b024e1SMatt Jacob 			 */
14755f5aafe1SMatt Jacob 			cto->ct_syshandle = 0;
14769e11e5beSMatt Jacob 			cto->ct_header.rqs_seqno = 0;
147765b024e1SMatt Jacob 
14789e11e5beSMatt Jacob 			ISP_TDQE(mp->isp, "dma2_tgt_fc", *mp->iptrp, cto);
1479d02373f1SMatt Jacob 			isp_prt(mp->isp, ISP_LOGTDEBUG1,
14805f5aafe1SMatt Jacob 			    "CTIO2[%x] lun %d->iid%d flgs 0x%x",
1481d02373f1SMatt Jacob 			    cto->ct_rxid, csio->ccb_h.target_lun,
1482d02373f1SMatt Jacob 			    (int) cto->ct_iid, cto->ct_flags);
148365b024e1SMatt Jacob 			/*
148465b024e1SMatt Jacob 			 * Get a new CTIO2
148565b024e1SMatt Jacob 			 */
14869e11e5beSMatt Jacob 			cto = (ct2_entry_t *)
14879e11e5beSMatt Jacob 			    ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
14889e11e5beSMatt Jacob 			*mp->iptrp =
1489d02373f1SMatt Jacob 			    ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp));
14909e11e5beSMatt Jacob 			if (*mp->iptrp == mp->optr) {
1491f7dddf8aSMatt Jacob 				isp_prt(mp->isp, ISP_LOGWARN,
1492f7dddf8aSMatt Jacob 				    "Queue Overflow in dma2_tgt_fc");
14939e11e5beSMatt Jacob 				mp->error = MUSHERR_NOQENTRIES;
14949e11e5beSMatt Jacob 				return;
14959e11e5beSMatt Jacob 			}
149665b024e1SMatt Jacob 
14979e11e5beSMatt Jacob 			/*
149865b024e1SMatt Jacob 			 * Fill in the new CTIO2 with info from the old one.
14999e11e5beSMatt Jacob 			 */
15009e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
15019e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_count = 1;
15029e11e5beSMatt Jacob 			cto->ct_header.rqs_flags = 0;
15035f5aafe1SMatt Jacob 			/* ct_header.rqs_seqno && ct_syshandle done later */
15045f5aafe1SMatt Jacob 			cto->ct_fwhandle = octo->ct_fwhandle;
15059e11e5beSMatt Jacob 			cto->ct_lun = octo->ct_lun;
15069e11e5beSMatt Jacob 			cto->ct_iid = octo->ct_iid;
15079e11e5beSMatt Jacob 			cto->ct_rxid = octo->ct_rxid;
150865b024e1SMatt Jacob 			cto->ct_flags = octo->ct_flags;
15099e11e5beSMatt Jacob 			cto->ct_status = 0;
15109e11e5beSMatt Jacob 			cto->ct_resid = 0;
15119e11e5beSMatt Jacob 			cto->ct_timeout = octo->ct_timeout;
15129e11e5beSMatt Jacob 			cto->ct_seg_count = 0;
151365b024e1SMatt Jacob 			/*
151465b024e1SMatt Jacob 			 * Adjust the new relative offset by the amount which
151565b024e1SMatt Jacob 			 * is recorded in the data segment of the old CTIO2 we
151665b024e1SMatt Jacob 			 * just finished filling out.
151765b024e1SMatt Jacob 			 */
151865b024e1SMatt Jacob 			cto->ct_reloff += octo->rsp.m0.ct_xfrlen;
15199e11e5beSMatt Jacob 			bzero(&cto->rsp, sizeof (cto->rsp));
152065b024e1SMatt Jacob 			ISP_SWIZ_CTIO2(isp, cto, cto);
15219e11e5beSMatt Jacob 		}
15229e11e5beSMatt Jacob 	}
15239e11e5beSMatt Jacob }
15249e11e5beSMatt Jacob #endif
15259e11e5beSMatt Jacob 
15269e11e5beSMatt Jacob static void dma2 __P((void *, bus_dma_segment_t *, int, int));
15279e11e5beSMatt Jacob 
15289e11e5beSMatt Jacob static void
15299e11e5beSMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
15309e11e5beSMatt Jacob {
15319e11e5beSMatt Jacob 	mush_t *mp;
15329e11e5beSMatt Jacob 	struct ccb_scsiio *csio;
15339e11e5beSMatt Jacob 	struct isp_pcisoftc *pci;
15349e11e5beSMatt Jacob 	bus_dmamap_t *dp;
15359e11e5beSMatt Jacob 	bus_dma_segment_t *eseg;
15369e11e5beSMatt Jacob 	ispreq_t *rq;
15379e11e5beSMatt Jacob 	ispcontreq_t *crq;
15389e11e5beSMatt Jacob 	int seglim, datalen;
15399e11e5beSMatt Jacob 
15409e11e5beSMatt Jacob 	mp = (mush_t *) arg;
15419e11e5beSMatt Jacob 	if (error) {
15429e11e5beSMatt Jacob 		mp->error = error;
15439e11e5beSMatt Jacob 		return;
15449e11e5beSMatt Jacob 	}
15459e11e5beSMatt Jacob 
15469e11e5beSMatt Jacob 	if (nseg < 1) {
1547f7dddf8aSMatt Jacob 		isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg);
15489e11e5beSMatt Jacob 		mp->error = EFAULT;
15499e11e5beSMatt Jacob 		return;
15509e11e5beSMatt Jacob 	}
15519e11e5beSMatt Jacob 	csio = mp->cmd_token;
15529e11e5beSMatt Jacob 	rq = mp->rq;
15539e11e5beSMatt Jacob 	pci = (struct isp_pcisoftc *)mp->isp;
1554469b6b9eSMatt Jacob 	dp = &pci->dmaps[isp_handle_index(rq->req_handle)];
15559e11e5beSMatt Jacob 
15569e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
15579e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
15589e11e5beSMatt Jacob 	} else {
15599e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
15609e11e5beSMatt Jacob 	}
15619e11e5beSMatt Jacob 
15629e11e5beSMatt Jacob 	datalen = XS_XFRLEN(csio);
15639e11e5beSMatt Jacob 
15649e11e5beSMatt Jacob 	/*
15659e11e5beSMatt Jacob 	 * We're passed an initial partially filled in entry that
15669e11e5beSMatt Jacob 	 * has most fields filled in except for data transfer
15679e11e5beSMatt Jacob 	 * related values.
15689e11e5beSMatt Jacob 	 *
15699e11e5beSMatt Jacob 	 * Our job is to fill in the initial request queue entry and
15709e11e5beSMatt Jacob 	 * then to start allocating and filling in continuation entries
15719e11e5beSMatt Jacob 	 * until we've covered the entire transfer.
15729e11e5beSMatt Jacob 	 */
15739e11e5beSMatt Jacob 
15749e11e5beSMatt Jacob 	if (IS_FC(mp->isp)) {
1575d720e6d5SJustin T. Gibbs 		seglim = ISP_RQDSEG_T2;
1576d720e6d5SJustin T. Gibbs 		((ispreqt2_t *)rq)->req_totalcnt = datalen;
15779e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
15789e11e5beSMatt Jacob 			((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_IN;
15799e11e5beSMatt Jacob 		} else {
15809e11e5beSMatt Jacob 			((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_OUT;
15819e11e5beSMatt Jacob 		}
1582d720e6d5SJustin T. Gibbs 	} else {
1583e142669aSMatt Jacob 		if (csio->cdb_len > 12) {
1584e142669aSMatt Jacob 			seglim = 0;
1585e142669aSMatt Jacob 		} else {
1586d720e6d5SJustin T. Gibbs 			seglim = ISP_RQDSEG;
1587e142669aSMatt Jacob 		}
15889e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
15899e11e5beSMatt Jacob 			rq->req_flags |= REQFLAG_DATA_IN;
15909e11e5beSMatt Jacob 		} else {
15919e11e5beSMatt Jacob 			rq->req_flags |= REQFLAG_DATA_OUT;
15929e11e5beSMatt Jacob 		}
1593d720e6d5SJustin T. Gibbs 	}
1594d720e6d5SJustin T. Gibbs 
1595d720e6d5SJustin T. Gibbs 	eseg = dm_segs + nseg;
1596d720e6d5SJustin T. Gibbs 
1597d720e6d5SJustin T. Gibbs 	while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) {
15989e11e5beSMatt Jacob 		if (IS_FC(mp->isp)) {
1599d720e6d5SJustin T. Gibbs 			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
1600d720e6d5SJustin T. Gibbs 			rq2->req_dataseg[rq2->req_seg_count].ds_base =
1601d720e6d5SJustin T. Gibbs 			    dm_segs->ds_addr;
1602d720e6d5SJustin T. Gibbs 			rq2->req_dataseg[rq2->req_seg_count].ds_count =
1603d720e6d5SJustin T. Gibbs 			    dm_segs->ds_len;
1604d720e6d5SJustin T. Gibbs 		} else {
1605d720e6d5SJustin T. Gibbs 			rq->req_dataseg[rq->req_seg_count].ds_base =
1606d720e6d5SJustin T. Gibbs 				dm_segs->ds_addr;
1607d720e6d5SJustin T. Gibbs 			rq->req_dataseg[rq->req_seg_count].ds_count =
1608d720e6d5SJustin T. Gibbs 				dm_segs->ds_len;
1609d720e6d5SJustin T. Gibbs 		}
1610d720e6d5SJustin T. Gibbs 		datalen -= dm_segs->ds_len;
1611d720e6d5SJustin T. Gibbs #if	0
16129e11e5beSMatt Jacob 		if (IS_FC(mp->isp)) {
1613d720e6d5SJustin T. Gibbs 			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
16146e5c5328SMatt Jacob 			device_printf(mp->isp->isp_dev,
16156e5c5328SMatt Jacob 			    "seg0[%d] cnt 0x%x paddr 0x%08x\n",
16166e5c5328SMatt Jacob 			    rq->req_seg_count,
1617d720e6d5SJustin T. Gibbs 			    rq2->req_dataseg[rq2->req_seg_count].ds_count,
1618d720e6d5SJustin T. Gibbs 			    rq2->req_dataseg[rq2->req_seg_count].ds_base);
1619d720e6d5SJustin T. Gibbs 		} else {
16206e5c5328SMatt Jacob 			device_printf(mp->isp->isp_dev,
16216e5c5328SMatt Jacob 			    "seg0[%d] cnt 0x%x paddr 0x%08x\n",
16226e5c5328SMatt Jacob 			    rq->req_seg_count,
1623d720e6d5SJustin T. Gibbs 			    rq->req_dataseg[rq->req_seg_count].ds_count,
1624d720e6d5SJustin T. Gibbs 			    rq->req_dataseg[rq->req_seg_count].ds_base);
1625d720e6d5SJustin T. Gibbs 		}
1626d720e6d5SJustin T. Gibbs #endif
1627d720e6d5SJustin T. Gibbs 		rq->req_seg_count++;
1628d720e6d5SJustin T. Gibbs 		dm_segs++;
1629d720e6d5SJustin T. Gibbs 	}
1630d720e6d5SJustin T. Gibbs 
1631d720e6d5SJustin T. Gibbs 	while (datalen > 0 && dm_segs != eseg) {
16329e11e5beSMatt Jacob 		crq = (ispcontreq_t *)
16339e11e5beSMatt Jacob 		    ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
1634d02373f1SMatt Jacob 		*mp->iptrp = ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp));
16359e11e5beSMatt Jacob 		if (*mp->iptrp == mp->optr) {
16366e5c5328SMatt Jacob 			isp_prt(mp->isp,
16376e5c5328SMatt Jacob 			    ISP_LOGDEBUG0, "Request Queue Overflow++");
16384873663cSMatt Jacob 			mp->error = MUSHERR_NOQENTRIES;
1639d720e6d5SJustin T. Gibbs 			return;
1640d720e6d5SJustin T. Gibbs 		}
1641d720e6d5SJustin T. Gibbs 		rq->req_header.rqs_entry_count++;
1642d720e6d5SJustin T. Gibbs 		bzero((void *)crq, sizeof (*crq));
1643d720e6d5SJustin T. Gibbs 		crq->req_header.rqs_entry_count = 1;
1644d720e6d5SJustin T. Gibbs 		crq->req_header.rqs_entry_type = RQSTYPE_DATASEG;
1645d720e6d5SJustin T. Gibbs 
1646d720e6d5SJustin T. Gibbs 		seglim = 0;
1647d720e6d5SJustin T. Gibbs 		while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) {
1648d720e6d5SJustin T. Gibbs 			crq->req_dataseg[seglim].ds_base =
1649d720e6d5SJustin T. Gibbs 			    dm_segs->ds_addr;
1650d720e6d5SJustin T. Gibbs 			crq->req_dataseg[seglim].ds_count =
1651d720e6d5SJustin T. Gibbs 			    dm_segs->ds_len;
1652d720e6d5SJustin T. Gibbs #if	0
16536e5c5328SMatt Jacob 			device_printf(mp->isp->isp_dev,
16546e5c5328SMatt Jacob 			    "seg%d[%d] cnt 0x%x paddr 0x%08x\n",
16556e5c5328SMatt Jacob 			    rq->req_header.rqs_entry_count-1,
1656d720e6d5SJustin T. Gibbs 			    seglim, crq->req_dataseg[seglim].ds_count,
1657d720e6d5SJustin T. Gibbs 			    crq->req_dataseg[seglim].ds_base);
1658d720e6d5SJustin T. Gibbs #endif
1659d720e6d5SJustin T. Gibbs 			rq->req_seg_count++;
1660d720e6d5SJustin T. Gibbs 			dm_segs++;
1661d720e6d5SJustin T. Gibbs 			seglim++;
1662d720e6d5SJustin T. Gibbs 			datalen -= dm_segs->ds_len;
1663d720e6d5SJustin T. Gibbs 		}
1664d720e6d5SJustin T. Gibbs 	}
1665d720e6d5SJustin T. Gibbs }
1666d720e6d5SJustin T. Gibbs 
1667d720e6d5SJustin T. Gibbs static int
16689e11e5beSMatt Jacob isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq,
16699637d68cSMatt Jacob 	u_int16_t *iptrp, u_int16_t optr)
1670d720e6d5SJustin T. Gibbs {
1671d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
16720a5f7e8bSMatt Jacob 	bus_dmamap_t *dp = NULL;
1673d720e6d5SJustin T. Gibbs 	mush_t mush, *mp;
16749e11e5beSMatt Jacob 	void (*eptr) __P((void *, bus_dma_segment_t *, int, int));
1675d720e6d5SJustin T. Gibbs 
167665b024e1SMatt Jacob #ifdef	ISP_TARGET_MODE
167765b024e1SMatt Jacob 	if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) {
167865b024e1SMatt Jacob 		if (IS_FC(isp)) {
167905fbcbb0SMatt Jacob 			eptr = tdma_mkfc;
168065b024e1SMatt Jacob 		} else {
168105fbcbb0SMatt Jacob 			eptr = tdma_mk;
168265b024e1SMatt Jacob 		}
168305fbcbb0SMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE ||
168405fbcbb0SMatt Jacob 		    (csio->dxfer_len == 0)) {
168565b024e1SMatt Jacob 			rq->req_seg_count = 1;
168665b024e1SMatt Jacob 			mp = &mush;
168765b024e1SMatt Jacob 			mp->isp = isp;
168865b024e1SMatt Jacob 			mp->cmd_token = csio;
168965b024e1SMatt Jacob 			mp->rq = rq;
169065b024e1SMatt Jacob 			mp->iptrp = iptrp;
169165b024e1SMatt Jacob 			mp->optr = optr;
169265b024e1SMatt Jacob 			mp->error = 0;
169365b024e1SMatt Jacob 			(*eptr)(mp, NULL, 0, 0);
169465b024e1SMatt Jacob 			goto exit;
169565b024e1SMatt Jacob 		}
169665b024e1SMatt Jacob 	} else
169765b024e1SMatt Jacob #endif
169865b024e1SMatt Jacob 	eptr = dma2;
169965b024e1SMatt Jacob 
170042426921SMatt Jacob 	/*
170142426921SMatt Jacob 	 * NB: if we need to do request queue entry swizzling,
170242426921SMatt Jacob 	 * NB: this is where it would need to be done for cmds
170342426921SMatt Jacob 	 * NB: that move no data. For commands that move data,
170442426921SMatt Jacob 	 * NB: swizzling would take place in those functions.
170542426921SMatt Jacob 	 */
170605fbcbb0SMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE ||
170705fbcbb0SMatt Jacob 	    (csio->dxfer_len == 0)) {
170842426921SMatt Jacob 		rq->req_seg_count = 1;
170942426921SMatt Jacob 		return (CMD_QUEUED);
171042426921SMatt Jacob 	}
171142426921SMatt Jacob 
1712d720e6d5SJustin T. Gibbs 	/*
1713d720e6d5SJustin T. Gibbs 	 * Do a virtual grapevine step to collect info for
17144873663cSMatt Jacob 	 * the callback dma allocation that we have to use...
1715d720e6d5SJustin T. Gibbs 	 */
1716d720e6d5SJustin T. Gibbs 	mp = &mush;
1717d720e6d5SJustin T. Gibbs 	mp->isp = isp;
17189e11e5beSMatt Jacob 	mp->cmd_token = csio;
1719d720e6d5SJustin T. Gibbs 	mp->rq = rq;
1720d720e6d5SJustin T. Gibbs 	mp->iptrp = iptrp;
1721d720e6d5SJustin T. Gibbs 	mp->optr = optr;
1722d720e6d5SJustin T. Gibbs 	mp->error = 0;
1723d720e6d5SJustin T. Gibbs 
17249e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
17259e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) {
17264873663cSMatt Jacob 			int error, s;
1727469b6b9eSMatt Jacob 			dp = &pci->dmaps[isp_handle_index(rq->req_handle)];
1728d720e6d5SJustin T. Gibbs 			s = splsoftvm();
1729d720e6d5SJustin T. Gibbs 			error = bus_dmamap_load(pci->parent_dmat, *dp,
17309e11e5beSMatt Jacob 			    csio->data_ptr, csio->dxfer_len, eptr, mp, 0);
1731d720e6d5SJustin T. Gibbs 			if (error == EINPROGRESS) {
1732d720e6d5SJustin T. Gibbs 				bus_dmamap_unload(pci->parent_dmat, *dp);
1733d720e6d5SJustin T. Gibbs 				mp->error = EINVAL;
1734f7dddf8aSMatt Jacob 				isp_prt(isp, ISP_LOGERR,
1735f7dddf8aSMatt Jacob 				    "deferred dma allocation not supported");
1736d720e6d5SJustin T. Gibbs 			} else if (error && mp->error == 0) {
17370a5f7e8bSMatt Jacob #ifdef	DIAGNOSTIC
17386e5c5328SMatt Jacob 				isp_prt(isp, ISP_LOGERR,
17396e5c5328SMatt Jacob 				    "error %d in dma mapping code", error);
17400a5f7e8bSMatt Jacob #endif
1741d720e6d5SJustin T. Gibbs 				mp->error = error;
1742d720e6d5SJustin T. Gibbs 			}
17434873663cSMatt Jacob 			splx(s);
1744d720e6d5SJustin T. Gibbs 		} else {
1745d720e6d5SJustin T. Gibbs 			/* Pointer to physical buffer */
1746d720e6d5SJustin T. Gibbs 			struct bus_dma_segment seg;
1747d720e6d5SJustin T. Gibbs 			seg.ds_addr = (bus_addr_t)csio->data_ptr;
1748d720e6d5SJustin T. Gibbs 			seg.ds_len = csio->dxfer_len;
17499e11e5beSMatt Jacob 			(*eptr)(mp, &seg, 1, 0);
1750d720e6d5SJustin T. Gibbs 		}
1751d720e6d5SJustin T. Gibbs 	} else {
1752d720e6d5SJustin T. Gibbs 		struct bus_dma_segment *segs;
1753d720e6d5SJustin T. Gibbs 
17549e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) {
1755f7dddf8aSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
1756f7dddf8aSMatt Jacob 			    "Physical segment pointers unsupported");
1757d720e6d5SJustin T. Gibbs 			mp->error = EINVAL;
17589e11e5beSMatt Jacob 		} else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) {
1759f7dddf8aSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
1760f7dddf8aSMatt Jacob 			    "Virtual segment addresses unsupported");
1761d720e6d5SJustin T. Gibbs 			mp->error = EINVAL;
1762d720e6d5SJustin T. Gibbs 		} else {
1763d720e6d5SJustin T. Gibbs 			/* Just use the segments provided */
1764d720e6d5SJustin T. Gibbs 			segs = (struct bus_dma_segment *) csio->data_ptr;
17659e11e5beSMatt Jacob 			(*eptr)(mp, segs, csio->sglist_cnt, 0);
1766d720e6d5SJustin T. Gibbs 		}
1767d720e6d5SJustin T. Gibbs 	}
1768003a310fSMatt Jacob #ifdef	ISP_TARGET_MODE
176965b024e1SMatt Jacob exit:
1770003a310fSMatt Jacob #endif
1771d720e6d5SJustin T. Gibbs 	if (mp->error) {
17724873663cSMatt Jacob 		int retval = CMD_COMPLETE;
17734873663cSMatt Jacob 		if (mp->error == MUSHERR_NOQENTRIES) {
17744873663cSMatt Jacob 			retval = CMD_EAGAIN;
17754873663cSMatt Jacob 		} else if (mp->error == EFBIG) {
17760a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_REQ_TOO_BIG);
1777d720e6d5SJustin T. Gibbs 		} else if (mp->error == EINVAL) {
17780a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_REQ_INVALID);
1779d720e6d5SJustin T. Gibbs 		} else {
17800a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_UNREC_HBA_ERROR);
1781d720e6d5SJustin T. Gibbs 		}
17824873663cSMatt Jacob 		return (retval);
17834873663cSMatt Jacob 	} else {
17840a5f7e8bSMatt Jacob 		/*
17850a5f7e8bSMatt Jacob 		 * Check to see if we weren't cancelled while sleeping on
17860a5f7e8bSMatt Jacob 		 * getting DMA resources...
17870a5f7e8bSMatt Jacob 		 */
17889e11e5beSMatt Jacob 		if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
17890a5f7e8bSMatt Jacob 			if (dp) {
17900a5f7e8bSMatt Jacob 				bus_dmamap_unload(pci->parent_dmat, *dp);
17910a5f7e8bSMatt Jacob 			}
17920a5f7e8bSMatt Jacob 			return (CMD_COMPLETE);
17930a5f7e8bSMatt Jacob 		}
17944873663cSMatt Jacob 		return (CMD_QUEUED);
1795d720e6d5SJustin T. Gibbs 	}
1796d720e6d5SJustin T. Gibbs }
1797d720e6d5SJustin T. Gibbs 
1798d720e6d5SJustin T. Gibbs static void
1799d8d5f2adSMatt Jacob isp_pci_dmateardown(struct ispsoftc *isp, XS_T *xs, u_int16_t handle)
1800d720e6d5SJustin T. Gibbs {
1801d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
1802469b6b9eSMatt Jacob 	bus_dmamap_t *dp = &pci->dmaps[isp_handle_index(handle)];
1803a95ae193SMatt Jacob 	if ((xs->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1804d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTREAD);
1805d720e6d5SJustin T. Gibbs 	} else {
1806d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTWRITE);
1807d720e6d5SJustin T. Gibbs 	}
1808d720e6d5SJustin T. Gibbs 	bus_dmamap_unload(pci->parent_dmat, *dp);
1809d720e6d5SJustin T. Gibbs }
1810d720e6d5SJustin T. Gibbs 
181165adb54cSMatt Jacob 
181265adb54cSMatt Jacob static void
181317e318c6SMatt Jacob isp_pci_reset1(struct ispsoftc *isp)
181465adb54cSMatt Jacob {
181565adb54cSMatt Jacob 	/* Make sure the BIOS is disabled */
181665adb54cSMatt Jacob 	isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS);
1817469b6b9eSMatt Jacob 	/* and enable interrupts */
1818469b6b9eSMatt Jacob 	ENABLE_INTS(isp);
181965adb54cSMatt Jacob }
182065adb54cSMatt Jacob 
182165adb54cSMatt Jacob static void
1822d02373f1SMatt Jacob isp_pci_dumpregs(struct ispsoftc *isp, const char *msg)
182365adb54cSMatt Jacob {
182465adb54cSMatt Jacob 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
1825d02373f1SMatt Jacob 	if (msg)
18266e5c5328SMatt Jacob 		printf("%s: %s\n", device_get_nameunit(isp->isp_dev), msg);
18276e5c5328SMatt Jacob 	else
18286e5c5328SMatt Jacob 		printf("%s:\n", device_get_nameunit(isp->isp_dev));
1829d02373f1SMatt Jacob 	if (IS_SCSI(isp))
1830d02373f1SMatt Jacob 		printf("    biu_conf1=%x", ISP_READ(isp, BIU_CONF1));
1831d02373f1SMatt Jacob 	else
1832d02373f1SMatt Jacob 		printf("    biu_csr=%x", ISP_READ(isp, BIU2100_CSR));
1833d02373f1SMatt Jacob 	printf(" biu_icr=%x biu_isr=%x biu_sema=%x ", ISP_READ(isp, BIU_ICR),
1834d02373f1SMatt Jacob 	    ISP_READ(isp, BIU_ISR), ISP_READ(isp, BIU_SEMA));
1835d02373f1SMatt Jacob 	printf("risc_hccr=%x\n", ISP_READ(isp, HCCR));
1836d02373f1SMatt Jacob 
1837d02373f1SMatt Jacob 
1838d02373f1SMatt Jacob 	if (IS_SCSI(isp)) {
1839d02373f1SMatt Jacob 		ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE);
1840d02373f1SMatt Jacob 		printf("    cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n",
1841d02373f1SMatt Jacob 			ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS),
1842d02373f1SMatt Jacob 			ISP_READ(isp, CDMA_FIFO_STS));
1843d02373f1SMatt Jacob 		printf("    ddma_conf=%x ddma_sts=%x ddma_fifostat=%x\n",
1844d02373f1SMatt Jacob 			ISP_READ(isp, DDMA_CONF), ISP_READ(isp, DDMA_STATUS),
1845d02373f1SMatt Jacob 			ISP_READ(isp, DDMA_FIFO_STS));
1846d02373f1SMatt Jacob 		printf("    sxp_int=%x sxp_gross=%x sxp(scsi_ctrl)=%x\n",
1847d02373f1SMatt Jacob 			ISP_READ(isp, SXP_INTERRUPT),
1848d02373f1SMatt Jacob 			ISP_READ(isp, SXP_GROSS_ERR),
1849d02373f1SMatt Jacob 			ISP_READ(isp, SXP_PINS_CTRL));
1850d02373f1SMatt Jacob 		ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE);
1851d02373f1SMatt Jacob 	}
1852d02373f1SMatt Jacob 	printf("    mbox regs: %x %x %x %x %x\n",
1853d02373f1SMatt Jacob 	    ISP_READ(isp, OUTMAILBOX0), ISP_READ(isp, OUTMAILBOX1),
1854d02373f1SMatt Jacob 	    ISP_READ(isp, OUTMAILBOX2), ISP_READ(isp, OUTMAILBOX3),
1855d02373f1SMatt Jacob 	    ISP_READ(isp, OUTMAILBOX4));
1856d02373f1SMatt Jacob 	printf("    PCI Status Command/Status=%x\n",
1857960f6939SMatt Jacob 	    pci_read_config(pci->pci_dev, PCIR_COMMAND, 1));
185865adb54cSMatt Jacob }
1859