xref: /freebsd/sys/dev/isp/isp_pci.c (revision 05fbcbb000a2972d1304bf5930baf7436dac4611)
1c3aac50fSPeter Wemm /* $FreeBSD$ */
265adb54cSMatt Jacob /*
365adb54cSMatt Jacob  * PCI specific probe and attach routines for Qlogic ISP SCSI adapters.
465adb54cSMatt Jacob  * FreeBSD Version.
565adb54cSMatt Jacob  *
665adb54cSMatt Jacob  *---------------------------------------
7222bb542SMatt Jacob  * Copyright (c) 1997, 1998, 1999 by Matthew Jacob
865adb54cSMatt Jacob  * NASA/Ames Research Center
965adb54cSMatt Jacob  * All rights reserved.
1065adb54cSMatt Jacob  *---------------------------------------
1165adb54cSMatt Jacob  *
1265adb54cSMatt Jacob  * Redistribution and use in source and binary forms, with or without
1365adb54cSMatt Jacob  * modification, are permitted provided that the following conditions
1465adb54cSMatt Jacob  * are met:
1565adb54cSMatt Jacob  * 1. Redistributions of source code must retain the above copyright
1665adb54cSMatt Jacob  *    notice immediately at the beginning of the file, without modification,
1765adb54cSMatt Jacob  *    this list of conditions, and the following disclaimer.
1865adb54cSMatt Jacob  * 2. Redistributions in binary form must reproduce the above copyright
1965adb54cSMatt Jacob  *    notice, this list of conditions and the following disclaimer in the
2065adb54cSMatt Jacob  *    documentation and/or other materials provided with the distribution.
2165adb54cSMatt Jacob  * 3. The name of the author may not be used to endorse or promote products
2265adb54cSMatt Jacob  *    derived from this software without specific prior written permission.
2365adb54cSMatt Jacob  *
2465adb54cSMatt Jacob  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2565adb54cSMatt Jacob  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2665adb54cSMatt Jacob  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2765adb54cSMatt Jacob  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2865adb54cSMatt Jacob  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2965adb54cSMatt Jacob  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3065adb54cSMatt Jacob  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3165adb54cSMatt Jacob  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3265adb54cSMatt Jacob  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3365adb54cSMatt Jacob  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3465adb54cSMatt Jacob  * SUCH DAMAGE.
3565adb54cSMatt Jacob  */
36d720e6d5SJustin T. Gibbs 
37960f6939SMatt Jacob #include <sys/param.h>
38960f6939SMatt Jacob #include <sys/systm.h>
39960f6939SMatt Jacob #include <sys/kernel.h>
40960f6939SMatt Jacob #include <sys/module.h>
41960f6939SMatt Jacob #include <sys/bus.h>
4265adb54cSMatt Jacob 
4365adb54cSMatt Jacob #include <pci/pcireg.h>
4465adb54cSMatt Jacob #include <pci/pcivar.h>
4565adb54cSMatt Jacob 
46d720e6d5SJustin T. Gibbs #include <machine/bus_memio.h>
47d720e6d5SJustin T. Gibbs #include <machine/bus_pio.h>
48d720e6d5SJustin T. Gibbs #include <machine/bus.h>
49960f6939SMatt Jacob #include <machine/resource.h>
50960f6939SMatt Jacob #include <machine/clock.h>
51960f6939SMatt Jacob #include <sys/rman.h>
52960f6939SMatt Jacob #include <sys/malloc.h>
53960f6939SMatt Jacob 
54960f6939SMatt Jacob #include <dev/isp/isp_freebsd.h>
55d59bd469SMatt Jacob 
5665adb54cSMatt Jacob static u_int16_t isp_pci_rd_reg __P((struct ispsoftc *, int));
5765adb54cSMatt Jacob static void isp_pci_wr_reg __P((struct ispsoftc *, int, u_int16_t));
58d59bd469SMatt Jacob static u_int16_t isp_pci_rd_reg_1080 __P((struct ispsoftc *, int));
59d59bd469SMatt Jacob static void isp_pci_wr_reg_1080 __P((struct ispsoftc *, int, u_int16_t));
6065adb54cSMatt Jacob static int isp_pci_mbxdma __P((struct ispsoftc *));
6165adb54cSMatt Jacob static int isp_pci_dmasetup __P((struct ispsoftc *, ISP_SCSI_XFER_T *,
629637d68cSMatt Jacob 	ispreq_t *, u_int16_t *, u_int16_t));
63d720e6d5SJustin T. Gibbs static void
64d720e6d5SJustin T. Gibbs isp_pci_dmateardown __P((struct ispsoftc *, ISP_SCSI_XFER_T *, u_int32_t));
6565adb54cSMatt Jacob 
6665adb54cSMatt Jacob static void isp_pci_reset1 __P((struct ispsoftc *));
6765adb54cSMatt Jacob static void isp_pci_dumpregs __P((struct ispsoftc *));
6865adb54cSMatt Jacob 
69fed92c47SMatt Jacob #ifndef	ISP_CODE_ORG
70fed92c47SMatt Jacob #define	ISP_CODE_ORG		0x1000
71fed92c47SMatt Jacob #endif
72fed92c47SMatt Jacob 
7365adb54cSMatt Jacob static struct ispmdvec mdvec = {
7465adb54cSMatt Jacob 	isp_pci_rd_reg,
7565adb54cSMatt Jacob 	isp_pci_wr_reg,
7665adb54cSMatt Jacob 	isp_pci_mbxdma,
7765adb54cSMatt Jacob 	isp_pci_dmasetup,
78d720e6d5SJustin T. Gibbs 	isp_pci_dmateardown,
7965adb54cSMatt Jacob 	NULL,
8065adb54cSMatt Jacob 	isp_pci_reset1,
8165adb54cSMatt Jacob 	isp_pci_dumpregs,
8256aef503SMatt Jacob 	NULL,
83fed92c47SMatt Jacob 	0,
8465adb54cSMatt Jacob 	ISP_CODE_ORG,
85a95ae193SMatt Jacob 	0,
86285e230dSMatt Jacob 	BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64,
87d720e6d5SJustin T. Gibbs 	0
8865adb54cSMatt Jacob };
8965adb54cSMatt Jacob 
90d59bd469SMatt Jacob static struct ispmdvec mdvec_1080 = {
91d59bd469SMatt Jacob 	isp_pci_rd_reg_1080,
92d59bd469SMatt Jacob 	isp_pci_wr_reg_1080,
93d59bd469SMatt Jacob 	isp_pci_mbxdma,
94d59bd469SMatt Jacob 	isp_pci_dmasetup,
95d59bd469SMatt Jacob 	isp_pci_dmateardown,
96d59bd469SMatt Jacob 	NULL,
97d59bd469SMatt Jacob 	isp_pci_reset1,
98d59bd469SMatt Jacob 	isp_pci_dumpregs,
9956aef503SMatt Jacob 	NULL,
100fed92c47SMatt Jacob 	0,
101fed92c47SMatt Jacob 	ISP_CODE_ORG,
102a95ae193SMatt Jacob 	0,
103d59bd469SMatt Jacob 	BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64,
104d59bd469SMatt Jacob 	0
105d59bd469SMatt Jacob };
106d59bd469SMatt Jacob 
107960f6939SMatt Jacob static struct ispmdvec mdvec_12160 = {
108960f6939SMatt Jacob 	isp_pci_rd_reg_1080,
109960f6939SMatt Jacob 	isp_pci_wr_reg_1080,
110960f6939SMatt Jacob 	isp_pci_mbxdma,
111960f6939SMatt Jacob 	isp_pci_dmasetup,
112960f6939SMatt Jacob 	isp_pci_dmateardown,
113960f6939SMatt Jacob 	NULL,
114960f6939SMatt Jacob 	isp_pci_reset1,
115960f6939SMatt Jacob 	isp_pci_dumpregs,
11656aef503SMatt Jacob 	NULL,
117960f6939SMatt Jacob 	0,
11856aef503SMatt Jacob 	NULL,
119960f6939SMatt Jacob 	0,
120960f6939SMatt Jacob 	BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64,
121960f6939SMatt Jacob 	0
122960f6939SMatt Jacob };
123960f6939SMatt Jacob 
12465adb54cSMatt Jacob static struct ispmdvec mdvec_2100 = {
12565adb54cSMatt Jacob 	isp_pci_rd_reg,
12665adb54cSMatt Jacob 	isp_pci_wr_reg,
12765adb54cSMatt Jacob 	isp_pci_mbxdma,
12865adb54cSMatt Jacob 	isp_pci_dmasetup,
129d720e6d5SJustin T. Gibbs 	isp_pci_dmateardown,
13065adb54cSMatt Jacob 	NULL,
13165adb54cSMatt Jacob 	isp_pci_reset1,
13265adb54cSMatt Jacob 	isp_pci_dumpregs,
13356aef503SMatt Jacob 	NULL,
134fed92c47SMatt Jacob 	0,
135fed92c47SMatt Jacob 	ISP_CODE_ORG,
136a95ae193SMatt Jacob 	0,
137a95ae193SMatt Jacob 	0,
138d720e6d5SJustin T. Gibbs 	0
13965adb54cSMatt Jacob };
140222bb542SMatt Jacob 
141222bb542SMatt Jacob static struct ispmdvec mdvec_2200 = {
142222bb542SMatt Jacob 	isp_pci_rd_reg,
143222bb542SMatt Jacob 	isp_pci_wr_reg,
144222bb542SMatt Jacob 	isp_pci_mbxdma,
145222bb542SMatt Jacob 	isp_pci_dmasetup,
146222bb542SMatt Jacob 	isp_pci_dmateardown,
147222bb542SMatt Jacob 	NULL,
148222bb542SMatt Jacob 	isp_pci_reset1,
149222bb542SMatt Jacob 	isp_pci_dumpregs,
15056aef503SMatt Jacob 	NULL,
151fed92c47SMatt Jacob 	0,
152fed92c47SMatt Jacob 	ISP_CODE_ORG,
153a95ae193SMatt Jacob 	0,
154222bb542SMatt Jacob 	0,
155222bb542SMatt Jacob 	0
156222bb542SMatt Jacob };
157d951bbcaSMatt Jacob 
15865adb54cSMatt Jacob #ifndef	PCIM_CMD_INVEN
15965adb54cSMatt Jacob #define	PCIM_CMD_INVEN			0x10
16065adb54cSMatt Jacob #endif
16165adb54cSMatt Jacob #ifndef	PCIM_CMD_BUSMASTEREN
16265adb54cSMatt Jacob #define	PCIM_CMD_BUSMASTEREN		0x0004
16365adb54cSMatt Jacob #endif
164d951bbcaSMatt Jacob #ifndef	PCIM_CMD_PERRESPEN
165d951bbcaSMatt Jacob #define	PCIM_CMD_PERRESPEN		0x0040
166d951bbcaSMatt Jacob #endif
167d951bbcaSMatt Jacob #ifndef	PCIM_CMD_SEREN
168d951bbcaSMatt Jacob #define	PCIM_CMD_SEREN			0x0100
169d951bbcaSMatt Jacob #endif
170d951bbcaSMatt Jacob 
171d951bbcaSMatt Jacob #ifndef	PCIR_COMMAND
172d951bbcaSMatt Jacob #define	PCIR_COMMAND			0x04
173d951bbcaSMatt Jacob #endif
174d951bbcaSMatt Jacob 
175d951bbcaSMatt Jacob #ifndef	PCIR_CACHELNSZ
176d951bbcaSMatt Jacob #define	PCIR_CACHELNSZ			0x0c
177d951bbcaSMatt Jacob #endif
178d951bbcaSMatt Jacob 
179d951bbcaSMatt Jacob #ifndef	PCIR_LATTIMER
180d951bbcaSMatt Jacob #define	PCIR_LATTIMER			0x0d
181d951bbcaSMatt Jacob #endif
182d951bbcaSMatt Jacob 
183ab6d0040SMatt Jacob #ifndef	PCIR_ROMADDR
184ab6d0040SMatt Jacob #define	PCIR_ROMADDR			0x30
185ab6d0040SMatt Jacob #endif
186ab6d0040SMatt Jacob 
18765adb54cSMatt Jacob #ifndef	PCI_VENDOR_QLOGIC
18865adb54cSMatt Jacob #define	PCI_VENDOR_QLOGIC		0x1077
18965adb54cSMatt Jacob #endif
19065adb54cSMatt Jacob 
19165adb54cSMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1020
19265adb54cSMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1020	0x1020
19365adb54cSMatt Jacob #endif
19465adb54cSMatt Jacob 
195d59bd469SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1080
196d59bd469SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1080	0x1080
197d59bd469SMatt Jacob #endif
198d59bd469SMatt Jacob 
199960f6939SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP12160
200960f6939SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP12160	0x1216
201960f6939SMatt Jacob #endif
202960f6939SMatt Jacob 
203d59bd469SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1240
204d59bd469SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1240	0x1240
205d59bd469SMatt Jacob #endif
20665adb54cSMatt Jacob 
20722e1dc85SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1280
20822e1dc85SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1280	0x1280
20922e1dc85SMatt Jacob #endif
21022e1dc85SMatt Jacob 
21165adb54cSMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP2100
21265adb54cSMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2100	0x2100
21365adb54cSMatt Jacob #endif
21465adb54cSMatt Jacob 
215222bb542SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP2200
216222bb542SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2200	0x2200
217222bb542SMatt Jacob #endif
218222bb542SMatt Jacob 
21956aef503SMatt Jacob #define	PCI_QLOGIC_ISP1020	\
22056aef503SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC)
221d59bd469SMatt Jacob 
222d59bd469SMatt Jacob #define	PCI_QLOGIC_ISP1080	\
223d59bd469SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC)
224d59bd469SMatt Jacob 
225960f6939SMatt Jacob #define	PCI_QLOGIC_ISP12160	\
226960f6939SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP12160 << 16) | PCI_VENDOR_QLOGIC)
227960f6939SMatt Jacob 
228d59bd469SMatt Jacob #define	PCI_QLOGIC_ISP1240	\
229d59bd469SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC)
230d59bd469SMatt Jacob 
23122e1dc85SMatt Jacob #define	PCI_QLOGIC_ISP1280	\
23222e1dc85SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1280 << 16) | PCI_VENDOR_QLOGIC)
23322e1dc85SMatt Jacob 
23465adb54cSMatt Jacob #define	PCI_QLOGIC_ISP2100	\
23565adb54cSMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC)
23665adb54cSMatt Jacob 
237222bb542SMatt Jacob #define	PCI_QLOGIC_ISP2200	\
238222bb542SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2200 << 16) | PCI_VENDOR_QLOGIC)
239222bb542SMatt Jacob 
24065adb54cSMatt Jacob #define	IO_MAP_REG	0x10
24165adb54cSMatt Jacob #define	MEM_MAP_REG	0x14
24265adb54cSMatt Jacob 
243d951bbcaSMatt Jacob #define	PCI_DFLT_LTNCY	0x40
244d951bbcaSMatt Jacob #define	PCI_DFLT_LNSZ	0x10
24565adb54cSMatt Jacob 
246960f6939SMatt Jacob static int isp_pci_probe (device_t);
247960f6939SMatt Jacob static int isp_pci_attach (device_t);
24865adb54cSMatt Jacob 
249d720e6d5SJustin T. Gibbs /* This distinguishing define is not right, but it does work */
250a185f9b1SMatt Jacob #ifdef __alpha__
251a185f9b1SMatt Jacob #define IO_SPACE_MAPPING	ALPHA_BUS_SPACE_IO
252a185f9b1SMatt Jacob #define MEM_SPACE_MAPPING	ALPHA_BUS_SPACE_MEM
253a185f9b1SMatt Jacob #else
254a185f9b1SMatt Jacob #define IO_SPACE_MAPPING	I386_BUS_SPACE_IO
255a185f9b1SMatt Jacob #define MEM_SPACE_MAPPING	I386_BUS_SPACE_MEM
256a185f9b1SMatt Jacob #endif
25765adb54cSMatt Jacob 
25865adb54cSMatt Jacob struct isp_pcisoftc {
25965adb54cSMatt Jacob 	struct ispsoftc			pci_isp;
260960f6939SMatt Jacob 	device_t			pci_dev;
261960f6939SMatt Jacob 	struct resource *		pci_reg;
26265adb54cSMatt Jacob 	bus_space_tag_t			pci_st;
26365adb54cSMatt Jacob 	bus_space_handle_t		pci_sh;
264960f6939SMatt Jacob 	void *				ih;
265d59bd469SMatt Jacob 	int16_t				pci_poff[_NREG_BLKS];
266d720e6d5SJustin T. Gibbs 	bus_dma_tag_t			parent_dmat;
267d720e6d5SJustin T. Gibbs 	bus_dma_tag_t			cntrol_dmat;
268d720e6d5SJustin T. Gibbs 	bus_dmamap_t			cntrol_dmap;
269a95ae193SMatt Jacob 	bus_dmamap_t			*dmaps;
27065adb54cSMatt Jacob };
27156aef503SMatt Jacob ispfwfunc *isp_get_firmware_p = NULL;
27265adb54cSMatt Jacob 
273960f6939SMatt Jacob static device_method_t isp_pci_methods[] = {
274960f6939SMatt Jacob 	/* Device interface */
275960f6939SMatt Jacob 	DEVMETHOD(device_probe,		isp_pci_probe),
276960f6939SMatt Jacob 	DEVMETHOD(device_attach,	isp_pci_attach),
277960f6939SMatt Jacob 	{ 0, 0 }
27865adb54cSMatt Jacob };
27965adb54cSMatt Jacob 
280960f6939SMatt Jacob static driver_t isp_pci_driver = {
281960f6939SMatt Jacob 	"isp", isp_pci_methods, sizeof (struct isp_pcisoftc)
282960f6939SMatt Jacob };
283960f6939SMatt Jacob static devclass_t isp_devclass;
284960f6939SMatt Jacob DRIVER_MODULE(isp, pci, isp_pci_driver, isp_devclass, 0, 0);
28556aef503SMatt Jacob MODULE_VERSION(isp, 1);
28665adb54cSMatt Jacob 
287960f6939SMatt Jacob static int
288960f6939SMatt Jacob isp_pci_probe(device_t dev)
28965adb54cSMatt Jacob {
290960f6939SMatt Jacob         switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) {
29156aef503SMatt Jacob 	case PCI_QLOGIC_ISP1020:
292960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1020/1040 PCI SCSI Adapter");
29365adb54cSMatt Jacob 		break;
294d59bd469SMatt Jacob 	case PCI_QLOGIC_ISP1080:
295960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1080 PCI SCSI Adapter");
296c6608df3SMatt Jacob 		break;
297c6608df3SMatt Jacob 	case PCI_QLOGIC_ISP1240:
298960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1240 PCI SCSI Adapter");
299d59bd469SMatt Jacob 		break;
30022e1dc85SMatt Jacob 	case PCI_QLOGIC_ISP1280:
301960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1280 PCI SCSI Adapter");
302960f6939SMatt Jacob 		break;
303960f6939SMatt Jacob 	case PCI_QLOGIC_ISP12160:
304960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 12160 PCI SCSI Adapter");
30522e1dc85SMatt Jacob 		break;
30665adb54cSMatt Jacob 	case PCI_QLOGIC_ISP2100:
307960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2100 PCI FC-AL Adapter");
30865adb54cSMatt Jacob 		break;
3095542fe4bSMatt Jacob 	case PCI_QLOGIC_ISP2200:
310960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2200 PCI FC-AL Adapter");
3115542fe4bSMatt Jacob 		break;
31265adb54cSMatt Jacob 	default:
313960f6939SMatt Jacob 		return (ENXIO);
31465adb54cSMatt Jacob 	}
315960f6939SMatt Jacob 	if (device_get_unit(dev) == 0) {
316a95ae193SMatt Jacob 		CFGPRINTF("Qlogic ISP Driver, FreeBSD Version %d.%d, "
317a95ae193SMatt Jacob 		    "Core Version %d.%d\n",
318d720e6d5SJustin T. Gibbs 		    ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR,
319d720e6d5SJustin T. Gibbs 		    ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR);
32065adb54cSMatt Jacob 	}
32156aef503SMatt Jacob 	/*
32256aef503SMatt Jacob 	 * XXXX: Here is where we might load the f/w module
32356aef503SMatt Jacob 	 * XXXX: (or increase a reference count to it).
32456aef503SMatt Jacob 	 */
325960f6939SMatt Jacob 	return (0);
32665adb54cSMatt Jacob }
32765adb54cSMatt Jacob 
328960f6939SMatt Jacob static int
329960f6939SMatt Jacob isp_pci_attach(device_t dev)
33065adb54cSMatt Jacob {
331960f6939SMatt Jacob 	struct resource *regs, *irq;
332469b6b9eSMatt Jacob 	int unit, bitmap, rtp, rgd, iqd, m1, m2, s;
333960f6939SMatt Jacob 	u_int32_t data, cmd, linesz, psize, basetype;
33465adb54cSMatt Jacob 	struct isp_pcisoftc *pcs;
33565adb54cSMatt Jacob 	struct ispsoftc *isp;
336c6608df3SMatt Jacob 	struct ispmdvec *mdvp;
337222bb542SMatt Jacob 	bus_size_t lim;
33865adb54cSMatt Jacob 
339222bb542SMatt Jacob 	/*
3409ba86737SMatt Jacob 	 * Figure out if we're supposed to skip this one.
3419ba86737SMatt Jacob 	 */
342960f6939SMatt Jacob 	unit = device_get_unit(dev);
3439ba86737SMatt Jacob 	if (getenv_int("isp_disable", &bitmap)) {
3449ba86737SMatt Jacob 		if (bitmap & (1 << unit)) {
345960f6939SMatt Jacob 			device_printf(dev, "not configuring\n");
346960f6939SMatt Jacob 			return (ENODEV);
3479ba86737SMatt Jacob 		}
3489ba86737SMatt Jacob 	}
3499ba86737SMatt Jacob 
350960f6939SMatt Jacob 	pcs = malloc(sizeof (struct isp_pcisoftc), M_DEVBUF, M_NOWAIT);
351960f6939SMatt Jacob 	if (pcs == NULL) {
352960f6939SMatt Jacob 		device_printf(dev, "cannot allocate softc\n");
353960f6939SMatt Jacob 		return (ENOMEM);
354960f6939SMatt Jacob 	}
355960f6939SMatt Jacob 	bzero(pcs, sizeof (struct isp_pcisoftc));
356960f6939SMatt Jacob 
3579ba86737SMatt Jacob 	/*
358222bb542SMatt Jacob 	 * Figure out which we should try first - memory mapping or i/o mapping?
359222bb542SMatt Jacob 	 */
36056aef503SMatt Jacob #ifdef	__alpha__
361960f6939SMatt Jacob 	m1 = PCIM_CMD_MEMEN;
362960f6939SMatt Jacob 	m2 = PCIM_CMD_PORTEN;
363222bb542SMatt Jacob #else
364960f6939SMatt Jacob 	m1 = PCIM_CMD_PORTEN;
365960f6939SMatt Jacob 	m2 = PCIM_CMD_MEMEN;
366222bb542SMatt Jacob #endif
367222bb542SMatt Jacob 	bitmap = 0;
368222bb542SMatt Jacob 	if (getenv_int("isp_mem_map", &bitmap)) {
369960f6939SMatt Jacob 		if (bitmap & (1 << unit)) {
370960f6939SMatt Jacob 			m1 = PCIM_CMD_MEMEN;
371960f6939SMatt Jacob 			m2 = PCIM_CMD_PORTEN;
372960f6939SMatt Jacob 		}
373222bb542SMatt Jacob 	}
374222bb542SMatt Jacob 	bitmap = 0;
375222bb542SMatt Jacob 	if (getenv_int("isp_io_map", &bitmap)) {
376960f6939SMatt Jacob 		if (bitmap & (1 << unit)) {
377960f6939SMatt Jacob 			m1 = PCIM_CMD_PORTEN;
378960f6939SMatt Jacob 			m2 = PCIM_CMD_MEMEN;
379960f6939SMatt Jacob 		}
380222bb542SMatt Jacob 	}
381222bb542SMatt Jacob 
382ab6d0040SMatt Jacob 	linesz = PCI_DFLT_LNSZ;
383960f6939SMatt Jacob 	irq = regs = NULL;
384960f6939SMatt Jacob 	rgd = rtp = iqd = 0;
385960f6939SMatt Jacob 
386960f6939SMatt Jacob 	cmd = pci_read_config(dev, PCIR_COMMAND, 1);
387960f6939SMatt Jacob 	if (cmd & m1) {
388960f6939SMatt Jacob 		rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT;
389960f6939SMatt Jacob 		rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG;
390960f6939SMatt Jacob 		regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE);
39165adb54cSMatt Jacob 	}
392960f6939SMatt Jacob 	if (regs == NULL && (cmd & m2)) {
393960f6939SMatt Jacob 		rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT;
394960f6939SMatt Jacob 		rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG;
395960f6939SMatt Jacob 		regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE);
39665adb54cSMatt Jacob 	}
397960f6939SMatt Jacob 	if (regs == NULL) {
398960f6939SMatt Jacob 		device_printf(dev, "unable to map any ports\n");
399960f6939SMatt Jacob 		goto bad;
40065adb54cSMatt Jacob 	}
401222bb542SMatt Jacob 	if (bootverbose)
40265adb54cSMatt Jacob 		printf("isp%d: using %s space register mapping\n", unit,
403960f6939SMatt Jacob 		    (rgd == IO_MAP_REG)? "I/O" : "Memory");
404960f6939SMatt Jacob 	pcs->pci_dev = dev;
405960f6939SMatt Jacob 	pcs->pci_reg = regs;
406960f6939SMatt Jacob 	pcs->pci_st = rman_get_bustag(regs);
407960f6939SMatt Jacob 	pcs->pci_sh = rman_get_bushandle(regs);
40865adb54cSMatt Jacob 
409d59bd469SMatt Jacob 	pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF;
410d59bd469SMatt Jacob 	pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF;
411d59bd469SMatt Jacob 	pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF;
412d59bd469SMatt Jacob 	pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF;
413d59bd469SMatt Jacob 	pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF;
414c6608df3SMatt Jacob 	mdvp = &mdvec;
415c6608df3SMatt Jacob 	basetype = ISP_HA_SCSI_UNKNOWN;
416c6608df3SMatt Jacob 	psize = sizeof (sdparam);
417222bb542SMatt Jacob 	lim = BUS_SPACE_MAXSIZE_32BIT;
41856aef503SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP1020) {
419c6608df3SMatt Jacob 		mdvp = &mdvec;
420c6608df3SMatt Jacob 		basetype = ISP_HA_SCSI_UNKNOWN;
421c6608df3SMatt Jacob 		psize = sizeof (sdparam);
422222bb542SMatt Jacob 		lim = BUS_SPACE_MAXSIZE_24BIT;
423d59bd469SMatt Jacob 	}
424960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP1080) {
425c6608df3SMatt Jacob 		mdvp = &mdvec_1080;
426c6608df3SMatt Jacob 		basetype = ISP_HA_SCSI_1080;
427c6608df3SMatt Jacob 		psize = sizeof (sdparam);
428c6608df3SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
429c6608df3SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
430c6608df3SMatt Jacob 	}
431960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP1240) {
432c6608df3SMatt Jacob 		mdvp = &mdvec_1080;
43322e1dc85SMatt Jacob 		basetype = ISP_HA_SCSI_1240;
43422e1dc85SMatt Jacob 		psize = 2 * sizeof (sdparam);
43522e1dc85SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
43622e1dc85SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
43722e1dc85SMatt Jacob 	}
438960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP1280) {
43922e1dc85SMatt Jacob 		mdvp = &mdvec_1080;
44022e1dc85SMatt Jacob 		basetype = ISP_HA_SCSI_1280;
441c6608df3SMatt Jacob 		psize = 2 * sizeof (sdparam);
442d59bd469SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
443d59bd469SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
444d59bd469SMatt Jacob 	}
445960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP12160) {
446960f6939SMatt Jacob 		mdvp = &mdvec_12160;
447960f6939SMatt Jacob 		basetype = ISP_HA_SCSI_12160;
448960f6939SMatt Jacob 		psize = 2 * sizeof (sdparam);
449960f6939SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
450960f6939SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
451960f6939SMatt Jacob 	}
452960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP2100) {
453c6608df3SMatt Jacob 		mdvp = &mdvec_2100;
454c6608df3SMatt Jacob 		basetype = ISP_HA_FC_2100;
455c6608df3SMatt Jacob 		psize = sizeof (fcparam);
456d59bd469SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
457d59bd469SMatt Jacob 		    PCI_MBOX_REGS2100_OFF;
458960f6939SMatt Jacob 		if (pci_get_revid(dev) < 3) {
459ab6d0040SMatt Jacob 			/*
460ab6d0040SMatt Jacob 			 * XXX: Need to get the actual revision
461ab6d0040SMatt Jacob 			 * XXX: number of the 2100 FB. At any rate,
462ab6d0040SMatt Jacob 			 * XXX: lower cache line size for early revision
463ab6d0040SMatt Jacob 			 * XXX; boards.
464ab6d0040SMatt Jacob 			 */
465ab6d0040SMatt Jacob 			linesz = 1;
466ab6d0040SMatt Jacob 		}
46765adb54cSMatt Jacob 	}
468960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP2200) {
469222bb542SMatt Jacob 		mdvp = &mdvec_2200;
470222bb542SMatt Jacob 		basetype = ISP_HA_FC_2200;
471222bb542SMatt Jacob 		psize = sizeof (fcparam);
472222bb542SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
473222bb542SMatt Jacob 		    PCI_MBOX_REGS2100_OFF;
474222bb542SMatt Jacob 	}
475c6608df3SMatt Jacob 	isp = &pcs->pci_isp;
476c6608df3SMatt Jacob 	isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT);
477c6608df3SMatt Jacob 	if (isp->isp_param == NULL) {
478960f6939SMatt Jacob 		device_printf(dev, "cannot allocate parameter data\n");
479960f6939SMatt Jacob 		goto bad;
480c6608df3SMatt Jacob 	}
481c6608df3SMatt Jacob 	bzero(isp->isp_param, psize);
482c6608df3SMatt Jacob 	isp->isp_mdvec = mdvp;
483c6608df3SMatt Jacob 	isp->isp_type = basetype;
484960f6939SMatt Jacob 	isp->isp_revision = pci_get_revid(dev);
485c6608df3SMatt Jacob 	(void) snprintf(isp->isp_name, sizeof (isp->isp_name), "isp%d", unit);
486c6608df3SMatt Jacob 	isp->isp_osinfo.unit = unit;
48765adb54cSMatt Jacob 
48856aef503SMatt Jacob 	/*
48956aef503SMatt Jacob 	 * Try and find firmware for this device.
49056aef503SMatt Jacob 	 */
49156aef503SMatt Jacob 
49256aef503SMatt Jacob 	if (isp_get_firmware_p) {
49356aef503SMatt Jacob 		int device = (int) pci_get_device(dev);
49456aef503SMatt Jacob #ifdef	ISP_TARGET_MODE
49556aef503SMatt Jacob 		(*isp_get_firmware_p)(0, 1, device, &mdvp->dv_ispfw);
49656aef503SMatt Jacob #else
49756aef503SMatt Jacob 		(*isp_get_firmware_p)(0, 0, device, &mdvp->dv_ispfw);
49856aef503SMatt Jacob #endif
49956aef503SMatt Jacob 	}
50056aef503SMatt Jacob 
50156aef503SMatt Jacob 	/*
50256aef503SMatt Jacob 	 *
50356aef503SMatt Jacob 	 */
50456aef503SMatt Jacob 
505469b6b9eSMatt Jacob 	s = splbio();
506d951bbcaSMatt Jacob 	/*
507d951bbcaSMatt Jacob 	 * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER
508d951bbcaSMatt Jacob 	 * are set.
509d951bbcaSMatt Jacob 	 */
510960f6939SMatt Jacob 	cmd |= PCIM_CMD_SEREN | PCIM_CMD_PERRESPEN |
511960f6939SMatt Jacob 		PCIM_CMD_BUSMASTEREN | PCIM_CMD_INVEN;
512960f6939SMatt Jacob 	pci_write_config(dev, PCIR_COMMAND, cmd, 1);
513ab6d0040SMatt Jacob 
514d951bbcaSMatt Jacob 	/*
515222bb542SMatt Jacob 	 * Make sure the Cache Line Size register is set sensibly.
516d951bbcaSMatt Jacob 	 */
517960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_CACHELNSZ, 1);
518ab6d0040SMatt Jacob 	if (data != linesz) {
519d951bbcaSMatt Jacob 		data = PCI_DFLT_LNSZ;
520a95ae193SMatt Jacob 		CFGPRINTF("%s: set PCI line size to %d\n", isp->isp_name, data);
521960f6939SMatt Jacob 		pci_write_config(dev, PCIR_CACHELNSZ, data, 1);
522d951bbcaSMatt Jacob 	}
523ab6d0040SMatt Jacob 
524d951bbcaSMatt Jacob 	/*
525d951bbcaSMatt Jacob 	 * Make sure the Latency Timer is sane.
526d951bbcaSMatt Jacob 	 */
527960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_LATTIMER, 1);
528d951bbcaSMatt Jacob 	if (data < PCI_DFLT_LTNCY) {
529d951bbcaSMatt Jacob 		data = PCI_DFLT_LTNCY;
530a95ae193SMatt Jacob 		CFGPRINTF("%s: set PCI latency to %d\n", isp->isp_name, data);
531960f6939SMatt Jacob 		pci_write_config(dev, PCIR_LATTIMER, data, 1);
532d951bbcaSMatt Jacob 	}
533ab6d0040SMatt Jacob 
534ab6d0040SMatt Jacob 	/*
535ab6d0040SMatt Jacob 	 * Make sure we've disabled the ROM.
536ab6d0040SMatt Jacob 	 */
537960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_ROMADDR, 4);
538ab6d0040SMatt Jacob 	data &= ~1;
539960f6939SMatt Jacob 	pci_write_config(dev, PCIR_ROMADDR, data, 4);
54005fbcbb0SMatt Jacob 
541d951bbcaSMatt Jacob 
542086646f7SJustin T. Gibbs 	if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
543222bb542SMatt Jacob 	    BUS_SPACE_MAXADDR, NULL, NULL, lim + 1,
544222bb542SMatt Jacob 	    255, lim, 0, &pcs->parent_dmat) != 0) {
54505fbcbb0SMatt Jacob 		splx(s);
546d720e6d5SJustin T. Gibbs 		printf("%s: could not create master dma tag\n", isp->isp_name);
547960f6939SMatt Jacob 		free(isp->isp_param, M_DEVBUF);
548d720e6d5SJustin T. Gibbs 		free(pcs, M_DEVBUF);
549960f6939SMatt Jacob 		return (ENXIO);
55065adb54cSMatt Jacob 	}
55165adb54cSMatt Jacob 
552960f6939SMatt Jacob 	iqd = 0;
553960f6939SMatt Jacob 	irq = bus_alloc_resource(dev, SYS_RES_IRQ, &iqd, 0, ~0,
554960f6939SMatt Jacob 	    1, RF_ACTIVE | RF_SHAREABLE);
555960f6939SMatt Jacob 	if (irq == NULL) {
556960f6939SMatt Jacob 		device_printf(dev, "could not allocate interrupt\n");
557960f6939SMatt Jacob 		goto bad;
558960f6939SMatt Jacob 	}
559960f6939SMatt Jacob 
560222bb542SMatt Jacob 	if (getenv_int("isp_no_fwload", &bitmap)) {
561222bb542SMatt Jacob 		if (bitmap & (1 << unit))
562222bb542SMatt Jacob 			isp->isp_confopts |= ISP_CFG_NORELOAD;
563222bb542SMatt Jacob 	}
564222bb542SMatt Jacob 	if (getenv_int("isp_fwload", &bitmap)) {
565222bb542SMatt Jacob 		if (bitmap & (1 << unit))
566222bb542SMatt Jacob 			isp->isp_confopts &= ~ISP_CFG_NORELOAD;
567222bb542SMatt Jacob 	}
568222bb542SMatt Jacob 	if (getenv_int("isp_no_nvram", &bitmap)) {
569222bb542SMatt Jacob 		if (bitmap & (1 << unit))
570222bb542SMatt Jacob 			isp->isp_confopts |= ISP_CFG_NONVRAM;
571222bb542SMatt Jacob 	}
572222bb542SMatt Jacob 	if (getenv_int("isp_nvram", &bitmap)) {
573222bb542SMatt Jacob 		if (bitmap & (1 << unit))
574222bb542SMatt Jacob 			isp->isp_confopts &= ~ISP_CFG_NONVRAM;
575222bb542SMatt Jacob 	}
576222bb542SMatt Jacob 	if (getenv_int("isp_fcduplex", &bitmap)) {
577222bb542SMatt Jacob 		if (bitmap & (1 << unit))
578222bb542SMatt Jacob 			isp->isp_confopts |= ISP_CFG_FULL_DUPLEX;
579222bb542SMatt Jacob 	}
580222bb542SMatt Jacob 	if (getenv_int("isp_no_fcduplex", &bitmap)) {
581222bb542SMatt Jacob 		if (bitmap & (1 << unit))
582222bb542SMatt Jacob 			isp->isp_confopts &= ~ISP_CFG_FULL_DUPLEX;
583222bb542SMatt Jacob 	}
584960f6939SMatt Jacob 	if (getenv_int("isp_nport", &bitmap)) {
585960f6939SMatt Jacob 		if (bitmap & (1 << unit))
586960f6939SMatt Jacob 			isp->isp_confopts |= ISP_CFG_NPORT;
587960f6939SMatt Jacob 	}
588222bb542SMatt Jacob 	/*
5899637d68cSMatt Jacob 	 * Look for overriding WWN. This is a Node WWN so it binds to
5909637d68cSMatt Jacob 	 * all FC instances. A Port WWN will be constructed from it
5919637d68cSMatt Jacob 	 * as appropriate.
592222bb542SMatt Jacob 	 */
5939637d68cSMatt Jacob 	if (!getenv_quad("isp_wwn", (quad_t *) &isp->isp_osinfo.default_wwn)) {
5949637d68cSMatt Jacob 		int i;
5959637d68cSMatt Jacob 		u_int64_t seed = (u_int64_t) (intptr_t) isp;
596222bb542SMatt Jacob 
5979637d68cSMatt Jacob 		seed <<= 16;
5989637d68cSMatt Jacob 		seed &= ((1LL << 48) - 1LL);
599222bb542SMatt Jacob 		/*
600222bb542SMatt Jacob 		 * This isn't very random, but it's the best we can do for
6019637d68cSMatt Jacob 		 * the real edge case of cards that don't have WWNs. If
6029637d68cSMatt Jacob 		 * you recompile a new vers.c, you'll get a different WWN.
603222bb542SMatt Jacob 		 */
6049637d68cSMatt Jacob 		for (i = 0; version[i] != 0; i++) {
6059637d68cSMatt Jacob 			seed += version[i];
6069637d68cSMatt Jacob 		}
6079637d68cSMatt Jacob 		/*
6089637d68cSMatt Jacob 		 * Make sure the top nibble has something vaguely sensible.
6099637d68cSMatt Jacob 		 */
6109637d68cSMatt Jacob 		isp->isp_osinfo.default_wwn |= (4LL << 60) | seed;
6119637d68cSMatt Jacob 	} else {
6129637d68cSMatt Jacob 		isp->isp_confopts |= ISP_CFG_OWNWWN;
613222bb542SMatt Jacob 	}
614a95ae193SMatt Jacob 	(void) getenv_int("isp_debug", &isp_debug);
61542426921SMatt Jacob #ifdef	ISP_TARGET_MODE
61642426921SMatt Jacob 	(void) getenv_int("isp_tdebug", &isp_tdebug);
61742426921SMatt Jacob #endif
618960f6939SMatt Jacob 	if (bus_setup_intr(dev, irq, INTR_TYPE_CAM, (void (*)(void *))isp_intr,
619960f6939SMatt Jacob 	    isp, &pcs->ih)) {
620469b6b9eSMatt Jacob 		splx(s);
621960f6939SMatt Jacob 		device_printf(dev, "could not setup interrupt\n");
622960f6939SMatt Jacob 		goto bad;
623960f6939SMatt Jacob 	}
624960f6939SMatt Jacob 
62505fbcbb0SMatt Jacob 	/*
62605fbcbb0SMatt Jacob 	 * Make sure we're in reset state.
62705fbcbb0SMatt Jacob 	 */
62865adb54cSMatt Jacob 	isp_reset(isp);
62965adb54cSMatt Jacob 	if (isp->isp_state != ISP_RESETSTATE) {
630469b6b9eSMatt Jacob 		splx(s);
631960f6939SMatt Jacob 		goto bad;
63265adb54cSMatt Jacob 	}
63365adb54cSMatt Jacob 	isp_init(isp);
63465adb54cSMatt Jacob 	if (isp->isp_state != ISP_INITSTATE) {
635d59bd469SMatt Jacob 		/* If we're a Fibre Channel Card, we allow deferred attach */
636222bb542SMatt Jacob 		if (IS_SCSI(isp)) {
63765adb54cSMatt Jacob 			isp_uninit(isp);
638469b6b9eSMatt Jacob 			splx(s);
639960f6939SMatt Jacob 			goto bad;
640d59bd469SMatt Jacob 		}
64165adb54cSMatt Jacob 	}
64265adb54cSMatt Jacob 	isp_attach(isp);
64365adb54cSMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE) {
644d59bd469SMatt Jacob 		/* If we're a Fibre Channel Card, we allow deferred attach */
64592c49d78SMatt Jacob 		if (IS_SCSI(isp)) {
64665adb54cSMatt Jacob 			isp_uninit(isp);
647469b6b9eSMatt Jacob 			splx(s);
648960f6939SMatt Jacob 			goto bad;
649960f6939SMatt Jacob 		}
650960f6939SMatt Jacob 	}
651469b6b9eSMatt Jacob 	splx(s);
65256aef503SMatt Jacob 	/*
65356aef503SMatt Jacob 	 * XXXX: Here is where we might unload the f/w module
65456aef503SMatt Jacob 	 * XXXX: (or decrease the reference count to it).
65556aef503SMatt Jacob 	 */
656960f6939SMatt Jacob 	return (0);
657960f6939SMatt Jacob 
658960f6939SMatt Jacob bad:
659960f6939SMatt Jacob 
660960f6939SMatt Jacob 	if (pcs && pcs->ih) {
661960f6939SMatt Jacob 		(void) bus_teardown_intr(dev, irq, pcs->ih);
662960f6939SMatt Jacob 	}
663960f6939SMatt Jacob 
664960f6939SMatt Jacob 	if (irq) {
665960f6939SMatt Jacob 		(void) bus_release_resource(dev, SYS_RES_IRQ, iqd, irq);
666960f6939SMatt Jacob 	}
667960f6939SMatt Jacob 	if (regs) {
668960f6939SMatt Jacob 		(void) bus_release_resource(dev, rtp, rgd, regs);
669960f6939SMatt Jacob 	}
670960f6939SMatt Jacob 	if (pcs) {
671960f6939SMatt Jacob 		if (pcs->pci_isp.isp_param)
672960f6939SMatt Jacob 			free(pcs->pci_isp.isp_param, M_DEVBUF);
67365adb54cSMatt Jacob 		free(pcs, M_DEVBUF);
67465adb54cSMatt Jacob 	}
67556aef503SMatt Jacob 	/*
67656aef503SMatt Jacob 	 * XXXX: Here is where we might unload the f/w module
67756aef503SMatt Jacob 	 * XXXX: (or decrease the reference count to it).
67856aef503SMatt Jacob 	 */
679960f6939SMatt Jacob 	return (ENXIO);
68065adb54cSMatt Jacob }
68165adb54cSMatt Jacob 
68265adb54cSMatt Jacob static u_int16_t
683d59bd469SMatt Jacob isp_pci_rd_reg(isp, regoff)
684d59bd469SMatt Jacob 	struct ispsoftc *isp;
685d59bd469SMatt Jacob 	int regoff;
68665adb54cSMatt Jacob {
68765adb54cSMatt Jacob 	u_int16_t rv;
68865adb54cSMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
689d59bd469SMatt Jacob 	int offset, oldconf = 0;
69065adb54cSMatt Jacob 
691d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
69265adb54cSMatt Jacob 		/*
69365adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
69465adb54cSMatt Jacob 		 */
695d59bd469SMatt Jacob 		oldconf = isp_pci_rd_reg(isp, BIU_CONF1);
696d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP);
69765adb54cSMatt Jacob 	}
698d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
699d59bd469SMatt Jacob 	offset += (regoff & 0xff);
70065adb54cSMatt Jacob 	rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset);
701d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
702d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf);
70365adb54cSMatt Jacob 	}
70465adb54cSMatt Jacob 	return (rv);
70565adb54cSMatt Jacob }
70665adb54cSMatt Jacob 
70765adb54cSMatt Jacob static void
708d59bd469SMatt Jacob isp_pci_wr_reg(isp, regoff, val)
709d59bd469SMatt Jacob 	struct ispsoftc *isp;
710d59bd469SMatt Jacob 	int regoff;
711d59bd469SMatt Jacob 	u_int16_t val;
71265adb54cSMatt Jacob {
71365adb54cSMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
714d59bd469SMatt Jacob 	int offset, oldconf = 0;
715d59bd469SMatt Jacob 
716d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
71765adb54cSMatt Jacob 		/*
71865adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
71965adb54cSMatt Jacob 		 */
720d59bd469SMatt Jacob 		oldconf = isp_pci_rd_reg(isp, BIU_CONF1);
721d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP);
72265adb54cSMatt Jacob 	}
723d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
724d59bd469SMatt Jacob 	offset += (regoff & 0xff);
72565adb54cSMatt Jacob 	bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val);
726d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
727d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf);
72865adb54cSMatt Jacob 	}
72965adb54cSMatt Jacob }
73065adb54cSMatt Jacob 
731d59bd469SMatt Jacob static u_int16_t
732d59bd469SMatt Jacob isp_pci_rd_reg_1080(isp, regoff)
733d59bd469SMatt Jacob 	struct ispsoftc *isp;
734d59bd469SMatt Jacob 	int regoff;
735d59bd469SMatt Jacob {
73622e1dc85SMatt Jacob 	u_int16_t rv, oc = 0;
737d59bd469SMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
73822e1dc85SMatt Jacob 	int offset;
739d59bd469SMatt Jacob 
74022e1dc85SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
74122e1dc85SMatt Jacob 	    (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
74222e1dc85SMatt Jacob 		u_int16_t tc;
743d59bd469SMatt Jacob 		/*
744d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
745d59bd469SMatt Jacob 		 */
746d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
74722e1dc85SMatt Jacob 		tc = oc & ~BIU_PCI1080_CONF1_DMA;
74822e1dc85SMatt Jacob 		if (regoff & SXP_BANK1_SELECT)
74922e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP1;
75022e1dc85SMatt Jacob 		else
75122e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP0;
75222e1dc85SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, tc);
753d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
754d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
755d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA);
756d59bd469SMatt Jacob 	}
757d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
758d59bd469SMatt Jacob 	offset += (regoff & 0xff);
759d59bd469SMatt Jacob 	rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset);
76022e1dc85SMatt Jacob 	if (oc) {
761d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc);
762d59bd469SMatt Jacob 	}
763d59bd469SMatt Jacob 	return (rv);
764d59bd469SMatt Jacob }
765d59bd469SMatt Jacob 
766d59bd469SMatt Jacob static void
767d59bd469SMatt Jacob isp_pci_wr_reg_1080(isp, regoff, val)
768d59bd469SMatt Jacob 	struct ispsoftc *isp;
769d59bd469SMatt Jacob 	int regoff;
770d59bd469SMatt Jacob 	u_int16_t val;
771d59bd469SMatt Jacob {
772d59bd469SMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
773d59bd469SMatt Jacob 	int offset, oc = 0;
774d59bd469SMatt Jacob 
77522e1dc85SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
77622e1dc85SMatt Jacob 	    (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
77722e1dc85SMatt Jacob 		u_int16_t tc;
778d59bd469SMatt Jacob 		/*
779d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
780d59bd469SMatt Jacob 		 */
781d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
78222e1dc85SMatt Jacob 		tc = oc & ~BIU_PCI1080_CONF1_DMA;
78322e1dc85SMatt Jacob 		if (regoff & SXP_BANK1_SELECT)
78422e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP1;
78522e1dc85SMatt Jacob 		else
78622e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP0;
78722e1dc85SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, tc);
788d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
789d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
790d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA);
791d59bd469SMatt Jacob 	}
792d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
793d59bd469SMatt Jacob 	offset += (regoff & 0xff);
794d59bd469SMatt Jacob 	bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val);
79522e1dc85SMatt Jacob 	if (oc) {
796d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc);
797d59bd469SMatt Jacob 	}
798d59bd469SMatt Jacob }
799d59bd469SMatt Jacob 
800d720e6d5SJustin T. Gibbs static void isp_map_rquest __P((void *, bus_dma_segment_t *, int, int));
801d720e6d5SJustin T. Gibbs static void isp_map_result __P((void *, bus_dma_segment_t *, int, int));
802d720e6d5SJustin T. Gibbs static void isp_map_fcscrt __P((void *, bus_dma_segment_t *, int, int));
803d720e6d5SJustin T. Gibbs 
804222bb542SMatt Jacob struct imush {
805222bb542SMatt Jacob 	struct ispsoftc *isp;
806222bb542SMatt Jacob 	int error;
807222bb542SMatt Jacob };
808222bb542SMatt Jacob 
809d720e6d5SJustin T. Gibbs static void
81017e318c6SMatt Jacob isp_map_rquest(void *arg, bus_dma_segment_t *segs, int nseg, int error)
811d720e6d5SJustin T. Gibbs {
812222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
813222bb542SMatt Jacob 	if (error) {
814222bb542SMatt Jacob 		imushp->error = error;
815222bb542SMatt Jacob 	} else {
816222bb542SMatt Jacob 		imushp->isp->isp_rquest_dma = segs->ds_addr;
817222bb542SMatt Jacob 	}
818d720e6d5SJustin T. Gibbs }
819d720e6d5SJustin T. Gibbs 
820d720e6d5SJustin T. Gibbs static void
82117e318c6SMatt Jacob isp_map_result(void *arg, bus_dma_segment_t *segs, int nseg, int error)
822d720e6d5SJustin T. Gibbs {
823222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
824222bb542SMatt Jacob 	if (error) {
825222bb542SMatt Jacob 		imushp->error = error;
826222bb542SMatt Jacob 	} else {
827222bb542SMatt Jacob 		imushp->isp->isp_result_dma = segs->ds_addr;
828222bb542SMatt Jacob 	}
829d720e6d5SJustin T. Gibbs }
830d720e6d5SJustin T. Gibbs 
831d720e6d5SJustin T. Gibbs static void
83217e318c6SMatt Jacob isp_map_fcscrt(void *arg, bus_dma_segment_t *segs, int nseg, int error)
833d720e6d5SJustin T. Gibbs {
834222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
835222bb542SMatt Jacob 	if (error) {
836222bb542SMatt Jacob 		imushp->error = error;
837222bb542SMatt Jacob 	} else {
838222bb542SMatt Jacob 		fcparam *fcp = imushp->isp->isp_param;
839d720e6d5SJustin T. Gibbs 		fcp->isp_scdma = segs->ds_addr;
840d720e6d5SJustin T. Gibbs 	}
841222bb542SMatt Jacob }
842d720e6d5SJustin T. Gibbs 
843d720e6d5SJustin T. Gibbs static int
84417e318c6SMatt Jacob isp_pci_mbxdma(struct ispsoftc *isp)
845d720e6d5SJustin T. Gibbs {
846d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
847d720e6d5SJustin T. Gibbs 	caddr_t base;
848d720e6d5SJustin T. Gibbs 	u_int32_t len;
849d720e6d5SJustin T. Gibbs 	int i, error;
850222bb542SMatt Jacob 	bus_size_t lim;
851222bb542SMatt Jacob 	struct imush im;
852222bb542SMatt Jacob 
853222bb542SMatt Jacob 
854a95ae193SMatt Jacob 	/*
855a95ae193SMatt Jacob 	 * Already been here? If so, leave...
856a95ae193SMatt Jacob 	 */
857a95ae193SMatt Jacob 	if (isp->isp_rquest) {
858a95ae193SMatt Jacob 		return (0);
859a95ae193SMatt Jacob 	}
860a95ae193SMatt Jacob 
861a95ae193SMatt Jacob 	len = sizeof (ISP_SCSI_XFER_T **) * isp->isp_maxcmds;
862a95ae193SMatt Jacob 	isp->isp_xflist = (ISP_SCSI_XFER_T **) malloc(len, M_DEVBUF, M_WAITOK);
863a95ae193SMatt Jacob 	if (isp->isp_xflist == NULL) {
864a95ae193SMatt Jacob 		printf("%s: can't alloc xflist array\n", isp->isp_name);
865a95ae193SMatt Jacob 		return (1);
866a95ae193SMatt Jacob 	}
867a95ae193SMatt Jacob 	bzero(isp->isp_xflist, len);
868a95ae193SMatt Jacob 	len = sizeof (bus_dmamap_t) * isp->isp_maxcmds;
869a95ae193SMatt Jacob 	pci->dmaps = (bus_dmamap_t *) malloc(len, M_DEVBUF,  M_WAITOK);
870a95ae193SMatt Jacob 	if (pci->dmaps == NULL) {
871a95ae193SMatt Jacob 		printf("%s: can't alloc dma maps\n", isp->isp_name);
872a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
873a95ae193SMatt Jacob 		return (1);
874a95ae193SMatt Jacob 	}
875a95ae193SMatt Jacob 
87622e1dc85SMatt Jacob 	if (IS_FC(isp) || IS_ULTRA2(isp))
877222bb542SMatt Jacob 		lim = BUS_SPACE_MAXADDR + 1;
878222bb542SMatt Jacob 	else
879222bb542SMatt Jacob 		lim = BUS_SPACE_MAXADDR_24BIT + 1;
880d720e6d5SJustin T. Gibbs 
881d720e6d5SJustin T. Gibbs 	/*
882d720e6d5SJustin T. Gibbs 	 * Allocate and map the request, result queues, plus FC scratch area.
883d720e6d5SJustin T. Gibbs 	 */
884d720e6d5SJustin T. Gibbs 	len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN);
885d720e6d5SJustin T. Gibbs 	len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN);
886222bb542SMatt Jacob 	if (IS_FC(isp)) {
887d720e6d5SJustin T. Gibbs 		len += ISP2100_SCRLEN;
888d720e6d5SJustin T. Gibbs 	}
889222bb542SMatt Jacob 	if (bus_dma_tag_create(pci->parent_dmat, PAGE_SIZE, lim,
890222bb542SMatt Jacob 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, len, 1,
891222bb542SMatt Jacob 	    BUS_SPACE_MAXSIZE_32BIT, 0, &pci->cntrol_dmat) != 0) {
892d720e6d5SJustin T. Gibbs 		printf("%s: cannot create a dma tag for control spaces\n",
893d720e6d5SJustin T. Gibbs 		    isp->isp_name);
894a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
895a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
896d720e6d5SJustin T. Gibbs 		return (1);
897d720e6d5SJustin T. Gibbs 	}
898d720e6d5SJustin T. Gibbs 	if (bus_dmamem_alloc(pci->cntrol_dmat, (void **)&base,
899d720e6d5SJustin T. Gibbs 	    BUS_DMA_NOWAIT, &pci->cntrol_dmap) != 0) {
9004873663cSMatt Jacob 		printf("%s: cannot allocate %d bytes of CCB memory\n",
9014873663cSMatt Jacob 		    isp->isp_name, len);
902a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
903a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
904d720e6d5SJustin T. Gibbs 		return (1);
905d720e6d5SJustin T. Gibbs 	}
906d720e6d5SJustin T. Gibbs 
907d720e6d5SJustin T. Gibbs 	isp->isp_rquest = base;
908222bb542SMatt Jacob 	im.isp = isp;
909222bb542SMatt Jacob 	im.error = 0;
910d720e6d5SJustin T. Gibbs 	bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_rquest,
911222bb542SMatt Jacob 	    ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN), isp_map_rquest, &im, 0);
912222bb542SMatt Jacob 	if (im.error) {
913222bb542SMatt Jacob 		printf("%s: error %d loading dma map for DMA request queue\n",
914222bb542SMatt Jacob 		    isp->isp_name, im.error);
915a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
916a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
917a95ae193SMatt Jacob 		isp->isp_rquest = NULL;
918222bb542SMatt Jacob 		return (1);
919222bb542SMatt Jacob 	}
920d720e6d5SJustin T. Gibbs 	isp->isp_result = base + ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN);
921222bb542SMatt Jacob 	im.error = 0;
922d720e6d5SJustin T. Gibbs 	bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_result,
923222bb542SMatt Jacob 	    ISP_QUEUE_SIZE(RESULT_QUEUE_LEN), isp_map_result, &im, 0);
924222bb542SMatt Jacob 	if (im.error) {
925222bb542SMatt Jacob 		printf("%s: error %d loading dma map for DMA result queue\n",
926222bb542SMatt Jacob 		    isp->isp_name, im.error);
927a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
928a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
929a95ae193SMatt Jacob 		isp->isp_rquest = NULL;
930222bb542SMatt Jacob 		return (1);
931222bb542SMatt Jacob 	}
932d720e6d5SJustin T. Gibbs 
933a95ae193SMatt Jacob 	for (i = 0; i < isp->isp_maxcmds; i++) {
934d720e6d5SJustin T. Gibbs 		error = bus_dmamap_create(pci->parent_dmat, 0, &pci->dmaps[i]);
935d720e6d5SJustin T. Gibbs 		if (error) {
936a95ae193SMatt Jacob 			printf("%s: error %d creating per-cmd DMA maps\n",
937d720e6d5SJustin T. Gibbs 			    isp->isp_name, error);
938a95ae193SMatt Jacob 			free(isp->isp_xflist, M_DEVBUF);
939a95ae193SMatt Jacob 			free(pci->dmaps, M_DEVBUF);
940a95ae193SMatt Jacob 			isp->isp_rquest = NULL;
941d720e6d5SJustin T. Gibbs 			return (1);
942d720e6d5SJustin T. Gibbs 		}
943d720e6d5SJustin T. Gibbs 	}
944a95ae193SMatt Jacob 
945222bb542SMatt Jacob 	if (IS_FC(isp)) {
94692c49d78SMatt Jacob 		fcparam *fcp = (fcparam *) isp->isp_param;
94792c49d78SMatt Jacob 		fcp->isp_scratch = base +
94892c49d78SMatt Jacob 			ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN) +
94992c49d78SMatt Jacob 			ISP_QUEUE_SIZE(RESULT_QUEUE_LEN);
950222bb542SMatt Jacob 		im.error = 0;
95192c49d78SMatt Jacob 		bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap,
952222bb542SMatt Jacob 		    fcp->isp_scratch, ISP2100_SCRLEN, isp_map_fcscrt, &im, 0);
953222bb542SMatt Jacob 		if (im.error) {
954222bb542SMatt Jacob 			printf("%s: error %d loading FC scratch area\n",
955222bb542SMatt Jacob 			    isp->isp_name, im.error);
956a95ae193SMatt Jacob 			free(isp->isp_xflist, M_DEVBUF);
957a95ae193SMatt Jacob 			free(pci->dmaps, M_DEVBUF);
958a95ae193SMatt Jacob 			isp->isp_rquest = NULL;
959222bb542SMatt Jacob 			return (1);
960222bb542SMatt Jacob 		}
96192c49d78SMatt Jacob 	}
962d720e6d5SJustin T. Gibbs 	return (0);
963d720e6d5SJustin T. Gibbs }
964d720e6d5SJustin T. Gibbs 
965d720e6d5SJustin T. Gibbs typedef struct {
966d720e6d5SJustin T. Gibbs 	struct ispsoftc *isp;
9679e11e5beSMatt Jacob 	void *cmd_token;
9689e11e5beSMatt Jacob 	void *rq;
9699637d68cSMatt Jacob 	u_int16_t *iptrp;
9709637d68cSMatt Jacob 	u_int16_t optr;
971d720e6d5SJustin T. Gibbs 	u_int error;
972d720e6d5SJustin T. Gibbs } mush_t;
973d720e6d5SJustin T. Gibbs 
9744873663cSMatt Jacob #define	MUSHERR_NOQENTRIES	-2
9754873663cSMatt Jacob 
9769e11e5beSMatt Jacob #ifdef	ISP_TARGET_MODE
9779e11e5beSMatt Jacob /*
9789e11e5beSMatt Jacob  * We need to handle DMA for target mode differently from initiator mode.
9799e11e5beSMatt Jacob  *
9809e11e5beSMatt Jacob  * DMA mapping and construction and submission of CTIO Request Entries
9819e11e5beSMatt Jacob  * and rendevous for completion are very tightly coupled because we start
9829e11e5beSMatt Jacob  * out by knowing (per platform) how much data we have to move, but we
9839e11e5beSMatt Jacob  * don't know, up front, how many DMA mapping segments will have to be used
9849e11e5beSMatt Jacob  * cover that data, so we don't know how many CTIO Request Entries we
9859e11e5beSMatt Jacob  * will end up using. Further, for performance reasons we may want to
9869e11e5beSMatt Jacob  * (on the last CTIO for Fibre Channel), send status too (if all went well).
9879e11e5beSMatt Jacob  *
9889e11e5beSMatt Jacob  * The standard vector still goes through isp_pci_dmasetup, but the callback
9899e11e5beSMatt Jacob  * for the DMA mapping routines comes here instead with the whole transfer
9909e11e5beSMatt Jacob  * mapped and a pointer to a partially filled in already allocated request
9919e11e5beSMatt Jacob  * queue entry. We finish the job.
9929e11e5beSMatt Jacob  */
99305fbcbb0SMatt Jacob static void tdma_mk __P((void *, bus_dma_segment_t *, int, int));
99405fbcbb0SMatt Jacob static void tdma_mkfc __P((void *, bus_dma_segment_t *, int, int));
9959e11e5beSMatt Jacob 
996d720e6d5SJustin T. Gibbs static void
99705fbcbb0SMatt Jacob tdma_mk(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
998d720e6d5SJustin T. Gibbs {
999d720e6d5SJustin T. Gibbs 	mush_t *mp;
10009e11e5beSMatt Jacob 	struct ccb_scsiio *csio;
1001d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci;
1002d720e6d5SJustin T. Gibbs 	bus_dmamap_t *dp;
100305fbcbb0SMatt Jacob 	u_int8_t scsi_status;
10049e11e5beSMatt Jacob 	ct_entry_t *cto;
100505fbcbb0SMatt Jacob 	u_int32_t handle, totxfr, sflags;
100605fbcbb0SMatt Jacob 	int nctios, send_status;
100705fbcbb0SMatt Jacob 	int32_t resid;
1008d720e6d5SJustin T. Gibbs 
1009d720e6d5SJustin T. Gibbs 	mp = (mush_t *) arg;
1010d720e6d5SJustin T. Gibbs 	if (error) {
1011d720e6d5SJustin T. Gibbs 		mp->error = error;
1012d720e6d5SJustin T. Gibbs 		return;
1013d720e6d5SJustin T. Gibbs 	}
10149e11e5beSMatt Jacob 	csio = mp->cmd_token;
10159e11e5beSMatt Jacob 	cto = mp->rq;
10169e11e5beSMatt Jacob 
101765b024e1SMatt Jacob 	cto->ct_xfrlen = 0;
101865b024e1SMatt Jacob 	cto->ct_seg_count = 0;
101965b024e1SMatt Jacob 	cto->ct_header.rqs_entry_count = 1;
102005fbcbb0SMatt Jacob 	MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg));
102105fbcbb0SMatt Jacob 
102205fbcbb0SMatt Jacob 	if (nseg == 0) {
102305fbcbb0SMatt Jacob 		cto->ct_header.rqs_seqno = 1;
102405fbcbb0SMatt Jacob 		ISP_TDQE(mp->isp, "tdma_mk[no data]", *mp->iptrp, cto);
102565b024e1SMatt Jacob 		if (isp_tdebug) {
102665b024e1SMatt Jacob 			printf("%s:CTIO lun %d->iid%d flgs 0x%x sts 0x%x ssts "
102705fbcbb0SMatt Jacob 			    "0x%x res %d\n", mp->isp->isp_name,
102865b024e1SMatt Jacob 			    csio->ccb_h.target_lun, cto->ct_iid, cto->ct_flags,
102965b024e1SMatt Jacob 			    cto->ct_status, cto->ct_scsi_status, cto->ct_resid);
103065b024e1SMatt Jacob 		}
103105fbcbb0SMatt Jacob 		ISP_SWIZ_CTIO(mp->isp, cto, cto);
103265b024e1SMatt Jacob 		return;
103365b024e1SMatt Jacob 	}
103465b024e1SMatt Jacob 
103565b024e1SMatt Jacob 	nctios = nseg / ISP_RQDSEG;
103665b024e1SMatt Jacob 	if (nseg % ISP_RQDSEG) {
103765b024e1SMatt Jacob 		nctios++;
103865b024e1SMatt Jacob 	}
103965b024e1SMatt Jacob 
104005fbcbb0SMatt Jacob 	/*
104105fbcbb0SMatt Jacob 	 * Save handle, and potentially any SCSI status, which we'll reinsert
104205fbcbb0SMatt Jacob 	 * on the last CTIO we're going to send.
104305fbcbb0SMatt Jacob 	 */
104405fbcbb0SMatt Jacob 	handle = cto->ct_reserved;
104505fbcbb0SMatt Jacob 	cto->ct_reserved = 0;
104605fbcbb0SMatt Jacob 	cto->ct_header.rqs_seqno = 0;
104705fbcbb0SMatt Jacob 	send_status = (cto->ct_flags & CT_SENDSTATUS) != 0;
104805fbcbb0SMatt Jacob 
104905fbcbb0SMatt Jacob 	if (send_status) {
105005fbcbb0SMatt Jacob 		sflags = cto->ct_flags & (CT_SENDSTATUS | CT_CCINCR);
105105fbcbb0SMatt Jacob 		cto->ct_flags &= ~(CT_SENDSTATUS | CT_CCINCR);
105205fbcbb0SMatt Jacob 		/*
105305fbcbb0SMatt Jacob 		 * Preserve residual.
105405fbcbb0SMatt Jacob 		 */
105505fbcbb0SMatt Jacob 		resid = cto->ct_resid;
105605fbcbb0SMatt Jacob 
105705fbcbb0SMatt Jacob 		/*
105805fbcbb0SMatt Jacob 		 * Save actual SCSI status.
105905fbcbb0SMatt Jacob 		 */
106005fbcbb0SMatt Jacob 		scsi_status = cto->ct_scsi_status;
106105fbcbb0SMatt Jacob 
106205fbcbb0SMatt Jacob 		/*
106305fbcbb0SMatt Jacob 		 * We can't do a status at the same time as a data CTIO, so
106405fbcbb0SMatt Jacob 		 * we need to synthesize an extra CTIO at this level.
106505fbcbb0SMatt Jacob 		 */
106605fbcbb0SMatt Jacob 		nctios++;
106705fbcbb0SMatt Jacob 	} else {
106805fbcbb0SMatt Jacob 		sflags = scsi_status = resid = 0;
106905fbcbb0SMatt Jacob 	}
107005fbcbb0SMatt Jacob 
107105fbcbb0SMatt Jacob 	totxfr = cto->ct_resid = 0;
107205fbcbb0SMatt Jacob 	cto->ct_scsi_status = 0;
107305fbcbb0SMatt Jacob 
10749e11e5beSMatt Jacob 	pci = (struct isp_pcisoftc *)mp->isp;
1075469b6b9eSMatt Jacob 	dp = &pci->dmaps[isp_handle_index(handle)];
10769e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1077d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
1078d720e6d5SJustin T. Gibbs 	} else {
1079d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
1080d720e6d5SJustin T. Gibbs 	}
1081d720e6d5SJustin T. Gibbs 
10829e11e5beSMatt Jacob 
10839e11e5beSMatt Jacob 	while (nctios--) {
108405fbcbb0SMatt Jacob 		int seglim;
10859e11e5beSMatt Jacob 
10869e11e5beSMatt Jacob 		seglim = nseg;
108705fbcbb0SMatt Jacob 		if (seglim) {
108805fbcbb0SMatt Jacob 			int seg;
108905fbcbb0SMatt Jacob 
10909e11e5beSMatt Jacob 			if (seglim > ISP_RQDSEG)
10919e11e5beSMatt Jacob 				seglim = ISP_RQDSEG;
10929e11e5beSMatt Jacob 
109305fbcbb0SMatt Jacob 			for (seg = 0; seg < seglim; seg++, nseg--) {
109405fbcbb0SMatt Jacob 				/*
109505fbcbb0SMatt Jacob 				 * Unlike normal initiator commands, we don't
109605fbcbb0SMatt Jacob 				 * do any swizzling here.
109705fbcbb0SMatt Jacob 				 */
10989e11e5beSMatt Jacob 				cto->ct_dataseg[seg].ds_count = dm_segs->ds_len;
109905fbcbb0SMatt Jacob 				cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr;
11009e11e5beSMatt Jacob 				cto->ct_xfrlen += dm_segs->ds_len;
110105fbcbb0SMatt Jacob 				totxfr += dm_segs->ds_len;
11029e11e5beSMatt Jacob 				dm_segs++;
11039e11e5beSMatt Jacob 			}
11049e11e5beSMatt Jacob 			cto->ct_seg_count = seg;
11059e11e5beSMatt Jacob 		} else {
110605fbcbb0SMatt Jacob 			/*
110705fbcbb0SMatt Jacob 			 * This case should only happen when we're sending an
110805fbcbb0SMatt Jacob 			 * extra CTIO with final status.
110905fbcbb0SMatt Jacob 			 */
111005fbcbb0SMatt Jacob 			if (send_status == 0) {
111105fbcbb0SMatt Jacob 				printf("%s: tdma_mk ran out of segments\n",
111205fbcbb0SMatt Jacob 				       mp->isp->isp_name);
111305fbcbb0SMatt Jacob 				mp->error = EINVAL;
111405fbcbb0SMatt Jacob 				return;
11159e11e5beSMatt Jacob 			}
111605fbcbb0SMatt Jacob 		}
111705fbcbb0SMatt Jacob 
111805fbcbb0SMatt Jacob 		/*
111905fbcbb0SMatt Jacob 		 * At this point, the fields ct_lun, ct_iid, ct_tagval,
112005fbcbb0SMatt Jacob 		 * ct_tagtype, and ct_timeout have been carried over
112105fbcbb0SMatt Jacob 		 * unchanged from what our caller had set.
112205fbcbb0SMatt Jacob 		 *
112305fbcbb0SMatt Jacob 		 * The dataseg fields and the seg_count fields we just got
112405fbcbb0SMatt Jacob 		 * through setting. The data direction we've preserved all
112505fbcbb0SMatt Jacob 		 * along and only clear it if we're now sending status.
112605fbcbb0SMatt Jacob 		 */
11279e11e5beSMatt Jacob 
11289e11e5beSMatt Jacob 		if (nctios == 0) {
11299e11e5beSMatt Jacob 			/*
113005fbcbb0SMatt Jacob 			 * We're the last in a sequence of CTIOs, so mark
113105fbcbb0SMatt Jacob 			 * this CTIO and save the handle to the CCB such that
113205fbcbb0SMatt Jacob 			 * when this CTIO completes we can free dma resources
113305fbcbb0SMatt Jacob 			 * and do whatever else we need to do to finish the
113405fbcbb0SMatt Jacob 			 * rest of the command.
11359e11e5beSMatt Jacob 			 */
11369e11e5beSMatt Jacob 			cto->ct_reserved = handle;
113705fbcbb0SMatt Jacob 			cto->ct_header.rqs_seqno = 1;
113805fbcbb0SMatt Jacob 
113905fbcbb0SMatt Jacob 			if (send_status) {
11409e11e5beSMatt Jacob 				cto->ct_scsi_status = scsi_status;
114105fbcbb0SMatt Jacob 				cto->ct_flags |= sflags | CT_NO_DATA;;
114205fbcbb0SMatt Jacob 				cto->ct_resid = resid;
114342426921SMatt Jacob 			}
114405fbcbb0SMatt Jacob 			if (isp_tdebug && send_status) {
114505fbcbb0SMatt Jacob 				printf("%s:CTIO lun%d for ID%d ct_flags 0x%x "
114605fbcbb0SMatt Jacob 				    "scsi_status 0x%x res %d\n",
114705fbcbb0SMatt Jacob 				    mp->isp->isp_name, csio->ccb_h.target_lun,
114805fbcbb0SMatt Jacob 				    cto->ct_iid, cto->ct_flags,
114905fbcbb0SMatt Jacob 				    cto->ct_scsi_status, cto->ct_resid);
115005fbcbb0SMatt Jacob 			} else if (isp_tdebug) {
115105fbcbb0SMatt Jacob 				printf("%s:CTIO lun%d for ID%d ct_flags 0x%x\n",
115205fbcbb0SMatt Jacob 				    mp->isp->isp_name, csio->ccb_h.target_lun,
115305fbcbb0SMatt Jacob 				    cto->ct_iid, cto->ct_flags);
115405fbcbb0SMatt Jacob 			}
115505fbcbb0SMatt Jacob 			ISP_TDQE(mp->isp, "last tdma_mk", *mp->iptrp, cto);
115605fbcbb0SMatt Jacob 			ISP_SWIZ_CTIO(mp->isp, cto, cto);
11579e11e5beSMatt Jacob 		} else {
11589e11e5beSMatt Jacob 			ct_entry_t     *octo = cto;
115905fbcbb0SMatt Jacob 
116005fbcbb0SMatt Jacob 			/*
116105fbcbb0SMatt Jacob 			 * Make sure handle fields are clean
116205fbcbb0SMatt Jacob 			 */
11639e11e5beSMatt Jacob 			cto->ct_reserved = 0;
11649e11e5beSMatt Jacob 			cto->ct_header.rqs_seqno = 0;
116505fbcbb0SMatt Jacob 
116642426921SMatt Jacob 			if (isp_tdebug) {
116705fbcbb0SMatt Jacob 				printf("%s:CTIO lun%d for ID%d ct_flags 0x%x\n",
116805fbcbb0SMatt Jacob 				    mp->isp->isp_name, csio->ccb_h.target_lun,
116905fbcbb0SMatt Jacob 				    cto->ct_iid, cto->ct_flags);
117042426921SMatt Jacob 			}
117105fbcbb0SMatt Jacob 			ISP_TDQE(mp->isp, "tdma_mk", *mp->iptrp, cto);
117205fbcbb0SMatt Jacob 
117305fbcbb0SMatt Jacob 			/*
117405fbcbb0SMatt Jacob 			 * Get a new CTIO
117505fbcbb0SMatt Jacob 			 */
11769e11e5beSMatt Jacob 			cto = (ct_entry_t *)
11779e11e5beSMatt Jacob 			    ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
11789e11e5beSMatt Jacob 			*mp->iptrp =
11799e11e5beSMatt Jacob 			    ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN);
11809e11e5beSMatt Jacob 			if (*mp->iptrp == mp->optr) {
118105fbcbb0SMatt Jacob 				printf("%s: Queue Overflow in tdma_mk\n",
11829e11e5beSMatt Jacob 				    mp->isp->isp_name);
11839e11e5beSMatt Jacob 				mp->error = MUSHERR_NOQENTRIES;
11849e11e5beSMatt Jacob 				return;
11859e11e5beSMatt Jacob 			}
11869e11e5beSMatt Jacob 			/*
11879e11e5beSMatt Jacob 			 * Fill in the new CTIO with info from the old one.
11889e11e5beSMatt Jacob 			 */
11899e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
11909e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_count = 1;
11919e11e5beSMatt Jacob 			cto->ct_header.rqs_flags = 0;
11929e11e5beSMatt Jacob 			cto->ct_lun = octo->ct_lun;
11939e11e5beSMatt Jacob 			cto->ct_iid = octo->ct_iid;
11949e11e5beSMatt Jacob 			cto->ct_reserved2 = octo->ct_reserved2;
11959e11e5beSMatt Jacob 			cto->ct_tgt = octo->ct_tgt;
119605fbcbb0SMatt Jacob 			cto->ct_flags = octo->ct_flags;
11979e11e5beSMatt Jacob 			cto->ct_status = 0;
11989e11e5beSMatt Jacob 			cto->ct_scsi_status = 0;
11999e11e5beSMatt Jacob 			cto->ct_tag_val = octo->ct_tag_val;
12009e11e5beSMatt Jacob 			cto->ct_tag_type = octo->ct_tag_type;
12019e11e5beSMatt Jacob 			cto->ct_xfrlen = 0;
12029e11e5beSMatt Jacob 			cto->ct_resid = 0;
12039e11e5beSMatt Jacob 			cto->ct_timeout = octo->ct_timeout;
12049e11e5beSMatt Jacob 			cto->ct_seg_count = 0;
120505fbcbb0SMatt Jacob 			MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg));
120605fbcbb0SMatt Jacob 			/*
120705fbcbb0SMatt Jacob 			 * Now swizzle the old one for the consumption of the
120805fbcbb0SMatt Jacob 			 * chip.
120905fbcbb0SMatt Jacob 			 */
121005fbcbb0SMatt Jacob 			ISP_SWIZ_CTIO(mp->isp, octo, octo);
12119e11e5beSMatt Jacob 		}
12129e11e5beSMatt Jacob 	}
12139e11e5beSMatt Jacob }
12149e11e5beSMatt Jacob 
12159e11e5beSMatt Jacob static void
121605fbcbb0SMatt Jacob tdma_mkfc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
12179e11e5beSMatt Jacob {
12189e11e5beSMatt Jacob 	mush_t *mp;
12199e11e5beSMatt Jacob 	struct ccb_scsiio *csio;
12209e11e5beSMatt Jacob 	struct isp_pcisoftc *pci;
12219e11e5beSMatt Jacob 	bus_dmamap_t *dp;
12229e11e5beSMatt Jacob 	ct2_entry_t *cto;
122365b024e1SMatt Jacob 	u_int16_t scsi_status, send_status, send_sense;
122405fbcbb0SMatt Jacob 	u_int32_t handle, totxfr, datalen;
122565b024e1SMatt Jacob 	u_int8_t sense[QLTM_SENSELEN];
12269e11e5beSMatt Jacob 	int nctios;
12279e11e5beSMatt Jacob 
12289e11e5beSMatt Jacob 	mp = (mush_t *) arg;
12299e11e5beSMatt Jacob 	if (error) {
12309e11e5beSMatt Jacob 		mp->error = error;
12319e11e5beSMatt Jacob 		return;
12329e11e5beSMatt Jacob 	}
12339e11e5beSMatt Jacob 
123465b024e1SMatt Jacob 	csio = mp->cmd_token;
123565b024e1SMatt Jacob 	cto = mp->rq;
123665b024e1SMatt Jacob 
123765b024e1SMatt Jacob 	if (nseg == 0) {
123865b024e1SMatt Jacob 		if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE1) {
123965b024e1SMatt Jacob 			printf("%s: dma2_tgt_fc, a status CTIO2 without MODE1 "
124065b024e1SMatt Jacob 			    "set (0x%x)\n", mp->isp->isp_name, cto->ct_flags);
124165b024e1SMatt Jacob 			mp->error = EINVAL;
124265b024e1SMatt Jacob 			return;
124365b024e1SMatt Jacob 		}
124465b024e1SMatt Jacob 	 	cto->ct_header.rqs_entry_count = 1;
124505fbcbb0SMatt Jacob 		cto->ct_header.rqs_seqno = 1;
124665b024e1SMatt Jacob 		/* ct_reserved contains the handle set by caller */
124765b024e1SMatt Jacob 		/*
124865b024e1SMatt Jacob 		 * We preserve ct_lun, ct_iid, ct_rxid. We set the data
124965b024e1SMatt Jacob 		 * flags to NO DATA and clear relative offset flags.
125065b024e1SMatt Jacob 		 * We preserve the ct_resid and the response area.
125165b024e1SMatt Jacob 		 */
125265b024e1SMatt Jacob 		cto->ct_flags |= CT2_NO_DATA;
125305fbcbb0SMatt Jacob 		if (cto->ct_resid > 0)
125405fbcbb0SMatt Jacob 			cto->ct_flags |= CT2_DATA_UNDER;
125505fbcbb0SMatt Jacob 		else if (cto->ct_resid < 0)
125605fbcbb0SMatt Jacob 			cto->ct_flags |= CT2_DATA_OVER;
125765b024e1SMatt Jacob 		cto->ct_seg_count = 0;
125865b024e1SMatt Jacob 		cto->ct_reloff = 0;
125965b024e1SMatt Jacob 		ISP_TDQE(mp->isp, "dma2_tgt_fc[no data]", *mp->iptrp, cto);
126065b024e1SMatt Jacob 		if (isp_tdebug) {
126165b024e1SMatt Jacob 			scsi_status = cto->rsp.m1.ct_scsi_status;
126265b024e1SMatt Jacob 			printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x "
126305fbcbb0SMatt Jacob 			    "sts 0x%x ssts 0x%x res %d\n", mp->isp->isp_name,
126465b024e1SMatt Jacob 			    cto->ct_rxid, csio->ccb_h.target_lun, cto->ct_iid,
126565b024e1SMatt Jacob 			    cto->ct_flags, cto->ct_status,
126665b024e1SMatt Jacob 			    cto->rsp.m1.ct_scsi_status, cto->ct_resid);
126765b024e1SMatt Jacob 		}
126865b024e1SMatt Jacob 		ISP_SWIZ_CTIO2(isp, cto, cto);
12699e11e5beSMatt Jacob 		return;
12709e11e5beSMatt Jacob 	}
12719e11e5beSMatt Jacob 
127265b024e1SMatt Jacob 	if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE0) {
127365b024e1SMatt Jacob 		printf("%s: dma2_tgt_fc, a data CTIO2 without MODE0 set "
127465b024e1SMatt Jacob 		    "(0x%x)\n\n", mp->isp->isp_name, cto->ct_flags);
127565b024e1SMatt Jacob 		mp->error = EINVAL;
127665b024e1SMatt Jacob 		return;
127765b024e1SMatt Jacob 	}
127865b024e1SMatt Jacob 
127965b024e1SMatt Jacob 
128065b024e1SMatt Jacob 	nctios = nseg / ISP_RQDSEG_T2;
128165b024e1SMatt Jacob 	if (nseg % ISP_RQDSEG_T2) {
128265b024e1SMatt Jacob 		nctios++;
128365b024e1SMatt Jacob 	}
128465b024e1SMatt Jacob 
12859e11e5beSMatt Jacob 	/*
128665b024e1SMatt Jacob 	 * Save the handle, status, reloff, and residual. We'll reinsert the
128765b024e1SMatt Jacob 	 * handle into the last CTIO2 we're going to send, and reinsert status
128865b024e1SMatt Jacob 	 * and residual (and possibly sense data) if that's to be sent as well.
128965b024e1SMatt Jacob 	 *
129065b024e1SMatt Jacob 	 * We preserve ct_reloff and adjust it for each data CTIO2 we send past
129165b024e1SMatt Jacob 	 * the first one. This is needed so that the FCP DATA IUs being sent
129265b024e1SMatt Jacob 	 * out have the correct offset (they can arrive at the other end out
129365b024e1SMatt Jacob 	 * of order).
12949e11e5beSMatt Jacob 	 */
129565b024e1SMatt Jacob 
12969e11e5beSMatt Jacob 	handle = cto->ct_reserved;
12979e11e5beSMatt Jacob 	cto->ct_reserved = 0;
129865b024e1SMatt Jacob 
129965b024e1SMatt Jacob 	if ((send_status = (cto->ct_flags & CT2_SENDSTATUS)) != 0) {
13009e11e5beSMatt Jacob 		cto->ct_flags &= ~CT2_SENDSTATUS;
13019e11e5beSMatt Jacob 
130265b024e1SMatt Jacob 		/*
130305fbcbb0SMatt Jacob 		 * Preserve residual, which is actually the total count.
130465b024e1SMatt Jacob 		 */
130505fbcbb0SMatt Jacob 		datalen = cto->ct_resid;
130665b024e1SMatt Jacob 
130765b024e1SMatt Jacob 		/*
130865b024e1SMatt Jacob 		 * Save actual SCSI status. We'll reinsert the
130965b024e1SMatt Jacob 		 * CT2_SNSLEN_VALID later if appropriate.
131065b024e1SMatt Jacob 		 */
131165b024e1SMatt Jacob 		scsi_status = cto->rsp.m0.ct_scsi_status & 0xff;
131265b024e1SMatt Jacob 		send_sense = cto->rsp.m0.ct_scsi_status & CT2_SNSLEN_VALID;
131365b024e1SMatt Jacob 
131465b024e1SMatt Jacob 		/*
131565b024e1SMatt Jacob 		 * If we're sending status and have a CHECK CONDTION and
131665b024e1SMatt Jacob 		 * have sense data,  we send one more CTIO2 with just the
131765b024e1SMatt Jacob 		 * status and sense data. The upper layers have stashed
131865b024e1SMatt Jacob 		 * the sense data in the dataseg structure for us.
131965b024e1SMatt Jacob 		 */
132065b024e1SMatt Jacob 
132165b024e1SMatt Jacob 		if ((scsi_status & 0xf) == SCSI_STATUS_CHECK_COND &&
132265b024e1SMatt Jacob 		    send_sense) {
132365b024e1SMatt Jacob 			bcopy(cto->rsp.m0.ct_dataseg, sense, QLTM_SENSELEN);
132465b024e1SMatt Jacob 			nctios++;
132565b024e1SMatt Jacob 		}
132665b024e1SMatt Jacob 	} else {
132705fbcbb0SMatt Jacob 		scsi_status = send_sense = datalen = 0;
132865b024e1SMatt Jacob 	}
132965b024e1SMatt Jacob 
133065b024e1SMatt Jacob 	totxfr = cto->ct_resid = 0;
133165b024e1SMatt Jacob 	cto->rsp.m0.ct_scsi_status = 0;
133265b024e1SMatt Jacob 	bzero(&cto->rsp, sizeof (cto->rsp));
133365b024e1SMatt Jacob 
13349e11e5beSMatt Jacob 	pci = (struct isp_pcisoftc *)mp->isp;
1335469b6b9eSMatt Jacob 	dp = &pci->dmaps[isp_handle_index(handle)];
13369e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
13379e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
13389e11e5beSMatt Jacob 	} else {
13399e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
13409e11e5beSMatt Jacob 	}
13419e11e5beSMatt Jacob 
13429e11e5beSMatt Jacob 	while (nctios--) {
13439e11e5beSMatt Jacob 		int seg, seglim;
13449e11e5beSMatt Jacob 
13459e11e5beSMatt Jacob 		seglim = nseg;
134665b024e1SMatt Jacob 		if (seglim) {
13479e11e5beSMatt Jacob 			if (seglim > ISP_RQDSEG_T2)
13489e11e5beSMatt Jacob 				seglim = ISP_RQDSEG_T2;
13499e11e5beSMatt Jacob 
13509e11e5beSMatt Jacob 			for (seg = 0; seg < seglim; seg++) {
135165b024e1SMatt Jacob 				cto->rsp.m0.ct_dataseg[seg].ds_base =
135265b024e1SMatt Jacob 				    dm_segs->ds_addr;
135365b024e1SMatt Jacob 				cto->rsp.m0.ct_dataseg[seg].ds_count =
135465b024e1SMatt Jacob 				    dm_segs->ds_len;
13559e11e5beSMatt Jacob 				cto->rsp.m0.ct_xfrlen += dm_segs->ds_len;
135665b024e1SMatt Jacob 				totxfr += dm_segs->ds_len;
13579e11e5beSMatt Jacob 				dm_segs++;
13589e11e5beSMatt Jacob 			}
13599e11e5beSMatt Jacob 			cto->ct_seg_count = seg;
13609e11e5beSMatt Jacob 		} else {
136165b024e1SMatt Jacob 			/*
136265b024e1SMatt Jacob 			 * This case should only happen when we're sending a
136365b024e1SMatt Jacob 			 * synthesized MODE1 final status with sense data.
136465b024e1SMatt Jacob 			 */
136565b024e1SMatt Jacob 			if (send_sense == 0) {
136665b024e1SMatt Jacob 				printf("%s: dma2_tgt_fc ran out of segments, "
136765b024e1SMatt Jacob 				    "no SENSE DATA\n", mp->isp->isp_name);
136865b024e1SMatt Jacob 				mp->error = EINVAL;
136965b024e1SMatt Jacob 				return;
137065b024e1SMatt Jacob 			}
13719e11e5beSMatt Jacob 		}
13729e11e5beSMatt Jacob 
13739e11e5beSMatt Jacob 		/*
137465b024e1SMatt Jacob 		 * At this point, the fields ct_lun, ct_iid, ct_rxid,
137565b024e1SMatt Jacob 		 * ct_timeout have been carried over unchanged from what
137665b024e1SMatt Jacob 		 * our caller had set.
137765b024e1SMatt Jacob 		 *
137865b024e1SMatt Jacob 		 * The field ct_reloff is either what the caller set, or
137965b024e1SMatt Jacob 		 * what we've added to below.
138065b024e1SMatt Jacob 		 *
138165b024e1SMatt Jacob 		 * The dataseg fields and the seg_count fields we just got
138265b024e1SMatt Jacob 		 * through setting. The data direction we've preserved all
138365b024e1SMatt Jacob 		 * along and only clear it if we're sending a MODE1 status
138465b024e1SMatt Jacob 		 * as the last CTIO.
138565b024e1SMatt Jacob 		 *
138665b024e1SMatt Jacob 		 */
138765b024e1SMatt Jacob 
138865b024e1SMatt Jacob 		if (nctios == 0) {
138965b024e1SMatt Jacob 
139065b024e1SMatt Jacob 			/*
139165b024e1SMatt Jacob 			 * We're the last in a sequence of CTIO2s, so mark this
139265b024e1SMatt Jacob 			 * CTIO2 and save the handle to the CCB such that when
139365b024e1SMatt Jacob 			 * this CTIO2 completes we can free dma resources and
13949e11e5beSMatt Jacob 			 * do whatever else we need to do to finish the rest
13959e11e5beSMatt Jacob 			 * of the command.
13969e11e5beSMatt Jacob 			 */
139765b024e1SMatt Jacob 
13989e11e5beSMatt Jacob 			cto->ct_reserved = handle;
139965b024e1SMatt Jacob 			cto->ct_header.rqs_seqno = 1;
140065b024e1SMatt Jacob 
140165b024e1SMatt Jacob 			if (send_status) {
140265b024e1SMatt Jacob 				if (send_sense) {
140365b024e1SMatt Jacob 					bcopy(sense, cto->rsp.m1.ct_resp,
140465b024e1SMatt Jacob 					    QLTM_SENSELEN);
140565b024e1SMatt Jacob 					cto->rsp.m1.ct_senselen =
140665b024e1SMatt Jacob 					    QLTM_SENSELEN;
140765b024e1SMatt Jacob 					scsi_status |= CT2_SNSLEN_VALID;
140865b024e1SMatt Jacob 					cto->rsp.m1.ct_scsi_status =
140965b024e1SMatt Jacob 					    scsi_status;
141065b024e1SMatt Jacob 					cto->ct_flags &= CT2_FLAG_MMASK;
141165b024e1SMatt Jacob 					cto->ct_flags |= CT2_FLAG_MODE1 |
141265b024e1SMatt Jacob 					    CT2_NO_DATA| CT2_SENDSTATUS;
141365b024e1SMatt Jacob 				} else {
141465b024e1SMatt Jacob 					cto->rsp.m0.ct_scsi_status =
141565b024e1SMatt Jacob 					    scsi_status;
141665b024e1SMatt Jacob 					cto->ct_flags |= CT2_SENDSTATUS;
141765b024e1SMatt Jacob 				}
141805fbcbb0SMatt Jacob 				/*
141905fbcbb0SMatt Jacob 				 * Get 'real' residual and set flags based
142005fbcbb0SMatt Jacob 				 * on it.
142105fbcbb0SMatt Jacob 				 */
142205fbcbb0SMatt Jacob 				cto->ct_resid = datalen - totxfr;
142305fbcbb0SMatt Jacob 				if (cto->ct_resid > 0)
142405fbcbb0SMatt Jacob 					cto->ct_flags |= CT2_DATA_UNDER;
142505fbcbb0SMatt Jacob 				else if (cto->ct_resid < 0)
142605fbcbb0SMatt Jacob 					cto->ct_flags |= CT2_DATA_OVER;
142765b024e1SMatt Jacob 			}
14289e11e5beSMatt Jacob 			ISP_TDQE(mp->isp, "last dma2_tgt_fc", *mp->iptrp, cto);
142942426921SMatt Jacob 			if (isp_tdebug) {
143042426921SMatt Jacob 				printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs"
143105fbcbb0SMatt Jacob 				    "0x%x sts 0x%x ssts 0x%x res %d\n",
143265b024e1SMatt Jacob 				    mp->isp->isp_name, cto->ct_rxid,
143365b024e1SMatt Jacob 				    csio->ccb_h.target_lun, (int) cto->ct_iid,
143442426921SMatt Jacob 				    cto->ct_flags, cto->ct_status,
143565b024e1SMatt Jacob 				    cto->rsp.m1.ct_scsi_status, cto->ct_resid);
143642426921SMatt Jacob 			}
143765b024e1SMatt Jacob 			ISP_SWIZ_CTIO2(isp, cto, cto);
14389e11e5beSMatt Jacob 		} else {
14399e11e5beSMatt Jacob 			ct2_entry_t *octo = cto;
144065b024e1SMatt Jacob 
144165b024e1SMatt Jacob 			/*
144265b024e1SMatt Jacob 			 * Make sure handle fields are clean
144365b024e1SMatt Jacob 			 */
14449e11e5beSMatt Jacob 			cto->ct_reserved = 0;
14459e11e5beSMatt Jacob 			cto->ct_header.rqs_seqno = 0;
144665b024e1SMatt Jacob 
14479e11e5beSMatt Jacob 			ISP_TDQE(mp->isp, "dma2_tgt_fc", *mp->iptrp, cto);
144842426921SMatt Jacob 			if (isp_tdebug) {
144942426921SMatt Jacob 				printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs"
145065b024e1SMatt Jacob 				    "0x%x\n", mp->isp->isp_name, cto->ct_rxid,
145165b024e1SMatt Jacob 				    csio->ccb_h.target_lun, (int) cto->ct_iid,
145265b024e1SMatt Jacob 				    cto->ct_flags);
145342426921SMatt Jacob 			}
145465b024e1SMatt Jacob 			/*
145565b024e1SMatt Jacob 			 * Get a new CTIO2
145665b024e1SMatt Jacob 			 */
14579e11e5beSMatt Jacob 			cto = (ct2_entry_t *)
14589e11e5beSMatt Jacob 			    ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
14599e11e5beSMatt Jacob 			*mp->iptrp =
14609e11e5beSMatt Jacob 			    ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN);
14619e11e5beSMatt Jacob 			if (*mp->iptrp == mp->optr) {
14629e11e5beSMatt Jacob 				printf("%s: Queue Overflow in dma2_tgt_fc\n",
14639e11e5beSMatt Jacob 				    mp->isp->isp_name);
14649e11e5beSMatt Jacob 				mp->error = MUSHERR_NOQENTRIES;
14659e11e5beSMatt Jacob 				return;
14669e11e5beSMatt Jacob 			}
146765b024e1SMatt Jacob 
14689e11e5beSMatt Jacob 			/*
146965b024e1SMatt Jacob 			 * Fill in the new CTIO2 with info from the old one.
14709e11e5beSMatt Jacob 			 */
14719e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
14729e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_count = 1;
14739e11e5beSMatt Jacob 			cto->ct_header.rqs_flags = 0;
147465b024e1SMatt Jacob 			/* ct_header.rqs_seqno && ct_reserved done later */
14759e11e5beSMatt Jacob 			cto->ct_lun = octo->ct_lun;
14769e11e5beSMatt Jacob 			cto->ct_iid = octo->ct_iid;
14779e11e5beSMatt Jacob 			cto->ct_rxid = octo->ct_rxid;
147865b024e1SMatt Jacob 			cto->ct_flags = octo->ct_flags;
14799e11e5beSMatt Jacob 			cto->ct_status = 0;
14809e11e5beSMatt Jacob 			cto->ct_resid = 0;
14819e11e5beSMatt Jacob 			cto->ct_timeout = octo->ct_timeout;
14829e11e5beSMatt Jacob 			cto->ct_seg_count = 0;
148365b024e1SMatt Jacob 			/*
148465b024e1SMatt Jacob 			 * Adjust the new relative offset by the amount which
148565b024e1SMatt Jacob 			 * is recorded in the data segment of the old CTIO2 we
148665b024e1SMatt Jacob 			 * just finished filling out.
148765b024e1SMatt Jacob 			 */
148865b024e1SMatt Jacob 			cto->ct_reloff += octo->rsp.m0.ct_xfrlen;
14899e11e5beSMatt Jacob 			bzero(&cto->rsp, sizeof (cto->rsp));
149065b024e1SMatt Jacob 			ISP_SWIZ_CTIO2(isp, cto, cto);
14919e11e5beSMatt Jacob 		}
14929e11e5beSMatt Jacob 	}
14939e11e5beSMatt Jacob }
14949e11e5beSMatt Jacob #endif
14959e11e5beSMatt Jacob 
14969e11e5beSMatt Jacob static void dma2 __P((void *, bus_dma_segment_t *, int, int));
14979e11e5beSMatt Jacob 
14989e11e5beSMatt Jacob static void
14999e11e5beSMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
15009e11e5beSMatt Jacob {
15019e11e5beSMatt Jacob 	mush_t *mp;
15029e11e5beSMatt Jacob 	struct ccb_scsiio *csio;
15039e11e5beSMatt Jacob 	struct isp_pcisoftc *pci;
15049e11e5beSMatt Jacob 	bus_dmamap_t *dp;
15059e11e5beSMatt Jacob 	bus_dma_segment_t *eseg;
15069e11e5beSMatt Jacob 	ispreq_t *rq;
15079e11e5beSMatt Jacob 	ispcontreq_t *crq;
15089e11e5beSMatt Jacob 	int seglim, datalen;
15099e11e5beSMatt Jacob 
15109e11e5beSMatt Jacob 	mp = (mush_t *) arg;
15119e11e5beSMatt Jacob 	if (error) {
15129e11e5beSMatt Jacob 		mp->error = error;
15139e11e5beSMatt Jacob 		return;
15149e11e5beSMatt Jacob 	}
15159e11e5beSMatt Jacob 
15169e11e5beSMatt Jacob 	if (nseg < 1) {
15179e11e5beSMatt Jacob 		printf("%s: bad segment count (%d)\n", mp->isp->isp_name, nseg);
15189e11e5beSMatt Jacob 		mp->error = EFAULT;
15199e11e5beSMatt Jacob 		return;
15209e11e5beSMatt Jacob 	}
15219e11e5beSMatt Jacob 	csio = mp->cmd_token;
15229e11e5beSMatt Jacob 	rq = mp->rq;
15239e11e5beSMatt Jacob 	pci = (struct isp_pcisoftc *)mp->isp;
1524469b6b9eSMatt Jacob 	dp = &pci->dmaps[isp_handle_index(rq->req_handle)];
15259e11e5beSMatt Jacob 
15269e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
15279e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
15289e11e5beSMatt Jacob 	} else {
15299e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
15309e11e5beSMatt Jacob 	}
15319e11e5beSMatt Jacob 
15329e11e5beSMatt Jacob 	datalen = XS_XFRLEN(csio);
15339e11e5beSMatt Jacob 
15349e11e5beSMatt Jacob 	/*
15359e11e5beSMatt Jacob 	 * We're passed an initial partially filled in entry that
15369e11e5beSMatt Jacob 	 * has most fields filled in except for data transfer
15379e11e5beSMatt Jacob 	 * related values.
15389e11e5beSMatt Jacob 	 *
15399e11e5beSMatt Jacob 	 * Our job is to fill in the initial request queue entry and
15409e11e5beSMatt Jacob 	 * then to start allocating and filling in continuation entries
15419e11e5beSMatt Jacob 	 * until we've covered the entire transfer.
15429e11e5beSMatt Jacob 	 */
15439e11e5beSMatt Jacob 
15449e11e5beSMatt Jacob 	if (IS_FC(mp->isp)) {
1545d720e6d5SJustin T. Gibbs 		seglim = ISP_RQDSEG_T2;
1546d720e6d5SJustin T. Gibbs 		((ispreqt2_t *)rq)->req_totalcnt = datalen;
15479e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
15489e11e5beSMatt Jacob 			((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_IN;
15499e11e5beSMatt Jacob 		} else {
15509e11e5beSMatt Jacob 			((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_OUT;
15519e11e5beSMatt Jacob 		}
1552d720e6d5SJustin T. Gibbs 	} else {
1553e142669aSMatt Jacob 		if (csio->cdb_len > 12) {
1554e142669aSMatt Jacob 			seglim = 0;
1555e142669aSMatt Jacob 		} else {
1556d720e6d5SJustin T. Gibbs 			seglim = ISP_RQDSEG;
1557e142669aSMatt Jacob 		}
15589e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
15599e11e5beSMatt Jacob 			rq->req_flags |= REQFLAG_DATA_IN;
15609e11e5beSMatt Jacob 		} else {
15619e11e5beSMatt Jacob 			rq->req_flags |= REQFLAG_DATA_OUT;
15629e11e5beSMatt Jacob 		}
1563d720e6d5SJustin T. Gibbs 	}
1564d720e6d5SJustin T. Gibbs 
1565d720e6d5SJustin T. Gibbs 	eseg = dm_segs + nseg;
1566d720e6d5SJustin T. Gibbs 
1567d720e6d5SJustin T. Gibbs 	while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) {
15689e11e5beSMatt Jacob 		if (IS_FC(mp->isp)) {
1569d720e6d5SJustin T. Gibbs 			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
1570d720e6d5SJustin T. Gibbs 			rq2->req_dataseg[rq2->req_seg_count].ds_base =
1571d720e6d5SJustin T. Gibbs 			    dm_segs->ds_addr;
1572d720e6d5SJustin T. Gibbs 			rq2->req_dataseg[rq2->req_seg_count].ds_count =
1573d720e6d5SJustin T. Gibbs 			    dm_segs->ds_len;
1574d720e6d5SJustin T. Gibbs 		} else {
1575d720e6d5SJustin T. Gibbs 			rq->req_dataseg[rq->req_seg_count].ds_base =
1576d720e6d5SJustin T. Gibbs 				dm_segs->ds_addr;
1577d720e6d5SJustin T. Gibbs 			rq->req_dataseg[rq->req_seg_count].ds_count =
1578d720e6d5SJustin T. Gibbs 				dm_segs->ds_len;
1579d720e6d5SJustin T. Gibbs 		}
1580d720e6d5SJustin T. Gibbs 		datalen -= dm_segs->ds_len;
1581d720e6d5SJustin T. Gibbs #if	0
15829e11e5beSMatt Jacob 		if (IS_FC(mp->isp)) {
1583d720e6d5SJustin T. Gibbs 			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
1584d720e6d5SJustin T. Gibbs 			printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n",
15859e11e5beSMatt Jacob 			    mp->isp->isp_name, rq->req_seg_count,
1586d720e6d5SJustin T. Gibbs 			    rq2->req_dataseg[rq2->req_seg_count].ds_count,
1587d720e6d5SJustin T. Gibbs 			    rq2->req_dataseg[rq2->req_seg_count].ds_base);
1588d720e6d5SJustin T. Gibbs 		} else {
1589d720e6d5SJustin T. Gibbs 			printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n",
15909e11e5beSMatt Jacob 			    mp->isp->isp_name, rq->req_seg_count,
1591d720e6d5SJustin T. Gibbs 			    rq->req_dataseg[rq->req_seg_count].ds_count,
1592d720e6d5SJustin T. Gibbs 			    rq->req_dataseg[rq->req_seg_count].ds_base);
1593d720e6d5SJustin T. Gibbs 		}
1594d720e6d5SJustin T. Gibbs #endif
1595d720e6d5SJustin T. Gibbs 		rq->req_seg_count++;
1596d720e6d5SJustin T. Gibbs 		dm_segs++;
1597d720e6d5SJustin T. Gibbs 	}
1598d720e6d5SJustin T. Gibbs 
1599d720e6d5SJustin T. Gibbs 	while (datalen > 0 && dm_segs != eseg) {
16009e11e5beSMatt Jacob 		crq = (ispcontreq_t *)
16019e11e5beSMatt Jacob 		    ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
16029e11e5beSMatt Jacob 		*mp->iptrp = ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN);
16039e11e5beSMatt Jacob 		if (*mp->iptrp == mp->optr) {
16044873663cSMatt Jacob #if	0
16059e11e5beSMatt Jacob 			printf("%s: Request Queue Overflow++\n",
16069e11e5beSMatt Jacob 			    mp->isp->isp_name);
16074873663cSMatt Jacob #endif
16084873663cSMatt Jacob 			mp->error = MUSHERR_NOQENTRIES;
1609d720e6d5SJustin T. Gibbs 			return;
1610d720e6d5SJustin T. Gibbs 		}
1611d720e6d5SJustin T. Gibbs 		rq->req_header.rqs_entry_count++;
1612d720e6d5SJustin T. Gibbs 		bzero((void *)crq, sizeof (*crq));
1613d720e6d5SJustin T. Gibbs 		crq->req_header.rqs_entry_count = 1;
1614d720e6d5SJustin T. Gibbs 		crq->req_header.rqs_entry_type = RQSTYPE_DATASEG;
1615d720e6d5SJustin T. Gibbs 
1616d720e6d5SJustin T. Gibbs 		seglim = 0;
1617d720e6d5SJustin T. Gibbs 		while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) {
1618d720e6d5SJustin T. Gibbs 			crq->req_dataseg[seglim].ds_base =
1619d720e6d5SJustin T. Gibbs 			    dm_segs->ds_addr;
1620d720e6d5SJustin T. Gibbs 			crq->req_dataseg[seglim].ds_count =
1621d720e6d5SJustin T. Gibbs 			    dm_segs->ds_len;
1622d720e6d5SJustin T. Gibbs #if	0
1623d720e6d5SJustin T. Gibbs 			printf("%s: seg%d[%d] cnt 0x%x paddr 0x%08x\n",
16249e11e5beSMatt Jacob 			    mp->isp->isp_name, rq->req_header.rqs_entry_count-1,
1625d720e6d5SJustin T. Gibbs 			    seglim, crq->req_dataseg[seglim].ds_count,
1626d720e6d5SJustin T. Gibbs 			    crq->req_dataseg[seglim].ds_base);
1627d720e6d5SJustin T. Gibbs #endif
1628d720e6d5SJustin T. Gibbs 			rq->req_seg_count++;
1629d720e6d5SJustin T. Gibbs 			dm_segs++;
1630d720e6d5SJustin T. Gibbs 			seglim++;
1631d720e6d5SJustin T. Gibbs 			datalen -= dm_segs->ds_len;
1632d720e6d5SJustin T. Gibbs 		}
1633d720e6d5SJustin T. Gibbs 	}
1634d720e6d5SJustin T. Gibbs }
1635d720e6d5SJustin T. Gibbs 
1636d720e6d5SJustin T. Gibbs static int
16379e11e5beSMatt Jacob isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq,
16389637d68cSMatt Jacob 	u_int16_t *iptrp, u_int16_t optr)
1639d720e6d5SJustin T. Gibbs {
1640d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
16410a5f7e8bSMatt Jacob 	bus_dmamap_t *dp = NULL;
1642d720e6d5SJustin T. Gibbs 	mush_t mush, *mp;
16439e11e5beSMatt Jacob 	void (*eptr) __P((void *, bus_dma_segment_t *, int, int));
1644d720e6d5SJustin T. Gibbs 
164565b024e1SMatt Jacob #ifdef	ISP_TARGET_MODE
164665b024e1SMatt Jacob 	if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) {
164765b024e1SMatt Jacob 		if (IS_FC(isp)) {
164805fbcbb0SMatt Jacob 			eptr = tdma_mkfc;
164965b024e1SMatt Jacob 		} else {
165005fbcbb0SMatt Jacob 			eptr = tdma_mk;
165165b024e1SMatt Jacob 		}
165205fbcbb0SMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE ||
165305fbcbb0SMatt Jacob 		    (csio->dxfer_len == 0)) {
165465b024e1SMatt Jacob 			rq->req_seg_count = 1;
165565b024e1SMatt Jacob 			mp = &mush;
165665b024e1SMatt Jacob 			mp->isp = isp;
165765b024e1SMatt Jacob 			mp->cmd_token = csio;
165865b024e1SMatt Jacob 			mp->rq = rq;
165965b024e1SMatt Jacob 			mp->iptrp = iptrp;
166065b024e1SMatt Jacob 			mp->optr = optr;
166165b024e1SMatt Jacob 			mp->error = 0;
166265b024e1SMatt Jacob 			(*eptr)(mp, NULL, 0, 0);
166365b024e1SMatt Jacob 			goto exit;
166465b024e1SMatt Jacob 		}
166565b024e1SMatt Jacob 	} else
166665b024e1SMatt Jacob #endif
166765b024e1SMatt Jacob 	eptr = dma2;
166865b024e1SMatt Jacob 
166942426921SMatt Jacob 	/*
167042426921SMatt Jacob 	 * NB: if we need to do request queue entry swizzling,
167142426921SMatt Jacob 	 * NB: this is where it would need to be done for cmds
167242426921SMatt Jacob 	 * NB: that move no data. For commands that move data,
167342426921SMatt Jacob 	 * NB: swizzling would take place in those functions.
167442426921SMatt Jacob 	 */
167505fbcbb0SMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE ||
167605fbcbb0SMatt Jacob 	    (csio->dxfer_len == 0)) {
167742426921SMatt Jacob 		rq->req_seg_count = 1;
167842426921SMatt Jacob 		return (CMD_QUEUED);
167942426921SMatt Jacob 	}
168042426921SMatt Jacob 
1681d720e6d5SJustin T. Gibbs 	/*
1682d720e6d5SJustin T. Gibbs 	 * Do a virtual grapevine step to collect info for
16834873663cSMatt Jacob 	 * the callback dma allocation that we have to use...
1684d720e6d5SJustin T. Gibbs 	 */
1685d720e6d5SJustin T. Gibbs 	mp = &mush;
1686d720e6d5SJustin T. Gibbs 	mp->isp = isp;
16879e11e5beSMatt Jacob 	mp->cmd_token = csio;
1688d720e6d5SJustin T. Gibbs 	mp->rq = rq;
1689d720e6d5SJustin T. Gibbs 	mp->iptrp = iptrp;
1690d720e6d5SJustin T. Gibbs 	mp->optr = optr;
1691d720e6d5SJustin T. Gibbs 	mp->error = 0;
1692d720e6d5SJustin T. Gibbs 
16939e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
16949e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) {
16954873663cSMatt Jacob 			int error, s;
1696469b6b9eSMatt Jacob 			dp = &pci->dmaps[isp_handle_index(rq->req_handle)];
1697d720e6d5SJustin T. Gibbs 			s = splsoftvm();
1698d720e6d5SJustin T. Gibbs 			error = bus_dmamap_load(pci->parent_dmat, *dp,
16999e11e5beSMatt Jacob 			    csio->data_ptr, csio->dxfer_len, eptr, mp, 0);
1700d720e6d5SJustin T. Gibbs 			if (error == EINPROGRESS) {
1701d720e6d5SJustin T. Gibbs 				bus_dmamap_unload(pci->parent_dmat, *dp);
1702d720e6d5SJustin T. Gibbs 				mp->error = EINVAL;
17034873663cSMatt Jacob 				printf("%s: deferred dma allocation not "
17044873663cSMatt Jacob 				    "supported\n", isp->isp_name);
1705d720e6d5SJustin T. Gibbs 			} else if (error && mp->error == 0) {
17060a5f7e8bSMatt Jacob #ifdef	DIAGNOSTIC
17070a5f7e8bSMatt Jacob 				printf("%s: error %d in dma mapping code\n",
17080a5f7e8bSMatt Jacob 				    isp->isp_name, error);
17090a5f7e8bSMatt Jacob #endif
1710d720e6d5SJustin T. Gibbs 				mp->error = error;
1711d720e6d5SJustin T. Gibbs 			}
17124873663cSMatt Jacob 			splx(s);
1713d720e6d5SJustin T. Gibbs 		} else {
1714d720e6d5SJustin T. Gibbs 			/* Pointer to physical buffer */
1715d720e6d5SJustin T. Gibbs 			struct bus_dma_segment seg;
1716d720e6d5SJustin T. Gibbs 			seg.ds_addr = (bus_addr_t)csio->data_ptr;
1717d720e6d5SJustin T. Gibbs 			seg.ds_len = csio->dxfer_len;
17189e11e5beSMatt Jacob 			(*eptr)(mp, &seg, 1, 0);
1719d720e6d5SJustin T. Gibbs 		}
1720d720e6d5SJustin T. Gibbs 	} else {
1721d720e6d5SJustin T. Gibbs 		struct bus_dma_segment *segs;
1722d720e6d5SJustin T. Gibbs 
17239e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) {
1724d720e6d5SJustin T. Gibbs 			printf("%s: Physical segment pointers unsupported",
1725d720e6d5SJustin T. Gibbs 				isp->isp_name);
1726d720e6d5SJustin T. Gibbs 			mp->error = EINVAL;
17279e11e5beSMatt Jacob 		} else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) {
1728d720e6d5SJustin T. Gibbs 			printf("%s: Virtual segment addresses unsupported",
1729d720e6d5SJustin T. Gibbs 				isp->isp_name);
1730d720e6d5SJustin T. Gibbs 			mp->error = EINVAL;
1731d720e6d5SJustin T. Gibbs 		} else {
1732d720e6d5SJustin T. Gibbs 			/* Just use the segments provided */
1733d720e6d5SJustin T. Gibbs 			segs = (struct bus_dma_segment *) csio->data_ptr;
17349e11e5beSMatt Jacob 			(*eptr)(mp, segs, csio->sglist_cnt, 0);
1735d720e6d5SJustin T. Gibbs 		}
1736d720e6d5SJustin T. Gibbs 	}
1737003a310fSMatt Jacob #ifdef	ISP_TARGET_MODE
173865b024e1SMatt Jacob exit:
1739003a310fSMatt Jacob #endif
1740d720e6d5SJustin T. Gibbs 	if (mp->error) {
17414873663cSMatt Jacob 		int retval = CMD_COMPLETE;
17424873663cSMatt Jacob 		if (mp->error == MUSHERR_NOQENTRIES) {
17434873663cSMatt Jacob 			retval = CMD_EAGAIN;
17444873663cSMatt Jacob 		} else if (mp->error == EFBIG) {
17450a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_REQ_TOO_BIG);
1746d720e6d5SJustin T. Gibbs 		} else if (mp->error == EINVAL) {
17470a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_REQ_INVALID);
1748d720e6d5SJustin T. Gibbs 		} else {
17490a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_UNREC_HBA_ERROR);
1750d720e6d5SJustin T. Gibbs 		}
17514873663cSMatt Jacob 		return (retval);
17524873663cSMatt Jacob 	} else {
17530a5f7e8bSMatt Jacob 		/*
17540a5f7e8bSMatt Jacob 		 * Check to see if we weren't cancelled while sleeping on
17550a5f7e8bSMatt Jacob 		 * getting DMA resources...
17560a5f7e8bSMatt Jacob 		 */
17579e11e5beSMatt Jacob 		if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
17580a5f7e8bSMatt Jacob 			if (dp) {
17590a5f7e8bSMatt Jacob 				bus_dmamap_unload(pci->parent_dmat, *dp);
17600a5f7e8bSMatt Jacob 			}
17610a5f7e8bSMatt Jacob 			return (CMD_COMPLETE);
17620a5f7e8bSMatt Jacob 		}
17634873663cSMatt Jacob 		return (CMD_QUEUED);
1764d720e6d5SJustin T. Gibbs 	}
1765d720e6d5SJustin T. Gibbs }
1766d720e6d5SJustin T. Gibbs 
1767d720e6d5SJustin T. Gibbs static void
1768a95ae193SMatt Jacob isp_pci_dmateardown(struct ispsoftc *isp, ISP_SCSI_XFER_T *xs, u_int32_t handle)
1769d720e6d5SJustin T. Gibbs {
1770d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
1771469b6b9eSMatt Jacob 	bus_dmamap_t *dp = &pci->dmaps[isp_handle_index(handle)];
1772a95ae193SMatt Jacob 	if ((xs->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1773d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTREAD);
1774d720e6d5SJustin T. Gibbs 	} else {
1775d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTWRITE);
1776d720e6d5SJustin T. Gibbs 	}
1777d720e6d5SJustin T. Gibbs 	bus_dmamap_unload(pci->parent_dmat, *dp);
1778d720e6d5SJustin T. Gibbs }
1779d720e6d5SJustin T. Gibbs 
178065adb54cSMatt Jacob 
178165adb54cSMatt Jacob static void
178217e318c6SMatt Jacob isp_pci_reset1(struct ispsoftc *isp)
178365adb54cSMatt Jacob {
178465adb54cSMatt Jacob 	/* Make sure the BIOS is disabled */
178565adb54cSMatt Jacob 	isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS);
1786469b6b9eSMatt Jacob 	/* and enable interrupts */
1787469b6b9eSMatt Jacob 	ENABLE_INTS(isp);
178865adb54cSMatt Jacob }
178965adb54cSMatt Jacob 
179065adb54cSMatt Jacob static void
179117e318c6SMatt Jacob isp_pci_dumpregs(struct ispsoftc *isp)
179265adb54cSMatt Jacob {
179365adb54cSMatt Jacob 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
1794960f6939SMatt Jacob 	printf("%s: PCI Status Command/Status=%x\n", pci->pci_isp.isp_name,
1795960f6939SMatt Jacob 	    pci_read_config(pci->pci_dev, PCIR_COMMAND, 1));
179665adb54cSMatt Jacob }
1797