xref: /freebsd/sys/dev/isp/isp_pci.c (revision 7cc0979fd64b721c92c3dd4a8688b56e15c9a5f9)
1c3aac50fSPeter Wemm /* $FreeBSD$ */
265adb54cSMatt Jacob /*
365adb54cSMatt Jacob  * PCI specific probe and attach routines for Qlogic ISP SCSI adapters.
465adb54cSMatt Jacob  * FreeBSD Version.
565adb54cSMatt Jacob  *
684267b9eSMatt Jacob  * Copyright (c) 1997, 1998, 1999, 2000 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
56d02373f1SMatt Jacob isp_pci_dmateardown __P((struct ispsoftc *, XS_T *, u_int32_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 };
24365adb54cSMatt Jacob 
244960f6939SMatt Jacob static driver_t isp_pci_driver = {
245960f6939SMatt Jacob 	"isp", isp_pci_methods, sizeof (struct isp_pcisoftc)
246960f6939SMatt Jacob };
247960f6939SMatt Jacob static devclass_t isp_devclass;
248960f6939SMatt Jacob DRIVER_MODULE(isp, pci, isp_pci_driver, isp_devclass, 0, 0);
24956aef503SMatt Jacob MODULE_VERSION(isp, 1);
25065adb54cSMatt Jacob 
251960f6939SMatt Jacob static int
252960f6939SMatt Jacob isp_pci_probe(device_t dev)
25365adb54cSMatt Jacob {
254960f6939SMatt Jacob         switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) {
25556aef503SMatt Jacob 	case PCI_QLOGIC_ISP1020:
256960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1020/1040 PCI SCSI Adapter");
25765adb54cSMatt Jacob 		break;
258d59bd469SMatt Jacob 	case PCI_QLOGIC_ISP1080:
259960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1080 PCI SCSI Adapter");
260c6608df3SMatt Jacob 		break;
261c6608df3SMatt Jacob 	case PCI_QLOGIC_ISP1240:
262960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1240 PCI SCSI Adapter");
263d59bd469SMatt Jacob 		break;
26422e1dc85SMatt Jacob 	case PCI_QLOGIC_ISP1280:
265960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1280 PCI SCSI Adapter");
266960f6939SMatt Jacob 		break;
267960f6939SMatt Jacob 	case PCI_QLOGIC_ISP12160:
268e11a1ee8SMatt Jacob 		if (pci_get_subvendor(dev) == AMI_RAID_SUBVENDOR_ID) {
269e11a1ee8SMatt Jacob 			return (ENXIO);
270e11a1ee8SMatt Jacob 		}
271960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 12160 PCI SCSI Adapter");
27222e1dc85SMatt Jacob 		break;
27365adb54cSMatt Jacob 	case PCI_QLOGIC_ISP2100:
274960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2100 PCI FC-AL Adapter");
27565adb54cSMatt Jacob 		break;
2765542fe4bSMatt Jacob 	case PCI_QLOGIC_ISP2200:
277960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2200 PCI FC-AL Adapter");
2785542fe4bSMatt Jacob 		break;
27965adb54cSMatt Jacob 	default:
280960f6939SMatt Jacob 		return (ENXIO);
28165adb54cSMatt Jacob 	}
282d02373f1SMatt Jacob 	if (device_get_unit(dev) == 0 && bootverbose) {
283d02373f1SMatt Jacob 		printf("Qlogic ISP Driver, FreeBSD Version %d.%d, "
284a95ae193SMatt Jacob 		    "Core Version %d.%d\n",
285d720e6d5SJustin T. Gibbs 		    ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR,
286d720e6d5SJustin T. Gibbs 		    ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR);
28765adb54cSMatt Jacob 	}
28856aef503SMatt Jacob 	/*
28956aef503SMatt Jacob 	 * XXXX: Here is where we might load the f/w module
29056aef503SMatt Jacob 	 * XXXX: (or increase a reference count to it).
29156aef503SMatt Jacob 	 */
292960f6939SMatt Jacob 	return (0);
29365adb54cSMatt Jacob }
29465adb54cSMatt Jacob 
295960f6939SMatt Jacob static int
296960f6939SMatt Jacob isp_pci_attach(device_t dev)
29765adb54cSMatt Jacob {
298960f6939SMatt Jacob 	struct resource *regs, *irq;
2993395b056SMatt Jacob 	int unit, bitmap, rtp, rgd, iqd, m1, m2, isp_debug;
300960f6939SMatt Jacob 	u_int32_t data, cmd, linesz, psize, basetype;
30165adb54cSMatt Jacob 	struct isp_pcisoftc *pcs;
3023395b056SMatt Jacob 	struct ispsoftc *isp = NULL;
303c6608df3SMatt Jacob 	struct ispmdvec *mdvp;
304222bb542SMatt Jacob 	bus_size_t lim;
3053395b056SMatt Jacob #ifdef	ISP_SMPLOCK
3063395b056SMatt Jacob 	int locksetup = 0;
3073395b056SMatt Jacob #endif
30865adb54cSMatt Jacob 
309222bb542SMatt Jacob 	/*
3109ba86737SMatt Jacob 	 * Figure out if we're supposed to skip this one.
3119ba86737SMatt Jacob 	 */
312960f6939SMatt Jacob 	unit = device_get_unit(dev);
3139ba86737SMatt Jacob 	if (getenv_int("isp_disable", &bitmap)) {
3149ba86737SMatt Jacob 		if (bitmap & (1 << unit)) {
315960f6939SMatt Jacob 			device_printf(dev, "not configuring\n");
316960f6939SMatt Jacob 			return (ENODEV);
3179ba86737SMatt Jacob 		}
3189ba86737SMatt Jacob 	}
3199ba86737SMatt Jacob 
3207cc0979fSDavid Malone 	pcs = malloc(sizeof (struct isp_pcisoftc), M_DEVBUF, M_NOWAIT | M_ZERO);
321960f6939SMatt Jacob 	if (pcs == NULL) {
322960f6939SMatt Jacob 		device_printf(dev, "cannot allocate softc\n");
323960f6939SMatt Jacob 		return (ENOMEM);
324960f6939SMatt Jacob 	}
325960f6939SMatt Jacob 
3269ba86737SMatt Jacob 	/*
327222bb542SMatt Jacob 	 * Figure out which we should try first - memory mapping or i/o mapping?
328222bb542SMatt Jacob 	 */
32956aef503SMatt Jacob #ifdef	__alpha__
330960f6939SMatt Jacob 	m1 = PCIM_CMD_MEMEN;
331960f6939SMatt Jacob 	m2 = PCIM_CMD_PORTEN;
332222bb542SMatt Jacob #else
333960f6939SMatt Jacob 	m1 = PCIM_CMD_PORTEN;
334960f6939SMatt Jacob 	m2 = PCIM_CMD_MEMEN;
335222bb542SMatt Jacob #endif
336222bb542SMatt Jacob 	bitmap = 0;
337222bb542SMatt Jacob 	if (getenv_int("isp_mem_map", &bitmap)) {
338960f6939SMatt Jacob 		if (bitmap & (1 << unit)) {
339960f6939SMatt Jacob 			m1 = PCIM_CMD_MEMEN;
340960f6939SMatt Jacob 			m2 = PCIM_CMD_PORTEN;
341960f6939SMatt Jacob 		}
342222bb542SMatt Jacob 	}
343222bb542SMatt Jacob 	bitmap = 0;
344222bb542SMatt Jacob 	if (getenv_int("isp_io_map", &bitmap)) {
345960f6939SMatt Jacob 		if (bitmap & (1 << unit)) {
346960f6939SMatt Jacob 			m1 = PCIM_CMD_PORTEN;
347960f6939SMatt Jacob 			m2 = PCIM_CMD_MEMEN;
348960f6939SMatt Jacob 		}
349222bb542SMatt Jacob 	}
350222bb542SMatt Jacob 
351ab6d0040SMatt Jacob 	linesz = PCI_DFLT_LNSZ;
352960f6939SMatt Jacob 	irq = regs = NULL;
353960f6939SMatt Jacob 	rgd = rtp = iqd = 0;
354960f6939SMatt Jacob 
355960f6939SMatt Jacob 	cmd = pci_read_config(dev, PCIR_COMMAND, 1);
356960f6939SMatt Jacob 	if (cmd & m1) {
357960f6939SMatt Jacob 		rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT;
358960f6939SMatt Jacob 		rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG;
359960f6939SMatt Jacob 		regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE);
36065adb54cSMatt Jacob 	}
361960f6939SMatt Jacob 	if (regs == NULL && (cmd & m2)) {
362960f6939SMatt Jacob 		rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT;
363960f6939SMatt Jacob 		rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG;
364960f6939SMatt Jacob 		regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE);
36565adb54cSMatt Jacob 	}
366960f6939SMatt Jacob 	if (regs == NULL) {
367960f6939SMatt Jacob 		device_printf(dev, "unable to map any ports\n");
368960f6939SMatt Jacob 		goto bad;
36965adb54cSMatt Jacob 	}
370222bb542SMatt Jacob 	if (bootverbose)
371f7dddf8aSMatt Jacob 		device_printf(dev, "using %s space register mapping\n",
372960f6939SMatt Jacob 		    (rgd == IO_MAP_REG)? "I/O" : "Memory");
373960f6939SMatt Jacob 	pcs->pci_dev = dev;
374960f6939SMatt Jacob 	pcs->pci_reg = regs;
375960f6939SMatt Jacob 	pcs->pci_st = rman_get_bustag(regs);
376960f6939SMatt Jacob 	pcs->pci_sh = rman_get_bushandle(regs);
37765adb54cSMatt Jacob 
378d59bd469SMatt Jacob 	pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF;
379d59bd469SMatt Jacob 	pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF;
380d59bd469SMatt Jacob 	pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF;
381d59bd469SMatt Jacob 	pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF;
382d59bd469SMatt Jacob 	pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF;
383c6608df3SMatt Jacob 	mdvp = &mdvec;
384c6608df3SMatt Jacob 	basetype = ISP_HA_SCSI_UNKNOWN;
385c6608df3SMatt Jacob 	psize = sizeof (sdparam);
386222bb542SMatt Jacob 	lim = BUS_SPACE_MAXSIZE_32BIT;
38756aef503SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP1020) {
388c6608df3SMatt Jacob 		mdvp = &mdvec;
389c6608df3SMatt Jacob 		basetype = ISP_HA_SCSI_UNKNOWN;
390c6608df3SMatt Jacob 		psize = sizeof (sdparam);
391222bb542SMatt Jacob 		lim = BUS_SPACE_MAXSIZE_24BIT;
392d59bd469SMatt Jacob 	}
393960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP1080) {
394c6608df3SMatt Jacob 		mdvp = &mdvec_1080;
395c6608df3SMatt Jacob 		basetype = ISP_HA_SCSI_1080;
396c6608df3SMatt Jacob 		psize = sizeof (sdparam);
397c6608df3SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
398c6608df3SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
399c6608df3SMatt Jacob 	}
400960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP1240) {
401c6608df3SMatt Jacob 		mdvp = &mdvec_1080;
40222e1dc85SMatt Jacob 		basetype = ISP_HA_SCSI_1240;
40322e1dc85SMatt Jacob 		psize = 2 * sizeof (sdparam);
40422e1dc85SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
40522e1dc85SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
40622e1dc85SMatt Jacob 	}
407960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP1280) {
40822e1dc85SMatt Jacob 		mdvp = &mdvec_1080;
40922e1dc85SMatt Jacob 		basetype = ISP_HA_SCSI_1280;
410c6608df3SMatt Jacob 		psize = 2 * sizeof (sdparam);
411d59bd469SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
412d59bd469SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
413d59bd469SMatt Jacob 	}
414960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP12160) {
415960f6939SMatt Jacob 		mdvp = &mdvec_12160;
416960f6939SMatt Jacob 		basetype = ISP_HA_SCSI_12160;
417960f6939SMatt Jacob 		psize = 2 * sizeof (sdparam);
418960f6939SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
419960f6939SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
420960f6939SMatt Jacob 	}
421960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP2100) {
422c6608df3SMatt Jacob 		mdvp = &mdvec_2100;
423c6608df3SMatt Jacob 		basetype = ISP_HA_FC_2100;
424c6608df3SMatt Jacob 		psize = sizeof (fcparam);
425d59bd469SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
426d59bd469SMatt Jacob 		    PCI_MBOX_REGS2100_OFF;
427960f6939SMatt Jacob 		if (pci_get_revid(dev) < 3) {
428ab6d0040SMatt Jacob 			/*
429ab6d0040SMatt Jacob 			 * XXX: Need to get the actual revision
430ab6d0040SMatt Jacob 			 * XXX: number of the 2100 FB. At any rate,
431ab6d0040SMatt Jacob 			 * XXX: lower cache line size for early revision
432ab6d0040SMatt Jacob 			 * XXX; boards.
433ab6d0040SMatt Jacob 			 */
434ab6d0040SMatt Jacob 			linesz = 1;
435ab6d0040SMatt Jacob 		}
43665adb54cSMatt Jacob 	}
437960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP2200) {
438222bb542SMatt Jacob 		mdvp = &mdvec_2200;
439222bb542SMatt Jacob 		basetype = ISP_HA_FC_2200;
440222bb542SMatt Jacob 		psize = sizeof (fcparam);
441222bb542SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
442222bb542SMatt Jacob 		    PCI_MBOX_REGS2100_OFF;
443222bb542SMatt Jacob 	}
444c6608df3SMatt Jacob 	isp = &pcs->pci_isp;
4457cc0979fSDavid Malone 	isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT | M_ZERO);
446c6608df3SMatt Jacob 	if (isp->isp_param == NULL) {
447960f6939SMatt Jacob 		device_printf(dev, "cannot allocate parameter data\n");
448960f6939SMatt Jacob 		goto bad;
449c6608df3SMatt Jacob 	}
450c6608df3SMatt Jacob 	isp->isp_mdvec = mdvp;
451c6608df3SMatt Jacob 	isp->isp_type = basetype;
452960f6939SMatt Jacob 	isp->isp_revision = pci_get_revid(dev);
453c6608df3SMatt Jacob 	(void) snprintf(isp->isp_name, sizeof (isp->isp_name), "isp%d", unit);
454c6608df3SMatt Jacob 	isp->isp_osinfo.unit = unit;
45565adb54cSMatt Jacob 
45656aef503SMatt Jacob 	/*
45756aef503SMatt Jacob 	 * Try and find firmware for this device.
45856aef503SMatt Jacob 	 */
45956aef503SMatt Jacob 
46056aef503SMatt Jacob 	if (isp_get_firmware_p) {
46156aef503SMatt Jacob 		int device = (int) pci_get_device(dev);
46256aef503SMatt Jacob #ifdef	ISP_TARGET_MODE
46356aef503SMatt Jacob 		(*isp_get_firmware_p)(0, 1, device, &mdvp->dv_ispfw);
46456aef503SMatt Jacob #else
46556aef503SMatt Jacob 		(*isp_get_firmware_p)(0, 0, device, &mdvp->dv_ispfw);
46656aef503SMatt Jacob #endif
46756aef503SMatt Jacob 	}
46856aef503SMatt Jacob 
46956aef503SMatt Jacob 	/*
470d951bbcaSMatt Jacob 	 * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER
471d951bbcaSMatt Jacob 	 * are set.
472d951bbcaSMatt Jacob 	 */
473960f6939SMatt Jacob 	cmd |= PCIM_CMD_SEREN | PCIM_CMD_PERRESPEN |
474960f6939SMatt Jacob 		PCIM_CMD_BUSMASTEREN | PCIM_CMD_INVEN;
475960f6939SMatt Jacob 	pci_write_config(dev, PCIR_COMMAND, cmd, 1);
476ab6d0040SMatt Jacob 
477d951bbcaSMatt Jacob 	/*
478222bb542SMatt Jacob 	 * Make sure the Cache Line Size register is set sensibly.
479d951bbcaSMatt Jacob 	 */
480960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_CACHELNSZ, 1);
481ab6d0040SMatt Jacob 	if (data != linesz) {
482d951bbcaSMatt Jacob 		data = PCI_DFLT_LNSZ;
483d02373f1SMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, "set PCI line size to %d", data);
484960f6939SMatt Jacob 		pci_write_config(dev, PCIR_CACHELNSZ, data, 1);
485d951bbcaSMatt Jacob 	}
486ab6d0040SMatt Jacob 
487d951bbcaSMatt Jacob 	/*
488d951bbcaSMatt Jacob 	 * Make sure the Latency Timer is sane.
489d951bbcaSMatt Jacob 	 */
490960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_LATTIMER, 1);
491d951bbcaSMatt Jacob 	if (data < PCI_DFLT_LTNCY) {
492d951bbcaSMatt Jacob 		data = PCI_DFLT_LTNCY;
493d02373f1SMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, "set PCI latency to %d", data);
494960f6939SMatt Jacob 		pci_write_config(dev, PCIR_LATTIMER, data, 1);
495d951bbcaSMatt Jacob 	}
496ab6d0040SMatt Jacob 
497ab6d0040SMatt Jacob 	/*
498ab6d0040SMatt Jacob 	 * Make sure we've disabled the ROM.
499ab6d0040SMatt Jacob 	 */
500960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_ROMADDR, 4);
501ab6d0040SMatt Jacob 	data &= ~1;
502960f6939SMatt Jacob 	pci_write_config(dev, PCIR_ROMADDR, data, 4);
50305fbcbb0SMatt Jacob 
504d951bbcaSMatt Jacob 
505086646f7SJustin T. Gibbs 	if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
506222bb542SMatt Jacob 	    BUS_SPACE_MAXADDR, NULL, NULL, lim + 1,
507222bb542SMatt Jacob 	    255, lim, 0, &pcs->parent_dmat) != 0) {
508f7dddf8aSMatt Jacob 		device_printf(dev, "could not create master dma tag\n");
509960f6939SMatt Jacob 		free(isp->isp_param, M_DEVBUF);
510d720e6d5SJustin T. Gibbs 		free(pcs, M_DEVBUF);
511960f6939SMatt Jacob 		return (ENXIO);
51265adb54cSMatt Jacob 	}
51365adb54cSMatt Jacob 
514960f6939SMatt Jacob 	iqd = 0;
515960f6939SMatt Jacob 	irq = bus_alloc_resource(dev, SYS_RES_IRQ, &iqd, 0, ~0,
516960f6939SMatt Jacob 	    1, RF_ACTIVE | RF_SHAREABLE);
517960f6939SMatt Jacob 	if (irq == NULL) {
518960f6939SMatt Jacob 		device_printf(dev, "could not allocate interrupt\n");
519960f6939SMatt Jacob 		goto bad;
520960f6939SMatt Jacob 	}
521960f6939SMatt Jacob 
522222bb542SMatt Jacob 	if (getenv_int("isp_no_fwload", &bitmap)) {
523222bb542SMatt Jacob 		if (bitmap & (1 << unit))
524222bb542SMatt Jacob 			isp->isp_confopts |= ISP_CFG_NORELOAD;
525222bb542SMatt Jacob 	}
526222bb542SMatt Jacob 	if (getenv_int("isp_fwload", &bitmap)) {
527222bb542SMatt Jacob 		if (bitmap & (1 << unit))
528222bb542SMatt Jacob 			isp->isp_confopts &= ~ISP_CFG_NORELOAD;
529222bb542SMatt Jacob 	}
530222bb542SMatt Jacob 	if (getenv_int("isp_no_nvram", &bitmap)) {
531222bb542SMatt Jacob 		if (bitmap & (1 << unit))
532222bb542SMatt Jacob 			isp->isp_confopts |= ISP_CFG_NONVRAM;
533222bb542SMatt Jacob 	}
534222bb542SMatt Jacob 	if (getenv_int("isp_nvram", &bitmap)) {
535222bb542SMatt Jacob 		if (bitmap & (1 << unit))
536222bb542SMatt Jacob 			isp->isp_confopts &= ~ISP_CFG_NONVRAM;
537222bb542SMatt Jacob 	}
538222bb542SMatt Jacob 	if (getenv_int("isp_fcduplex", &bitmap)) {
539222bb542SMatt Jacob 		if (bitmap & (1 << unit))
540222bb542SMatt Jacob 			isp->isp_confopts |= ISP_CFG_FULL_DUPLEX;
541222bb542SMatt Jacob 	}
542222bb542SMatt Jacob 	if (getenv_int("isp_no_fcduplex", &bitmap)) {
543222bb542SMatt Jacob 		if (bitmap & (1 << unit))
544222bb542SMatt Jacob 			isp->isp_confopts &= ~ISP_CFG_FULL_DUPLEX;
545222bb542SMatt Jacob 	}
546960f6939SMatt Jacob 	if (getenv_int("isp_nport", &bitmap)) {
547960f6939SMatt Jacob 		if (bitmap & (1 << unit))
548960f6939SMatt Jacob 			isp->isp_confopts |= ISP_CFG_NPORT;
549960f6939SMatt Jacob 	}
550222bb542SMatt Jacob 	/*
5519637d68cSMatt Jacob 	 * Look for overriding WWN. This is a Node WWN so it binds to
5529637d68cSMatt Jacob 	 * all FC instances. A Port WWN will be constructed from it
5539637d68cSMatt Jacob 	 * as appropriate.
554222bb542SMatt Jacob 	 */
5559637d68cSMatt Jacob 	if (!getenv_quad("isp_wwn", (quad_t *) &isp->isp_osinfo.default_wwn)) {
5569637d68cSMatt Jacob 		int i;
5579637d68cSMatt Jacob 		u_int64_t seed = (u_int64_t) (intptr_t) isp;
558222bb542SMatt Jacob 
5599637d68cSMatt Jacob 		seed <<= 16;
5609637d68cSMatt Jacob 		seed &= ((1LL << 48) - 1LL);
561222bb542SMatt Jacob 		/*
562222bb542SMatt Jacob 		 * This isn't very random, but it's the best we can do for
5639637d68cSMatt Jacob 		 * the real edge case of cards that don't have WWNs. If
5649637d68cSMatt Jacob 		 * you recompile a new vers.c, you'll get a different WWN.
565222bb542SMatt Jacob 		 */
5669637d68cSMatt Jacob 		for (i = 0; version[i] != 0; i++) {
5679637d68cSMatt Jacob 			seed += version[i];
5689637d68cSMatt Jacob 		}
5699637d68cSMatt Jacob 		/*
570d02373f1SMatt Jacob 		 * Make sure the top nibble has something vaguely sensible
571d02373f1SMatt Jacob 		 * (NAA == Locally Administered)
5729637d68cSMatt Jacob 		 */
573d02373f1SMatt Jacob 		isp->isp_osinfo.default_wwn |= (3LL << 60) | seed;
5749637d68cSMatt Jacob 	} else {
5759637d68cSMatt Jacob 		isp->isp_confopts |= ISP_CFG_OWNWWN;
576222bb542SMatt Jacob 	}
577d02373f1SMatt Jacob 	isp_debug = 0;
578a95ae193SMatt Jacob 	(void) getenv_int("isp_debug", &isp_debug);
579960f6939SMatt Jacob 	if (bus_setup_intr(dev, irq, INTR_TYPE_CAM, (void (*)(void *))isp_intr,
580960f6939SMatt Jacob 	    isp, &pcs->ih)) {
581960f6939SMatt Jacob 		device_printf(dev, "could not setup interrupt\n");
582960f6939SMatt Jacob 		goto bad;
583960f6939SMatt Jacob 	}
584960f6939SMatt Jacob 
58505fbcbb0SMatt Jacob 	/*
586d02373f1SMatt Jacob 	 * Set up logging levels.
587d02373f1SMatt Jacob 	 */
588d02373f1SMatt Jacob 	if (isp_debug) {
589d02373f1SMatt Jacob 		isp->isp_dblev = isp_debug;
590d02373f1SMatt Jacob 	} else {
591d02373f1SMatt Jacob 		isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR;
592d02373f1SMatt Jacob 	}
593d02373f1SMatt Jacob 	if (bootverbose)
594f7dddf8aSMatt Jacob 		isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO;
595d02373f1SMatt Jacob 
5963395b056SMatt Jacob #ifdef	ISP_SMPLOCK
5973395b056SMatt Jacob 	/* Make sure the lock is set up. */
5983395b056SMatt Jacob 	mtx_init(&isp->isp_osinfo.lock, "isp", MTX_DEF);
5993395b056SMatt Jacob 	locksetup++;
6003395b056SMatt Jacob #endif
6013395b056SMatt Jacob 
602d02373f1SMatt Jacob 	/*
60305fbcbb0SMatt Jacob 	 * Make sure we're in reset state.
60405fbcbb0SMatt Jacob 	 */
6053395b056SMatt Jacob 	ISP_LOCK(isp);
60665adb54cSMatt Jacob 	isp_reset(isp);
607d02373f1SMatt Jacob 
60865adb54cSMatt Jacob 	if (isp->isp_state != ISP_RESETSTATE) {
6093395b056SMatt Jacob 		ISP_UNLOCK(isp);
610960f6939SMatt Jacob 		goto bad;
61165adb54cSMatt Jacob 	}
61265adb54cSMatt Jacob 	isp_init(isp);
61365adb54cSMatt Jacob 	if (isp->isp_state != ISP_INITSTATE) {
614d59bd469SMatt Jacob 		/* If we're a Fibre Channel Card, we allow deferred attach */
615222bb542SMatt Jacob 		if (IS_SCSI(isp)) {
61665adb54cSMatt Jacob 			isp_uninit(isp);
6173395b056SMatt Jacob 			ISP_UNLOCK(isp);
618960f6939SMatt Jacob 			goto bad;
619d59bd469SMatt Jacob 		}
62065adb54cSMatt Jacob 	}
62165adb54cSMatt Jacob 	isp_attach(isp);
62265adb54cSMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE) {
623d59bd469SMatt Jacob 		/* If we're a Fibre Channel Card, we allow deferred attach */
62492c49d78SMatt Jacob 		if (IS_SCSI(isp)) {
62565adb54cSMatt Jacob 			isp_uninit(isp);
6263395b056SMatt Jacob 			ISP_UNLOCK(isp);
627960f6939SMatt Jacob 			goto bad;
628960f6939SMatt Jacob 		}
629960f6939SMatt Jacob 	}
63056aef503SMatt Jacob 	/*
63156aef503SMatt Jacob 	 * XXXX: Here is where we might unload the f/w module
63256aef503SMatt Jacob 	 * XXXX: (or decrease the reference count to it).
63356aef503SMatt Jacob 	 */
6343395b056SMatt Jacob 	ISP_UNLOCK(isp);
635960f6939SMatt Jacob 	return (0);
636960f6939SMatt Jacob 
637960f6939SMatt Jacob bad:
638960f6939SMatt Jacob 
639960f6939SMatt Jacob 	if (pcs && pcs->ih) {
640960f6939SMatt Jacob 		(void) bus_teardown_intr(dev, irq, pcs->ih);
641960f6939SMatt Jacob 	}
642960f6939SMatt Jacob 
6433395b056SMatt Jacob #ifdef	ISP_SMPLOCK
6443395b056SMatt Jacob 	if (locksetup && isp) {
6453395b056SMatt Jacob 		mtx_destroy(&isp->isp_osinfo.lock);
6463395b056SMatt Jacob 	}
6473395b056SMatt Jacob #endif
6483395b056SMatt Jacob 
649960f6939SMatt Jacob 	if (irq) {
650960f6939SMatt Jacob 		(void) bus_release_resource(dev, SYS_RES_IRQ, iqd, irq);
651960f6939SMatt Jacob 	}
6523395b056SMatt Jacob 
6533395b056SMatt Jacob 
654960f6939SMatt Jacob 	if (regs) {
655960f6939SMatt Jacob 		(void) bus_release_resource(dev, rtp, rgd, regs);
656960f6939SMatt Jacob 	}
6573395b056SMatt Jacob 
658960f6939SMatt Jacob 	if (pcs) {
659960f6939SMatt Jacob 		if (pcs->pci_isp.isp_param)
660960f6939SMatt Jacob 			free(pcs->pci_isp.isp_param, M_DEVBUF);
66165adb54cSMatt Jacob 		free(pcs, M_DEVBUF);
66265adb54cSMatt Jacob 	}
6633395b056SMatt 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 	 */
668960f6939SMatt Jacob 	return (ENXIO);
66965adb54cSMatt Jacob }
67065adb54cSMatt Jacob 
67165adb54cSMatt Jacob static u_int16_t
672d59bd469SMatt Jacob isp_pci_rd_reg(isp, regoff)
673d59bd469SMatt Jacob 	struct ispsoftc *isp;
674d59bd469SMatt Jacob 	int regoff;
67565adb54cSMatt Jacob {
67665adb54cSMatt Jacob 	u_int16_t rv;
67765adb54cSMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
678d59bd469SMatt Jacob 	int offset, oldconf = 0;
67965adb54cSMatt Jacob 
680d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
68165adb54cSMatt Jacob 		/*
68265adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
68365adb54cSMatt Jacob 		 */
684d59bd469SMatt Jacob 		oldconf = isp_pci_rd_reg(isp, BIU_CONF1);
685d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP);
68665adb54cSMatt Jacob 	}
687d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
688d59bd469SMatt Jacob 	offset += (regoff & 0xff);
68965adb54cSMatt Jacob 	rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset);
690d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
691d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf);
69265adb54cSMatt Jacob 	}
69365adb54cSMatt Jacob 	return (rv);
69465adb54cSMatt Jacob }
69565adb54cSMatt Jacob 
69665adb54cSMatt Jacob static void
697d59bd469SMatt Jacob isp_pci_wr_reg(isp, regoff, val)
698d59bd469SMatt Jacob 	struct ispsoftc *isp;
699d59bd469SMatt Jacob 	int regoff;
700d59bd469SMatt Jacob 	u_int16_t val;
70165adb54cSMatt Jacob {
70265adb54cSMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
703d59bd469SMatt Jacob 	int offset, oldconf = 0;
704d59bd469SMatt Jacob 
705d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
70665adb54cSMatt Jacob 		/*
70765adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
70865adb54cSMatt Jacob 		 */
709d59bd469SMatt Jacob 		oldconf = isp_pci_rd_reg(isp, BIU_CONF1);
710d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP);
71165adb54cSMatt Jacob 	}
712d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
713d59bd469SMatt Jacob 	offset += (regoff & 0xff);
71465adb54cSMatt Jacob 	bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val);
715d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
716d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf);
71765adb54cSMatt Jacob 	}
71865adb54cSMatt Jacob }
71965adb54cSMatt Jacob 
720d59bd469SMatt Jacob static u_int16_t
721d59bd469SMatt Jacob isp_pci_rd_reg_1080(isp, regoff)
722d59bd469SMatt Jacob 	struct ispsoftc *isp;
723d59bd469SMatt Jacob 	int regoff;
724d59bd469SMatt Jacob {
72522e1dc85SMatt Jacob 	u_int16_t rv, oc = 0;
726d59bd469SMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
72722e1dc85SMatt Jacob 	int offset;
728d59bd469SMatt Jacob 
72922e1dc85SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
73022e1dc85SMatt Jacob 	    (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
73122e1dc85SMatt Jacob 		u_int16_t tc;
732d59bd469SMatt Jacob 		/*
733d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
734d59bd469SMatt Jacob 		 */
735d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
73622e1dc85SMatt Jacob 		tc = oc & ~BIU_PCI1080_CONF1_DMA;
73722e1dc85SMatt Jacob 		if (regoff & SXP_BANK1_SELECT)
73822e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP1;
73922e1dc85SMatt Jacob 		else
74022e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP0;
74122e1dc85SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, tc);
742d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
743d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
744d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA);
745d59bd469SMatt Jacob 	}
746d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
747d59bd469SMatt Jacob 	offset += (regoff & 0xff);
748d59bd469SMatt Jacob 	rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset);
74922e1dc85SMatt Jacob 	if (oc) {
750d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc);
751d59bd469SMatt Jacob 	}
752d59bd469SMatt Jacob 	return (rv);
753d59bd469SMatt Jacob }
754d59bd469SMatt Jacob 
755d59bd469SMatt Jacob static void
756d59bd469SMatt Jacob isp_pci_wr_reg_1080(isp, regoff, val)
757d59bd469SMatt Jacob 	struct ispsoftc *isp;
758d59bd469SMatt Jacob 	int regoff;
759d59bd469SMatt Jacob 	u_int16_t val;
760d59bd469SMatt Jacob {
761d59bd469SMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
762d59bd469SMatt Jacob 	int offset, oc = 0;
763d59bd469SMatt Jacob 
76422e1dc85SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
76522e1dc85SMatt Jacob 	    (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
76622e1dc85SMatt Jacob 		u_int16_t tc;
767d59bd469SMatt Jacob 		/*
768d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
769d59bd469SMatt Jacob 		 */
770d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
77122e1dc85SMatt Jacob 		tc = oc & ~BIU_PCI1080_CONF1_DMA;
77222e1dc85SMatt Jacob 		if (regoff & SXP_BANK1_SELECT)
77322e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP1;
77422e1dc85SMatt Jacob 		else
77522e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP0;
77622e1dc85SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, tc);
777d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
778d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
779d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA);
780d59bd469SMatt Jacob 	}
781d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
782d59bd469SMatt Jacob 	offset += (regoff & 0xff);
783d59bd469SMatt Jacob 	bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val);
78422e1dc85SMatt Jacob 	if (oc) {
785d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc);
786d59bd469SMatt Jacob 	}
787d59bd469SMatt Jacob }
788d59bd469SMatt Jacob 
789d720e6d5SJustin T. Gibbs static void isp_map_rquest __P((void *, bus_dma_segment_t *, int, int));
790d720e6d5SJustin T. Gibbs static void isp_map_result __P((void *, bus_dma_segment_t *, int, int));
791d720e6d5SJustin T. Gibbs static void isp_map_fcscrt __P((void *, bus_dma_segment_t *, int, int));
792d720e6d5SJustin T. Gibbs 
793222bb542SMatt Jacob struct imush {
794222bb542SMatt Jacob 	struct ispsoftc *isp;
795222bb542SMatt Jacob 	int error;
796222bb542SMatt Jacob };
797222bb542SMatt Jacob 
798d720e6d5SJustin T. Gibbs static void
79917e318c6SMatt Jacob isp_map_rquest(void *arg, bus_dma_segment_t *segs, int nseg, int error)
800d720e6d5SJustin T. Gibbs {
801222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
802222bb542SMatt Jacob 	if (error) {
803222bb542SMatt Jacob 		imushp->error = error;
804222bb542SMatt Jacob 	} else {
805222bb542SMatt Jacob 		imushp->isp->isp_rquest_dma = segs->ds_addr;
806222bb542SMatt Jacob 	}
807d720e6d5SJustin T. Gibbs }
808d720e6d5SJustin T. Gibbs 
809d720e6d5SJustin T. Gibbs static void
81017e318c6SMatt Jacob isp_map_result(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_result_dma = segs->ds_addr;
817222bb542SMatt Jacob 	}
818d720e6d5SJustin T. Gibbs }
819d720e6d5SJustin T. Gibbs 
820d720e6d5SJustin T. Gibbs static void
82117e318c6SMatt Jacob isp_map_fcscrt(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 		fcparam *fcp = imushp->isp->isp_param;
828d720e6d5SJustin T. Gibbs 		fcp->isp_scdma = segs->ds_addr;
829d720e6d5SJustin T. Gibbs 	}
830222bb542SMatt Jacob }
831d720e6d5SJustin T. Gibbs 
832d720e6d5SJustin T. Gibbs static int
83317e318c6SMatt Jacob isp_pci_mbxdma(struct ispsoftc *isp)
834d720e6d5SJustin T. Gibbs {
835d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
836d720e6d5SJustin T. Gibbs 	caddr_t base;
837d720e6d5SJustin T. Gibbs 	u_int32_t len;
838d720e6d5SJustin T. Gibbs 	int i, error;
839222bb542SMatt Jacob 	bus_size_t lim;
840222bb542SMatt Jacob 	struct imush im;
841222bb542SMatt Jacob 
842222bb542SMatt Jacob 
843a95ae193SMatt Jacob 	/*
844a95ae193SMatt Jacob 	 * Already been here? If so, leave...
845a95ae193SMatt Jacob 	 */
846a95ae193SMatt Jacob 	if (isp->isp_rquest) {
847a95ae193SMatt Jacob 		return (0);
848a95ae193SMatt Jacob 	}
849a95ae193SMatt Jacob 
850d02373f1SMatt Jacob 	len = sizeof (XS_T **) * isp->isp_maxcmds;
8517cc0979fSDavid Malone 	isp->isp_xflist = (XS_T **) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
852a95ae193SMatt Jacob 	if (isp->isp_xflist == NULL) {
853d02373f1SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array");
854a95ae193SMatt Jacob 		return (1);
855a95ae193SMatt Jacob 	}
856a95ae193SMatt Jacob 	len = sizeof (bus_dmamap_t) * isp->isp_maxcmds;
857a95ae193SMatt Jacob 	pci->dmaps = (bus_dmamap_t *) malloc(len, M_DEVBUF,  M_WAITOK);
858a95ae193SMatt Jacob 	if (pci->dmaps == NULL) {
859d02373f1SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "can't alloc dma maps");
860a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
861a95ae193SMatt Jacob 		return (1);
862a95ae193SMatt Jacob 	}
863a95ae193SMatt Jacob 
86422e1dc85SMatt Jacob 	if (IS_FC(isp) || IS_ULTRA2(isp))
865222bb542SMatt Jacob 		lim = BUS_SPACE_MAXADDR + 1;
866222bb542SMatt Jacob 	else
867222bb542SMatt Jacob 		lim = BUS_SPACE_MAXADDR_24BIT + 1;
868d720e6d5SJustin T. Gibbs 
869d720e6d5SJustin T. Gibbs 	/*
870d720e6d5SJustin T. Gibbs 	 * Allocate and map the request, result queues, plus FC scratch area.
871d720e6d5SJustin T. Gibbs 	 */
872d02373f1SMatt Jacob 	len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
873d02373f1SMatt Jacob 	len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
874222bb542SMatt Jacob 	if (IS_FC(isp)) {
875d720e6d5SJustin T. Gibbs 		len += ISP2100_SCRLEN;
876d720e6d5SJustin T. Gibbs 	}
877222bb542SMatt Jacob 	if (bus_dma_tag_create(pci->parent_dmat, PAGE_SIZE, lim,
878222bb542SMatt Jacob 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, len, 1,
879222bb542SMatt Jacob 	    BUS_SPACE_MAXSIZE_32BIT, 0, &pci->cntrol_dmat) != 0) {
880f7dddf8aSMatt Jacob 		isp_prt(isp, ISP_LOGERR,
881f7dddf8aSMatt Jacob 		    "cannot create a dma tag for control spaces");
882a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
883a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
884d720e6d5SJustin T. Gibbs 		return (1);
885d720e6d5SJustin T. Gibbs 	}
886d720e6d5SJustin T. Gibbs 	if (bus_dmamem_alloc(pci->cntrol_dmat, (void **)&base,
887d720e6d5SJustin T. Gibbs 	    BUS_DMA_NOWAIT, &pci->cntrol_dmap) != 0) {
888f7dddf8aSMatt Jacob 		isp_prt(isp, ISP_LOGERR,
889f7dddf8aSMatt Jacob 		    "cannot allocate %d bytes of CCB memory");
890a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
891a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
892d720e6d5SJustin T. Gibbs 		return (1);
893d720e6d5SJustin T. Gibbs 	}
894d720e6d5SJustin T. Gibbs 
895d720e6d5SJustin T. Gibbs 	isp->isp_rquest = base;
896222bb542SMatt Jacob 	im.isp = isp;
897222bb542SMatt Jacob 	im.error = 0;
898d720e6d5SJustin T. Gibbs 	bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_rquest,
899d02373f1SMatt Jacob 	    ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)), isp_map_rquest, &im, 0);
900222bb542SMatt Jacob 	if (im.error) {
901f7dddf8aSMatt Jacob 		isp_prt(isp, ISP_LOGERR,
902f7dddf8aSMatt Jacob 		    "error %d loading dma map for DMA request queue", im.error);
903a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
904a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
905a95ae193SMatt Jacob 		isp->isp_rquest = NULL;
906222bb542SMatt Jacob 		return (1);
907222bb542SMatt Jacob 	}
908d02373f1SMatt Jacob 	isp->isp_result = base + ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
909222bb542SMatt Jacob 	im.error = 0;
910d720e6d5SJustin T. Gibbs 	bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_result,
911d02373f1SMatt Jacob 	    ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)), isp_map_result, &im, 0);
912222bb542SMatt Jacob 	if (im.error) {
913f7dddf8aSMatt Jacob 		isp_prt(isp, ISP_LOGERR,
914f7dddf8aSMatt Jacob 		    "error %d loading dma map for DMA result queue", 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 
921a95ae193SMatt Jacob 	for (i = 0; i < isp->isp_maxcmds; i++) {
922d720e6d5SJustin T. Gibbs 		error = bus_dmamap_create(pci->parent_dmat, 0, &pci->dmaps[i]);
923d720e6d5SJustin T. Gibbs 		if (error) {
924f7dddf8aSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
925f7dddf8aSMatt Jacob 			    "error %d creating per-cmd DMA maps", error);
926a95ae193SMatt Jacob 			free(isp->isp_xflist, M_DEVBUF);
927a95ae193SMatt Jacob 			free(pci->dmaps, M_DEVBUF);
928a95ae193SMatt Jacob 			isp->isp_rquest = NULL;
929d720e6d5SJustin T. Gibbs 			return (1);
930d720e6d5SJustin T. Gibbs 		}
931d720e6d5SJustin T. Gibbs 	}
932a95ae193SMatt Jacob 
933222bb542SMatt Jacob 	if (IS_FC(isp)) {
93492c49d78SMatt Jacob 		fcparam *fcp = (fcparam *) isp->isp_param;
93592c49d78SMatt Jacob 		fcp->isp_scratch = base +
936d02373f1SMatt Jacob 			ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)) +
937d02373f1SMatt Jacob 			ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
938222bb542SMatt Jacob 		im.error = 0;
93992c49d78SMatt Jacob 		bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap,
940222bb542SMatt Jacob 		    fcp->isp_scratch, ISP2100_SCRLEN, isp_map_fcscrt, &im, 0);
941222bb542SMatt Jacob 		if (im.error) {
942f7dddf8aSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
943f7dddf8aSMatt Jacob 			    "error %d loading FC scratch area", im.error);
944a95ae193SMatt Jacob 			free(isp->isp_xflist, M_DEVBUF);
945a95ae193SMatt Jacob 			free(pci->dmaps, M_DEVBUF);
946a95ae193SMatt Jacob 			isp->isp_rquest = NULL;
947222bb542SMatt Jacob 			return (1);
948222bb542SMatt Jacob 		}
94992c49d78SMatt Jacob 	}
950d720e6d5SJustin T. Gibbs 	return (0);
951d720e6d5SJustin T. Gibbs }
952d720e6d5SJustin T. Gibbs 
953d720e6d5SJustin T. Gibbs typedef struct {
954d720e6d5SJustin T. Gibbs 	struct ispsoftc *isp;
9559e11e5beSMatt Jacob 	void *cmd_token;
9569e11e5beSMatt Jacob 	void *rq;
9579637d68cSMatt Jacob 	u_int16_t *iptrp;
9589637d68cSMatt Jacob 	u_int16_t optr;
959d720e6d5SJustin T. Gibbs 	u_int error;
960d720e6d5SJustin T. Gibbs } mush_t;
961d720e6d5SJustin T. Gibbs 
9624873663cSMatt Jacob #define	MUSHERR_NOQENTRIES	-2
9634873663cSMatt Jacob 
9649e11e5beSMatt Jacob #ifdef	ISP_TARGET_MODE
9659e11e5beSMatt Jacob /*
9669e11e5beSMatt Jacob  * We need to handle DMA for target mode differently from initiator mode.
9679e11e5beSMatt Jacob  *
9689e11e5beSMatt Jacob  * DMA mapping and construction and submission of CTIO Request Entries
9699e11e5beSMatt Jacob  * and rendevous for completion are very tightly coupled because we start
9709e11e5beSMatt Jacob  * out by knowing (per platform) how much data we have to move, but we
9719e11e5beSMatt Jacob  * don't know, up front, how many DMA mapping segments will have to be used
9729e11e5beSMatt Jacob  * cover that data, so we don't know how many CTIO Request Entries we
9739e11e5beSMatt Jacob  * will end up using. Further, for performance reasons we may want to
9749e11e5beSMatt Jacob  * (on the last CTIO for Fibre Channel), send status too (if all went well).
9759e11e5beSMatt Jacob  *
9769e11e5beSMatt Jacob  * The standard vector still goes through isp_pci_dmasetup, but the callback
9779e11e5beSMatt Jacob  * for the DMA mapping routines comes here instead with the whole transfer
9789e11e5beSMatt Jacob  * mapped and a pointer to a partially filled in already allocated request
9799e11e5beSMatt Jacob  * queue entry. We finish the job.
9809e11e5beSMatt Jacob  */
98105fbcbb0SMatt Jacob static void tdma_mk __P((void *, bus_dma_segment_t *, int, int));
98205fbcbb0SMatt Jacob static void tdma_mkfc __P((void *, bus_dma_segment_t *, int, int));
9839e11e5beSMatt Jacob 
984d720e6d5SJustin T. Gibbs static void
98505fbcbb0SMatt Jacob tdma_mk(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
986d720e6d5SJustin T. Gibbs {
987d720e6d5SJustin T. Gibbs 	mush_t *mp;
9889e11e5beSMatt Jacob 	struct ccb_scsiio *csio;
989d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci;
990d720e6d5SJustin T. Gibbs 	bus_dmamap_t *dp;
99105fbcbb0SMatt Jacob 	u_int8_t scsi_status;
9929e11e5beSMatt Jacob 	ct_entry_t *cto;
99305fbcbb0SMatt Jacob 	u_int32_t handle, totxfr, sflags;
99405fbcbb0SMatt Jacob 	int nctios, send_status;
99505fbcbb0SMatt Jacob 	int32_t resid;
996d720e6d5SJustin T. Gibbs 
997d720e6d5SJustin T. Gibbs 	mp = (mush_t *) arg;
998d720e6d5SJustin T. Gibbs 	if (error) {
999d720e6d5SJustin T. Gibbs 		mp->error = error;
1000d720e6d5SJustin T. Gibbs 		return;
1001d720e6d5SJustin T. Gibbs 	}
10029e11e5beSMatt Jacob 	csio = mp->cmd_token;
10039e11e5beSMatt Jacob 	cto = mp->rq;
10049e11e5beSMatt Jacob 
100565b024e1SMatt Jacob 	cto->ct_xfrlen = 0;
100665b024e1SMatt Jacob 	cto->ct_seg_count = 0;
100765b024e1SMatt Jacob 	cto->ct_header.rqs_entry_count = 1;
100805fbcbb0SMatt Jacob 	MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg));
100905fbcbb0SMatt Jacob 
101005fbcbb0SMatt Jacob 	if (nseg == 0) {
101105fbcbb0SMatt Jacob 		cto->ct_header.rqs_seqno = 1;
101205fbcbb0SMatt Jacob 		ISP_TDQE(mp->isp, "tdma_mk[no data]", *mp->iptrp, cto);
1013d02373f1SMatt Jacob 		isp_prt(mp->isp, ISP_LOGTDEBUG1,
1014d02373f1SMatt Jacob 		    "CTIO lun %d->iid%d flgs 0x%x sts 0x%x ssts 0x%x res %d",
101565b024e1SMatt Jacob 		    csio->ccb_h.target_lun, cto->ct_iid, cto->ct_flags,
101665b024e1SMatt Jacob 		    cto->ct_status, cto->ct_scsi_status, cto->ct_resid);
101705fbcbb0SMatt Jacob 		ISP_SWIZ_CTIO(mp->isp, cto, cto);
101865b024e1SMatt Jacob 		return;
101965b024e1SMatt Jacob 	}
102065b024e1SMatt Jacob 
102165b024e1SMatt Jacob 	nctios = nseg / ISP_RQDSEG;
102265b024e1SMatt Jacob 	if (nseg % ISP_RQDSEG) {
102365b024e1SMatt Jacob 		nctios++;
102465b024e1SMatt Jacob 	}
102565b024e1SMatt Jacob 
102605fbcbb0SMatt Jacob 	/*
102705fbcbb0SMatt Jacob 	 * Save handle, and potentially any SCSI status, which we'll reinsert
102805fbcbb0SMatt Jacob 	 * on the last CTIO we're going to send.
102905fbcbb0SMatt Jacob 	 */
103005fbcbb0SMatt Jacob 	handle = cto->ct_reserved;
103105fbcbb0SMatt Jacob 	cto->ct_reserved = 0;
103205fbcbb0SMatt Jacob 	cto->ct_header.rqs_seqno = 0;
103305fbcbb0SMatt Jacob 	send_status = (cto->ct_flags & CT_SENDSTATUS) != 0;
103405fbcbb0SMatt Jacob 
103505fbcbb0SMatt Jacob 	if (send_status) {
103605fbcbb0SMatt Jacob 		sflags = cto->ct_flags & (CT_SENDSTATUS | CT_CCINCR);
103705fbcbb0SMatt Jacob 		cto->ct_flags &= ~(CT_SENDSTATUS | CT_CCINCR);
103805fbcbb0SMatt Jacob 		/*
103905fbcbb0SMatt Jacob 		 * Preserve residual.
104005fbcbb0SMatt Jacob 		 */
104105fbcbb0SMatt Jacob 		resid = cto->ct_resid;
104205fbcbb0SMatt Jacob 
104305fbcbb0SMatt Jacob 		/*
104405fbcbb0SMatt Jacob 		 * Save actual SCSI status.
104505fbcbb0SMatt Jacob 		 */
104605fbcbb0SMatt Jacob 		scsi_status = cto->ct_scsi_status;
104705fbcbb0SMatt Jacob 
104805fbcbb0SMatt Jacob 		/*
104905fbcbb0SMatt Jacob 		 * We can't do a status at the same time as a data CTIO, so
105005fbcbb0SMatt Jacob 		 * we need to synthesize an extra CTIO at this level.
105105fbcbb0SMatt Jacob 		 */
105205fbcbb0SMatt Jacob 		nctios++;
105305fbcbb0SMatt Jacob 	} else {
105405fbcbb0SMatt Jacob 		sflags = scsi_status = resid = 0;
105505fbcbb0SMatt Jacob 	}
105605fbcbb0SMatt Jacob 
105705fbcbb0SMatt Jacob 	totxfr = cto->ct_resid = 0;
105805fbcbb0SMatt Jacob 	cto->ct_scsi_status = 0;
105905fbcbb0SMatt Jacob 
10609e11e5beSMatt Jacob 	pci = (struct isp_pcisoftc *)mp->isp;
1061469b6b9eSMatt Jacob 	dp = &pci->dmaps[isp_handle_index(handle)];
10629e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1063d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
1064d720e6d5SJustin T. Gibbs 	} else {
1065d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
1066d720e6d5SJustin T. Gibbs 	}
1067d720e6d5SJustin T. Gibbs 
10689e11e5beSMatt Jacob 
10699e11e5beSMatt Jacob 	while (nctios--) {
107005fbcbb0SMatt Jacob 		int seglim;
10719e11e5beSMatt Jacob 
10729e11e5beSMatt Jacob 		seglim = nseg;
107305fbcbb0SMatt Jacob 		if (seglim) {
107405fbcbb0SMatt Jacob 			int seg;
107505fbcbb0SMatt Jacob 
10769e11e5beSMatt Jacob 			if (seglim > ISP_RQDSEG)
10779e11e5beSMatt Jacob 				seglim = ISP_RQDSEG;
10789e11e5beSMatt Jacob 
107905fbcbb0SMatt Jacob 			for (seg = 0; seg < seglim; seg++, nseg--) {
108005fbcbb0SMatt Jacob 				/*
108105fbcbb0SMatt Jacob 				 * Unlike normal initiator commands, we don't
108205fbcbb0SMatt Jacob 				 * do any swizzling here.
108305fbcbb0SMatt Jacob 				 */
10849e11e5beSMatt Jacob 				cto->ct_dataseg[seg].ds_count = dm_segs->ds_len;
108505fbcbb0SMatt Jacob 				cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr;
10869e11e5beSMatt Jacob 				cto->ct_xfrlen += dm_segs->ds_len;
108705fbcbb0SMatt Jacob 				totxfr += dm_segs->ds_len;
10889e11e5beSMatt Jacob 				dm_segs++;
10899e11e5beSMatt Jacob 			}
10909e11e5beSMatt Jacob 			cto->ct_seg_count = seg;
10919e11e5beSMatt Jacob 		} else {
109205fbcbb0SMatt Jacob 			/*
109305fbcbb0SMatt Jacob 			 * This case should only happen when we're sending an
109405fbcbb0SMatt Jacob 			 * extra CTIO with final status.
109505fbcbb0SMatt Jacob 			 */
109605fbcbb0SMatt Jacob 			if (send_status == 0) {
1097f7dddf8aSMatt Jacob 				isp_prt(mp->isp, ISP_LOGWARN,
1098f7dddf8aSMatt Jacob 				    "tdma_mk ran out of segments");
109905fbcbb0SMatt Jacob 				mp->error = EINVAL;
110005fbcbb0SMatt Jacob 				return;
11019e11e5beSMatt Jacob 			}
110205fbcbb0SMatt Jacob 		}
110305fbcbb0SMatt Jacob 
110405fbcbb0SMatt Jacob 		/*
110505fbcbb0SMatt Jacob 		 * At this point, the fields ct_lun, ct_iid, ct_tagval,
110605fbcbb0SMatt Jacob 		 * ct_tagtype, and ct_timeout have been carried over
110705fbcbb0SMatt Jacob 		 * unchanged from what our caller had set.
110805fbcbb0SMatt Jacob 		 *
110905fbcbb0SMatt Jacob 		 * The dataseg fields and the seg_count fields we just got
111005fbcbb0SMatt Jacob 		 * through setting. The data direction we've preserved all
111105fbcbb0SMatt Jacob 		 * along and only clear it if we're now sending status.
111205fbcbb0SMatt Jacob 		 */
11139e11e5beSMatt Jacob 
11149e11e5beSMatt Jacob 		if (nctios == 0) {
11159e11e5beSMatt Jacob 			/*
111605fbcbb0SMatt Jacob 			 * We're the last in a sequence of CTIOs, so mark
111705fbcbb0SMatt Jacob 			 * this CTIO and save the handle to the CCB such that
111805fbcbb0SMatt Jacob 			 * when this CTIO completes we can free dma resources
111905fbcbb0SMatt Jacob 			 * and do whatever else we need to do to finish the
112005fbcbb0SMatt Jacob 			 * rest of the command.
11219e11e5beSMatt Jacob 			 */
11229e11e5beSMatt Jacob 			cto->ct_reserved = handle;
112305fbcbb0SMatt Jacob 			cto->ct_header.rqs_seqno = 1;
112405fbcbb0SMatt Jacob 
112505fbcbb0SMatt Jacob 			if (send_status) {
11269e11e5beSMatt Jacob 				cto->ct_scsi_status = scsi_status;
112705fbcbb0SMatt Jacob 				cto->ct_flags |= sflags | CT_NO_DATA;;
112805fbcbb0SMatt Jacob 				cto->ct_resid = resid;
112942426921SMatt Jacob 			}
1130d02373f1SMatt Jacob 			if (send_status) {
1131d02373f1SMatt Jacob 				isp_prt(mp->isp, ISP_LOGTDEBUG1,
1132d02373f1SMatt Jacob 				    "CTIO lun%d for ID %d ct_flags 0x%x scsi "
1133d02373f1SMatt Jacob 				    "status %x resid %d",
1134d02373f1SMatt Jacob 				    csio->ccb_h.target_lun,
113505fbcbb0SMatt Jacob 				    cto->ct_iid, cto->ct_flags,
113605fbcbb0SMatt Jacob 				    cto->ct_scsi_status, cto->ct_resid);
1137d02373f1SMatt Jacob 			} else {
1138d02373f1SMatt Jacob 				isp_prt(mp->isp, ISP_LOGTDEBUG1,
1139d02373f1SMatt Jacob 				    "CTIO lun%d for ID%d ct_flags 0x%x",
1140d02373f1SMatt Jacob 				    csio->ccb_h.target_lun,
114105fbcbb0SMatt Jacob 				    cto->ct_iid, cto->ct_flags);
114205fbcbb0SMatt Jacob 			}
114305fbcbb0SMatt Jacob 			ISP_TDQE(mp->isp, "last tdma_mk", *mp->iptrp, cto);
114405fbcbb0SMatt Jacob 			ISP_SWIZ_CTIO(mp->isp, cto, cto);
11459e11e5beSMatt Jacob 		} else {
11469e11e5beSMatt Jacob 			ct_entry_t     *octo = cto;
114705fbcbb0SMatt Jacob 
114805fbcbb0SMatt Jacob 			/*
114905fbcbb0SMatt Jacob 			 * Make sure handle fields are clean
115005fbcbb0SMatt Jacob 			 */
11519e11e5beSMatt Jacob 			cto->ct_reserved = 0;
11529e11e5beSMatt Jacob 			cto->ct_header.rqs_seqno = 0;
115305fbcbb0SMatt Jacob 
1154d02373f1SMatt Jacob 			isp_prt(mp->isp, ISP_LOGTDEBUG1,
1155d02373f1SMatt Jacob 			    "CTIO lun%d for ID%d ct_flags 0x%x",
1156d02373f1SMatt Jacob 			    csio->ccb_h.target_lun, cto->ct_iid, cto->ct_flags);
115705fbcbb0SMatt Jacob 			ISP_TDQE(mp->isp, "tdma_mk", *mp->iptrp, cto);
115805fbcbb0SMatt Jacob 
115905fbcbb0SMatt Jacob 			/*
116005fbcbb0SMatt Jacob 			 * Get a new CTIO
116105fbcbb0SMatt Jacob 			 */
11629e11e5beSMatt Jacob 			cto = (ct_entry_t *)
11639e11e5beSMatt Jacob 			    ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
11649e11e5beSMatt Jacob 			*mp->iptrp =
1165d02373f1SMatt Jacob 			    ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp));
11669e11e5beSMatt Jacob 			if (*mp->iptrp == mp->optr) {
1167f7dddf8aSMatt Jacob 				isp_prt(mp->isp, ISP_LOGWARN,
1168f7dddf8aSMatt Jacob 				    "Queue Overflow in tdma_mk");
11699e11e5beSMatt Jacob 				mp->error = MUSHERR_NOQENTRIES;
11709e11e5beSMatt Jacob 				return;
11719e11e5beSMatt Jacob 			}
11729e11e5beSMatt Jacob 			/*
11739e11e5beSMatt Jacob 			 * Fill in the new CTIO with info from the old one.
11749e11e5beSMatt Jacob 			 */
11759e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
11769e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_count = 1;
11779e11e5beSMatt Jacob 			cto->ct_header.rqs_flags = 0;
11789e11e5beSMatt Jacob 			cto->ct_lun = octo->ct_lun;
11799e11e5beSMatt Jacob 			cto->ct_iid = octo->ct_iid;
11809e11e5beSMatt Jacob 			cto->ct_reserved2 = octo->ct_reserved2;
11819e11e5beSMatt Jacob 			cto->ct_tgt = octo->ct_tgt;
118205fbcbb0SMatt Jacob 			cto->ct_flags = octo->ct_flags;
11839e11e5beSMatt Jacob 			cto->ct_status = 0;
11849e11e5beSMatt Jacob 			cto->ct_scsi_status = 0;
11859e11e5beSMatt Jacob 			cto->ct_tag_val = octo->ct_tag_val;
11869e11e5beSMatt Jacob 			cto->ct_tag_type = octo->ct_tag_type;
11879e11e5beSMatt Jacob 			cto->ct_xfrlen = 0;
11889e11e5beSMatt Jacob 			cto->ct_resid = 0;
11899e11e5beSMatt Jacob 			cto->ct_timeout = octo->ct_timeout;
11909e11e5beSMatt Jacob 			cto->ct_seg_count = 0;
119105fbcbb0SMatt Jacob 			MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg));
119205fbcbb0SMatt Jacob 			/*
119305fbcbb0SMatt Jacob 			 * Now swizzle the old one for the consumption of the
119405fbcbb0SMatt Jacob 			 * chip.
119505fbcbb0SMatt Jacob 			 */
119605fbcbb0SMatt Jacob 			ISP_SWIZ_CTIO(mp->isp, octo, octo);
11979e11e5beSMatt Jacob 		}
11989e11e5beSMatt Jacob 	}
11999e11e5beSMatt Jacob }
12009e11e5beSMatt Jacob 
12019e11e5beSMatt Jacob static void
120205fbcbb0SMatt Jacob tdma_mkfc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
12039e11e5beSMatt Jacob {
12049e11e5beSMatt Jacob 	mush_t *mp;
12059e11e5beSMatt Jacob 	struct ccb_scsiio *csio;
12069e11e5beSMatt Jacob 	struct isp_pcisoftc *pci;
12079e11e5beSMatt Jacob 	bus_dmamap_t *dp;
12089e11e5beSMatt Jacob 	ct2_entry_t *cto;
120965b024e1SMatt Jacob 	u_int16_t scsi_status, send_status, send_sense;
121005fbcbb0SMatt Jacob 	u_int32_t handle, totxfr, datalen;
121165b024e1SMatt Jacob 	u_int8_t sense[QLTM_SENSELEN];
12129e11e5beSMatt Jacob 	int nctios;
12139e11e5beSMatt Jacob 
12149e11e5beSMatt Jacob 	mp = (mush_t *) arg;
12159e11e5beSMatt Jacob 	if (error) {
12169e11e5beSMatt Jacob 		mp->error = error;
12179e11e5beSMatt Jacob 		return;
12189e11e5beSMatt Jacob 	}
12199e11e5beSMatt Jacob 
122065b024e1SMatt Jacob 	csio = mp->cmd_token;
122165b024e1SMatt Jacob 	cto = mp->rq;
122265b024e1SMatt Jacob 
122365b024e1SMatt Jacob 	if (nseg == 0) {
122465b024e1SMatt Jacob 		if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE1) {
1225f7dddf8aSMatt Jacob 			isp_prt(mp->isp, ISP_LOGWARN,
1226f7dddf8aSMatt Jacob 			    "dma2_tgt_fc, a status CTIO2 without MODE1 "
1227f7dddf8aSMatt Jacob 			    "set (0x%x)", cto->ct_flags);
122865b024e1SMatt Jacob 			mp->error = EINVAL;
122965b024e1SMatt Jacob 			return;
123065b024e1SMatt Jacob 		}
123165b024e1SMatt Jacob 	 	cto->ct_header.rqs_entry_count = 1;
123205fbcbb0SMatt Jacob 		cto->ct_header.rqs_seqno = 1;
123365b024e1SMatt Jacob 		/* ct_reserved contains the handle set by caller */
123465b024e1SMatt Jacob 		/*
123565b024e1SMatt Jacob 		 * We preserve ct_lun, ct_iid, ct_rxid. We set the data
123665b024e1SMatt Jacob 		 * flags to NO DATA and clear relative offset flags.
123765b024e1SMatt Jacob 		 * We preserve the ct_resid and the response area.
123865b024e1SMatt Jacob 		 */
123965b024e1SMatt Jacob 		cto->ct_flags |= CT2_NO_DATA;
124005fbcbb0SMatt Jacob 		if (cto->ct_resid > 0)
124105fbcbb0SMatt Jacob 			cto->ct_flags |= CT2_DATA_UNDER;
124205fbcbb0SMatt Jacob 		else if (cto->ct_resid < 0)
124305fbcbb0SMatt Jacob 			cto->ct_flags |= CT2_DATA_OVER;
124465b024e1SMatt Jacob 		cto->ct_seg_count = 0;
124565b024e1SMatt Jacob 		cto->ct_reloff = 0;
124665b024e1SMatt Jacob 		ISP_TDQE(mp->isp, "dma2_tgt_fc[no data]", *mp->iptrp, cto);
1247d02373f1SMatt Jacob 		isp_prt(mp->isp, ISP_LOGTDEBUG1,
1248d02373f1SMatt Jacob 		    "CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x sts 0x%x ssts "
1249d02373f1SMatt Jacob 		    "0x%x res %d", cto->ct_rxid, csio->ccb_h.target_lun,
1250d02373f1SMatt Jacob 		    cto->ct_iid, cto->ct_flags, cto->ct_status,
125165b024e1SMatt Jacob 		    cto->rsp.m1.ct_scsi_status, cto->ct_resid);
125265b024e1SMatt Jacob 		ISP_SWIZ_CTIO2(isp, cto, cto);
12539e11e5beSMatt Jacob 		return;
12549e11e5beSMatt Jacob 	}
12559e11e5beSMatt Jacob 
125665b024e1SMatt Jacob 	if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE0) {
1257f7dddf8aSMatt Jacob 		isp_prt(mp->isp, ISP_LOGWARN,
1258f7dddf8aSMatt Jacob 		    "dma2_tgt_fc, a data CTIO2 without MODE0 set "
1259f7dddf8aSMatt Jacob 		    "(0x%x)", cto->ct_flags);
126065b024e1SMatt Jacob 		mp->error = EINVAL;
126165b024e1SMatt Jacob 		return;
126265b024e1SMatt Jacob 	}
126365b024e1SMatt Jacob 
126465b024e1SMatt Jacob 
126565b024e1SMatt Jacob 	nctios = nseg / ISP_RQDSEG_T2;
126665b024e1SMatt Jacob 	if (nseg % ISP_RQDSEG_T2) {
126765b024e1SMatt Jacob 		nctios++;
126865b024e1SMatt Jacob 	}
126965b024e1SMatt Jacob 
12709e11e5beSMatt Jacob 	/*
127165b024e1SMatt Jacob 	 * Save the handle, status, reloff, and residual. We'll reinsert the
127265b024e1SMatt Jacob 	 * handle into the last CTIO2 we're going to send, and reinsert status
127365b024e1SMatt Jacob 	 * and residual (and possibly sense data) if that's to be sent as well.
127465b024e1SMatt Jacob 	 *
127565b024e1SMatt Jacob 	 * We preserve ct_reloff and adjust it for each data CTIO2 we send past
127665b024e1SMatt Jacob 	 * the first one. This is needed so that the FCP DATA IUs being sent
127765b024e1SMatt Jacob 	 * out have the correct offset (they can arrive at the other end out
127865b024e1SMatt Jacob 	 * of order).
12799e11e5beSMatt Jacob 	 */
128065b024e1SMatt Jacob 
12819e11e5beSMatt Jacob 	handle = cto->ct_reserved;
12829e11e5beSMatt Jacob 	cto->ct_reserved = 0;
128365b024e1SMatt Jacob 
128465b024e1SMatt Jacob 	if ((send_status = (cto->ct_flags & CT2_SENDSTATUS)) != 0) {
12859e11e5beSMatt Jacob 		cto->ct_flags &= ~CT2_SENDSTATUS;
12869e11e5beSMatt Jacob 
128765b024e1SMatt Jacob 		/*
128805fbcbb0SMatt Jacob 		 * Preserve residual, which is actually the total count.
128965b024e1SMatt Jacob 		 */
129005fbcbb0SMatt Jacob 		datalen = cto->ct_resid;
129165b024e1SMatt Jacob 
129265b024e1SMatt Jacob 		/*
129365b024e1SMatt Jacob 		 * Save actual SCSI status. We'll reinsert the
129465b024e1SMatt Jacob 		 * CT2_SNSLEN_VALID later if appropriate.
129565b024e1SMatt Jacob 		 */
129665b024e1SMatt Jacob 		scsi_status = cto->rsp.m0.ct_scsi_status & 0xff;
129765b024e1SMatt Jacob 		send_sense = cto->rsp.m0.ct_scsi_status & CT2_SNSLEN_VALID;
129865b024e1SMatt Jacob 
129965b024e1SMatt Jacob 		/*
130065b024e1SMatt Jacob 		 * If we're sending status and have a CHECK CONDTION and
130165b024e1SMatt Jacob 		 * have sense data,  we send one more CTIO2 with just the
130265b024e1SMatt Jacob 		 * status and sense data. The upper layers have stashed
130365b024e1SMatt Jacob 		 * the sense data in the dataseg structure for us.
130465b024e1SMatt Jacob 		 */
130565b024e1SMatt Jacob 
130665b024e1SMatt Jacob 		if ((scsi_status & 0xf) == SCSI_STATUS_CHECK_COND &&
130765b024e1SMatt Jacob 		    send_sense) {
130865b024e1SMatt Jacob 			bcopy(cto->rsp.m0.ct_dataseg, sense, QLTM_SENSELEN);
130965b024e1SMatt Jacob 			nctios++;
131065b024e1SMatt Jacob 		}
131165b024e1SMatt Jacob 	} else {
131205fbcbb0SMatt Jacob 		scsi_status = send_sense = datalen = 0;
131365b024e1SMatt Jacob 	}
131465b024e1SMatt Jacob 
131565b024e1SMatt Jacob 	totxfr = cto->ct_resid = 0;
131665b024e1SMatt Jacob 	cto->rsp.m0.ct_scsi_status = 0;
131765b024e1SMatt Jacob 	bzero(&cto->rsp, sizeof (cto->rsp));
131865b024e1SMatt Jacob 
13199e11e5beSMatt Jacob 	pci = (struct isp_pcisoftc *)mp->isp;
1320469b6b9eSMatt Jacob 	dp = &pci->dmaps[isp_handle_index(handle)];
13219e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
13229e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
13239e11e5beSMatt Jacob 	} else {
13249e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
13259e11e5beSMatt Jacob 	}
13269e11e5beSMatt Jacob 
13279e11e5beSMatt Jacob 	while (nctios--) {
13289e11e5beSMatt Jacob 		int seg, seglim;
13299e11e5beSMatt Jacob 
13309e11e5beSMatt Jacob 		seglim = nseg;
133165b024e1SMatt Jacob 		if (seglim) {
13329e11e5beSMatt Jacob 			if (seglim > ISP_RQDSEG_T2)
13339e11e5beSMatt Jacob 				seglim = ISP_RQDSEG_T2;
13349e11e5beSMatt Jacob 
13359e11e5beSMatt Jacob 			for (seg = 0; seg < seglim; seg++) {
133665b024e1SMatt Jacob 				cto->rsp.m0.ct_dataseg[seg].ds_base =
133765b024e1SMatt Jacob 				    dm_segs->ds_addr;
133865b024e1SMatt Jacob 				cto->rsp.m0.ct_dataseg[seg].ds_count =
133965b024e1SMatt Jacob 				    dm_segs->ds_len;
13409e11e5beSMatt Jacob 				cto->rsp.m0.ct_xfrlen += dm_segs->ds_len;
134165b024e1SMatt Jacob 				totxfr += dm_segs->ds_len;
13429e11e5beSMatt Jacob 				dm_segs++;
13439e11e5beSMatt Jacob 			}
13449e11e5beSMatt Jacob 			cto->ct_seg_count = seg;
13459e11e5beSMatt Jacob 		} else {
134665b024e1SMatt Jacob 			/*
134765b024e1SMatt Jacob 			 * This case should only happen when we're sending a
134865b024e1SMatt Jacob 			 * synthesized MODE1 final status with sense data.
134965b024e1SMatt Jacob 			 */
135065b024e1SMatt Jacob 			if (send_sense == 0) {
1351f7dddf8aSMatt Jacob 				isp_prt(mp->isp, ISP_LOGWARN,
1352f7dddf8aSMatt Jacob 				    "dma2_tgt_fc ran out of segments, "
1353f7dddf8aSMatt Jacob 				    "no SENSE DATA");
135465b024e1SMatt Jacob 				mp->error = EINVAL;
135565b024e1SMatt Jacob 				return;
135665b024e1SMatt Jacob 			}
13579e11e5beSMatt Jacob 		}
13589e11e5beSMatt Jacob 
13599e11e5beSMatt Jacob 		/*
136065b024e1SMatt Jacob 		 * At this point, the fields ct_lun, ct_iid, ct_rxid,
136165b024e1SMatt Jacob 		 * ct_timeout have been carried over unchanged from what
136265b024e1SMatt Jacob 		 * our caller had set.
136365b024e1SMatt Jacob 		 *
136465b024e1SMatt Jacob 		 * The field ct_reloff is either what the caller set, or
136565b024e1SMatt Jacob 		 * what we've added to below.
136665b024e1SMatt Jacob 		 *
136765b024e1SMatt Jacob 		 * The dataseg fields and the seg_count fields we just got
136865b024e1SMatt Jacob 		 * through setting. The data direction we've preserved all
136965b024e1SMatt Jacob 		 * along and only clear it if we're sending a MODE1 status
137065b024e1SMatt Jacob 		 * as the last CTIO.
137165b024e1SMatt Jacob 		 *
137265b024e1SMatt Jacob 		 */
137365b024e1SMatt Jacob 
137465b024e1SMatt Jacob 		if (nctios == 0) {
137565b024e1SMatt Jacob 
137665b024e1SMatt Jacob 			/*
137765b024e1SMatt Jacob 			 * We're the last in a sequence of CTIO2s, so mark this
137865b024e1SMatt Jacob 			 * CTIO2 and save the handle to the CCB such that when
137965b024e1SMatt Jacob 			 * this CTIO2 completes we can free dma resources and
13809e11e5beSMatt Jacob 			 * do whatever else we need to do to finish the rest
13819e11e5beSMatt Jacob 			 * of the command.
13829e11e5beSMatt Jacob 			 */
138365b024e1SMatt Jacob 
13849e11e5beSMatt Jacob 			cto->ct_reserved = handle;
138565b024e1SMatt Jacob 			cto->ct_header.rqs_seqno = 1;
138665b024e1SMatt Jacob 
138765b024e1SMatt Jacob 			if (send_status) {
138865b024e1SMatt Jacob 				if (send_sense) {
138965b024e1SMatt Jacob 					bcopy(sense, cto->rsp.m1.ct_resp,
139065b024e1SMatt Jacob 					    QLTM_SENSELEN);
139165b024e1SMatt Jacob 					cto->rsp.m1.ct_senselen =
139265b024e1SMatt Jacob 					    QLTM_SENSELEN;
139365b024e1SMatt Jacob 					scsi_status |= CT2_SNSLEN_VALID;
139465b024e1SMatt Jacob 					cto->rsp.m1.ct_scsi_status =
139565b024e1SMatt Jacob 					    scsi_status;
139665b024e1SMatt Jacob 					cto->ct_flags &= CT2_FLAG_MMASK;
139765b024e1SMatt Jacob 					cto->ct_flags |= CT2_FLAG_MODE1 |
139865b024e1SMatt Jacob 					    CT2_NO_DATA| CT2_SENDSTATUS;
139965b024e1SMatt Jacob 				} else {
140065b024e1SMatt Jacob 					cto->rsp.m0.ct_scsi_status =
140165b024e1SMatt Jacob 					    scsi_status;
140265b024e1SMatt Jacob 					cto->ct_flags |= CT2_SENDSTATUS;
140365b024e1SMatt Jacob 				}
140405fbcbb0SMatt Jacob 				/*
140505fbcbb0SMatt Jacob 				 * Get 'real' residual and set flags based
140605fbcbb0SMatt Jacob 				 * on it.
140705fbcbb0SMatt Jacob 				 */
140805fbcbb0SMatt Jacob 				cto->ct_resid = datalen - totxfr;
140905fbcbb0SMatt Jacob 				if (cto->ct_resid > 0)
141005fbcbb0SMatt Jacob 					cto->ct_flags |= CT2_DATA_UNDER;
141105fbcbb0SMatt Jacob 				else if (cto->ct_resid < 0)
141205fbcbb0SMatt Jacob 					cto->ct_flags |= CT2_DATA_OVER;
141365b024e1SMatt Jacob 			}
14149e11e5beSMatt Jacob 			ISP_TDQE(mp->isp, "last dma2_tgt_fc", *mp->iptrp, cto);
1415d02373f1SMatt Jacob 			isp_prt(mp->isp, ISP_LOGTDEBUG1,
1416d02373f1SMatt Jacob 			    "CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x sts 0x%x"
1417d02373f1SMatt Jacob 			    " ssts 0x%x res %d", cto->ct_rxid,
141865b024e1SMatt Jacob 			    csio->ccb_h.target_lun, (int) cto->ct_iid,
141942426921SMatt Jacob 			    cto->ct_flags, cto->ct_status,
142065b024e1SMatt Jacob 			    cto->rsp.m1.ct_scsi_status, cto->ct_resid);
142165b024e1SMatt Jacob 			ISP_SWIZ_CTIO2(isp, cto, cto);
14229e11e5beSMatt Jacob 		} else {
14239e11e5beSMatt Jacob 			ct2_entry_t *octo = cto;
142465b024e1SMatt Jacob 
142565b024e1SMatt Jacob 			/*
142665b024e1SMatt Jacob 			 * Make sure handle fields are clean
142765b024e1SMatt Jacob 			 */
14289e11e5beSMatt Jacob 			cto->ct_reserved = 0;
14299e11e5beSMatt Jacob 			cto->ct_header.rqs_seqno = 0;
143065b024e1SMatt Jacob 
14319e11e5beSMatt Jacob 			ISP_TDQE(mp->isp, "dma2_tgt_fc", *mp->iptrp, cto);
1432d02373f1SMatt Jacob 			isp_prt(mp->isp, ISP_LOGTDEBUG1,
1433d02373f1SMatt Jacob 			    "CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x",
1434d02373f1SMatt Jacob 			    cto->ct_rxid, csio->ccb_h.target_lun,
1435d02373f1SMatt Jacob 			    (int) cto->ct_iid, cto->ct_flags);
143665b024e1SMatt Jacob 			/*
143765b024e1SMatt Jacob 			 * Get a new CTIO2
143865b024e1SMatt Jacob 			 */
14399e11e5beSMatt Jacob 			cto = (ct2_entry_t *)
14409e11e5beSMatt Jacob 			    ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
14419e11e5beSMatt Jacob 			*mp->iptrp =
1442d02373f1SMatt Jacob 			    ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp));
14439e11e5beSMatt Jacob 			if (*mp->iptrp == mp->optr) {
1444f7dddf8aSMatt Jacob 				isp_prt(mp->isp, ISP_LOGWARN,
1445f7dddf8aSMatt Jacob 				    "Queue Overflow in dma2_tgt_fc");
14469e11e5beSMatt Jacob 				mp->error = MUSHERR_NOQENTRIES;
14479e11e5beSMatt Jacob 				return;
14489e11e5beSMatt Jacob 			}
144965b024e1SMatt Jacob 
14509e11e5beSMatt Jacob 			/*
145165b024e1SMatt Jacob 			 * Fill in the new CTIO2 with info from the old one.
14529e11e5beSMatt Jacob 			 */
14539e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
14549e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_count = 1;
14559e11e5beSMatt Jacob 			cto->ct_header.rqs_flags = 0;
145665b024e1SMatt Jacob 			/* ct_header.rqs_seqno && ct_reserved done later */
14579e11e5beSMatt Jacob 			cto->ct_lun = octo->ct_lun;
14589e11e5beSMatt Jacob 			cto->ct_iid = octo->ct_iid;
14599e11e5beSMatt Jacob 			cto->ct_rxid = octo->ct_rxid;
146065b024e1SMatt Jacob 			cto->ct_flags = octo->ct_flags;
14619e11e5beSMatt Jacob 			cto->ct_status = 0;
14629e11e5beSMatt Jacob 			cto->ct_resid = 0;
14639e11e5beSMatt Jacob 			cto->ct_timeout = octo->ct_timeout;
14649e11e5beSMatt Jacob 			cto->ct_seg_count = 0;
146565b024e1SMatt Jacob 			/*
146665b024e1SMatt Jacob 			 * Adjust the new relative offset by the amount which
146765b024e1SMatt Jacob 			 * is recorded in the data segment of the old CTIO2 we
146865b024e1SMatt Jacob 			 * just finished filling out.
146965b024e1SMatt Jacob 			 */
147065b024e1SMatt Jacob 			cto->ct_reloff += octo->rsp.m0.ct_xfrlen;
14719e11e5beSMatt Jacob 			bzero(&cto->rsp, sizeof (cto->rsp));
147265b024e1SMatt Jacob 			ISP_SWIZ_CTIO2(isp, cto, cto);
14739e11e5beSMatt Jacob 		}
14749e11e5beSMatt Jacob 	}
14759e11e5beSMatt Jacob }
14769e11e5beSMatt Jacob #endif
14779e11e5beSMatt Jacob 
14789e11e5beSMatt Jacob static void dma2 __P((void *, bus_dma_segment_t *, int, int));
14799e11e5beSMatt Jacob 
14809e11e5beSMatt Jacob static void
14819e11e5beSMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
14829e11e5beSMatt Jacob {
14839e11e5beSMatt Jacob 	mush_t *mp;
14849e11e5beSMatt Jacob 	struct ccb_scsiio *csio;
14859e11e5beSMatt Jacob 	struct isp_pcisoftc *pci;
14869e11e5beSMatt Jacob 	bus_dmamap_t *dp;
14879e11e5beSMatt Jacob 	bus_dma_segment_t *eseg;
14889e11e5beSMatt Jacob 	ispreq_t *rq;
14899e11e5beSMatt Jacob 	ispcontreq_t *crq;
14909e11e5beSMatt Jacob 	int seglim, datalen;
14919e11e5beSMatt Jacob 
14929e11e5beSMatt Jacob 	mp = (mush_t *) arg;
14939e11e5beSMatt Jacob 	if (error) {
14949e11e5beSMatt Jacob 		mp->error = error;
14959e11e5beSMatt Jacob 		return;
14969e11e5beSMatt Jacob 	}
14979e11e5beSMatt Jacob 
14989e11e5beSMatt Jacob 	if (nseg < 1) {
1499f7dddf8aSMatt Jacob 		isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg);
15009e11e5beSMatt Jacob 		mp->error = EFAULT;
15019e11e5beSMatt Jacob 		return;
15029e11e5beSMatt Jacob 	}
15039e11e5beSMatt Jacob 	csio = mp->cmd_token;
15049e11e5beSMatt Jacob 	rq = mp->rq;
15059e11e5beSMatt Jacob 	pci = (struct isp_pcisoftc *)mp->isp;
1506469b6b9eSMatt Jacob 	dp = &pci->dmaps[isp_handle_index(rq->req_handle)];
15079e11e5beSMatt Jacob 
15089e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
15099e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
15109e11e5beSMatt Jacob 	} else {
15119e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
15129e11e5beSMatt Jacob 	}
15139e11e5beSMatt Jacob 
15149e11e5beSMatt Jacob 	datalen = XS_XFRLEN(csio);
15159e11e5beSMatt Jacob 
15169e11e5beSMatt Jacob 	/*
15179e11e5beSMatt Jacob 	 * We're passed an initial partially filled in entry that
15189e11e5beSMatt Jacob 	 * has most fields filled in except for data transfer
15199e11e5beSMatt Jacob 	 * related values.
15209e11e5beSMatt Jacob 	 *
15219e11e5beSMatt Jacob 	 * Our job is to fill in the initial request queue entry and
15229e11e5beSMatt Jacob 	 * then to start allocating and filling in continuation entries
15239e11e5beSMatt Jacob 	 * until we've covered the entire transfer.
15249e11e5beSMatt Jacob 	 */
15259e11e5beSMatt Jacob 
15269e11e5beSMatt Jacob 	if (IS_FC(mp->isp)) {
1527d720e6d5SJustin T. Gibbs 		seglim = ISP_RQDSEG_T2;
1528d720e6d5SJustin T. Gibbs 		((ispreqt2_t *)rq)->req_totalcnt = datalen;
15299e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
15309e11e5beSMatt Jacob 			((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_IN;
15319e11e5beSMatt Jacob 		} else {
15329e11e5beSMatt Jacob 			((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_OUT;
15339e11e5beSMatt Jacob 		}
1534d720e6d5SJustin T. Gibbs 	} else {
1535e142669aSMatt Jacob 		if (csio->cdb_len > 12) {
1536e142669aSMatt Jacob 			seglim = 0;
1537e142669aSMatt Jacob 		} else {
1538d720e6d5SJustin T. Gibbs 			seglim = ISP_RQDSEG;
1539e142669aSMatt Jacob 		}
15409e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
15419e11e5beSMatt Jacob 			rq->req_flags |= REQFLAG_DATA_IN;
15429e11e5beSMatt Jacob 		} else {
15439e11e5beSMatt Jacob 			rq->req_flags |= REQFLAG_DATA_OUT;
15449e11e5beSMatt Jacob 		}
1545d720e6d5SJustin T. Gibbs 	}
1546d720e6d5SJustin T. Gibbs 
1547d720e6d5SJustin T. Gibbs 	eseg = dm_segs + nseg;
1548d720e6d5SJustin T. Gibbs 
1549d720e6d5SJustin T. Gibbs 	while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) {
15509e11e5beSMatt Jacob 		if (IS_FC(mp->isp)) {
1551d720e6d5SJustin T. Gibbs 			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
1552d720e6d5SJustin T. Gibbs 			rq2->req_dataseg[rq2->req_seg_count].ds_base =
1553d720e6d5SJustin T. Gibbs 			    dm_segs->ds_addr;
1554d720e6d5SJustin T. Gibbs 			rq2->req_dataseg[rq2->req_seg_count].ds_count =
1555d720e6d5SJustin T. Gibbs 			    dm_segs->ds_len;
1556d720e6d5SJustin T. Gibbs 		} else {
1557d720e6d5SJustin T. Gibbs 			rq->req_dataseg[rq->req_seg_count].ds_base =
1558d720e6d5SJustin T. Gibbs 				dm_segs->ds_addr;
1559d720e6d5SJustin T. Gibbs 			rq->req_dataseg[rq->req_seg_count].ds_count =
1560d720e6d5SJustin T. Gibbs 				dm_segs->ds_len;
1561d720e6d5SJustin T. Gibbs 		}
1562d720e6d5SJustin T. Gibbs 		datalen -= dm_segs->ds_len;
1563d720e6d5SJustin T. Gibbs #if	0
15649e11e5beSMatt Jacob 		if (IS_FC(mp->isp)) {
1565d720e6d5SJustin T. Gibbs 			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
1566d720e6d5SJustin T. Gibbs 			printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n",
15679e11e5beSMatt Jacob 			    mp->isp->isp_name, rq->req_seg_count,
1568d720e6d5SJustin T. Gibbs 			    rq2->req_dataseg[rq2->req_seg_count].ds_count,
1569d720e6d5SJustin T. Gibbs 			    rq2->req_dataseg[rq2->req_seg_count].ds_base);
1570d720e6d5SJustin T. Gibbs 		} else {
1571d720e6d5SJustin T. Gibbs 			printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n",
15729e11e5beSMatt Jacob 			    mp->isp->isp_name, rq->req_seg_count,
1573d720e6d5SJustin T. Gibbs 			    rq->req_dataseg[rq->req_seg_count].ds_count,
1574d720e6d5SJustin T. Gibbs 			    rq->req_dataseg[rq->req_seg_count].ds_base);
1575d720e6d5SJustin T. Gibbs 		}
1576d720e6d5SJustin T. Gibbs #endif
1577d720e6d5SJustin T. Gibbs 		rq->req_seg_count++;
1578d720e6d5SJustin T. Gibbs 		dm_segs++;
1579d720e6d5SJustin T. Gibbs 	}
1580d720e6d5SJustin T. Gibbs 
1581d720e6d5SJustin T. Gibbs 	while (datalen > 0 && dm_segs != eseg) {
15829e11e5beSMatt Jacob 		crq = (ispcontreq_t *)
15839e11e5beSMatt Jacob 		    ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
1584d02373f1SMatt Jacob 		*mp->iptrp = ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp));
15859e11e5beSMatt Jacob 		if (*mp->iptrp == mp->optr) {
15864873663cSMatt Jacob #if	0
15879e11e5beSMatt Jacob 			printf("%s: Request Queue Overflow++\n",
15889e11e5beSMatt Jacob 			    mp->isp->isp_name);
15894873663cSMatt Jacob #endif
15904873663cSMatt Jacob 			mp->error = MUSHERR_NOQENTRIES;
1591d720e6d5SJustin T. Gibbs 			return;
1592d720e6d5SJustin T. Gibbs 		}
1593d720e6d5SJustin T. Gibbs 		rq->req_header.rqs_entry_count++;
1594d720e6d5SJustin T. Gibbs 		bzero((void *)crq, sizeof (*crq));
1595d720e6d5SJustin T. Gibbs 		crq->req_header.rqs_entry_count = 1;
1596d720e6d5SJustin T. Gibbs 		crq->req_header.rqs_entry_type = RQSTYPE_DATASEG;
1597d720e6d5SJustin T. Gibbs 
1598d720e6d5SJustin T. Gibbs 		seglim = 0;
1599d720e6d5SJustin T. Gibbs 		while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) {
1600d720e6d5SJustin T. Gibbs 			crq->req_dataseg[seglim].ds_base =
1601d720e6d5SJustin T. Gibbs 			    dm_segs->ds_addr;
1602d720e6d5SJustin T. Gibbs 			crq->req_dataseg[seglim].ds_count =
1603d720e6d5SJustin T. Gibbs 			    dm_segs->ds_len;
1604d720e6d5SJustin T. Gibbs #if	0
1605d720e6d5SJustin T. Gibbs 			printf("%s: seg%d[%d] cnt 0x%x paddr 0x%08x\n",
16069e11e5beSMatt Jacob 			    mp->isp->isp_name, rq->req_header.rqs_entry_count-1,
1607d720e6d5SJustin T. Gibbs 			    seglim, crq->req_dataseg[seglim].ds_count,
1608d720e6d5SJustin T. Gibbs 			    crq->req_dataseg[seglim].ds_base);
1609d720e6d5SJustin T. Gibbs #endif
1610d720e6d5SJustin T. Gibbs 			rq->req_seg_count++;
1611d720e6d5SJustin T. Gibbs 			dm_segs++;
1612d720e6d5SJustin T. Gibbs 			seglim++;
1613d720e6d5SJustin T. Gibbs 			datalen -= dm_segs->ds_len;
1614d720e6d5SJustin T. Gibbs 		}
1615d720e6d5SJustin T. Gibbs 	}
1616d720e6d5SJustin T. Gibbs }
1617d720e6d5SJustin T. Gibbs 
1618d720e6d5SJustin T. Gibbs static int
16199e11e5beSMatt Jacob isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq,
16209637d68cSMatt Jacob 	u_int16_t *iptrp, u_int16_t optr)
1621d720e6d5SJustin T. Gibbs {
1622d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
16230a5f7e8bSMatt Jacob 	bus_dmamap_t *dp = NULL;
1624d720e6d5SJustin T. Gibbs 	mush_t mush, *mp;
16259e11e5beSMatt Jacob 	void (*eptr) __P((void *, bus_dma_segment_t *, int, int));
1626d720e6d5SJustin T. Gibbs 
162765b024e1SMatt Jacob #ifdef	ISP_TARGET_MODE
162865b024e1SMatt Jacob 	if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) {
162965b024e1SMatt Jacob 		if (IS_FC(isp)) {
163005fbcbb0SMatt Jacob 			eptr = tdma_mkfc;
163165b024e1SMatt Jacob 		} else {
163205fbcbb0SMatt Jacob 			eptr = tdma_mk;
163365b024e1SMatt Jacob 		}
163405fbcbb0SMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE ||
163505fbcbb0SMatt Jacob 		    (csio->dxfer_len == 0)) {
163665b024e1SMatt Jacob 			rq->req_seg_count = 1;
163765b024e1SMatt Jacob 			mp = &mush;
163865b024e1SMatt Jacob 			mp->isp = isp;
163965b024e1SMatt Jacob 			mp->cmd_token = csio;
164065b024e1SMatt Jacob 			mp->rq = rq;
164165b024e1SMatt Jacob 			mp->iptrp = iptrp;
164265b024e1SMatt Jacob 			mp->optr = optr;
164365b024e1SMatt Jacob 			mp->error = 0;
164465b024e1SMatt Jacob 			(*eptr)(mp, NULL, 0, 0);
164565b024e1SMatt Jacob 			goto exit;
164665b024e1SMatt Jacob 		}
164765b024e1SMatt Jacob 	} else
164865b024e1SMatt Jacob #endif
164965b024e1SMatt Jacob 	eptr = dma2;
165065b024e1SMatt Jacob 
165142426921SMatt Jacob 	/*
165242426921SMatt Jacob 	 * NB: if we need to do request queue entry swizzling,
165342426921SMatt Jacob 	 * NB: this is where it would need to be done for cmds
165442426921SMatt Jacob 	 * NB: that move no data. For commands that move data,
165542426921SMatt Jacob 	 * NB: swizzling would take place in those functions.
165642426921SMatt Jacob 	 */
165705fbcbb0SMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE ||
165805fbcbb0SMatt Jacob 	    (csio->dxfer_len == 0)) {
165942426921SMatt Jacob 		rq->req_seg_count = 1;
166042426921SMatt Jacob 		return (CMD_QUEUED);
166142426921SMatt Jacob 	}
166242426921SMatt Jacob 
1663d720e6d5SJustin T. Gibbs 	/*
1664d720e6d5SJustin T. Gibbs 	 * Do a virtual grapevine step to collect info for
16654873663cSMatt Jacob 	 * the callback dma allocation that we have to use...
1666d720e6d5SJustin T. Gibbs 	 */
1667d720e6d5SJustin T. Gibbs 	mp = &mush;
1668d720e6d5SJustin T. Gibbs 	mp->isp = isp;
16699e11e5beSMatt Jacob 	mp->cmd_token = csio;
1670d720e6d5SJustin T. Gibbs 	mp->rq = rq;
1671d720e6d5SJustin T. Gibbs 	mp->iptrp = iptrp;
1672d720e6d5SJustin T. Gibbs 	mp->optr = optr;
1673d720e6d5SJustin T. Gibbs 	mp->error = 0;
1674d720e6d5SJustin T. Gibbs 
16759e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
16769e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) {
16774873663cSMatt Jacob 			int error, s;
1678469b6b9eSMatt Jacob 			dp = &pci->dmaps[isp_handle_index(rq->req_handle)];
1679d720e6d5SJustin T. Gibbs 			s = splsoftvm();
1680d720e6d5SJustin T. Gibbs 			error = bus_dmamap_load(pci->parent_dmat, *dp,
16819e11e5beSMatt Jacob 			    csio->data_ptr, csio->dxfer_len, eptr, mp, 0);
1682d720e6d5SJustin T. Gibbs 			if (error == EINPROGRESS) {
1683d720e6d5SJustin T. Gibbs 				bus_dmamap_unload(pci->parent_dmat, *dp);
1684d720e6d5SJustin T. Gibbs 				mp->error = EINVAL;
1685f7dddf8aSMatt Jacob 				isp_prt(isp, ISP_LOGERR,
1686f7dddf8aSMatt Jacob 				    "deferred dma allocation not supported");
1687d720e6d5SJustin T. Gibbs 			} else if (error && mp->error == 0) {
16880a5f7e8bSMatt Jacob #ifdef	DIAGNOSTIC
16890a5f7e8bSMatt Jacob 				printf("%s: error %d in dma mapping code\n",
16900a5f7e8bSMatt Jacob 				    isp->isp_name, error);
16910a5f7e8bSMatt Jacob #endif
1692d720e6d5SJustin T. Gibbs 				mp->error = error;
1693d720e6d5SJustin T. Gibbs 			}
16944873663cSMatt Jacob 			splx(s);
1695d720e6d5SJustin T. Gibbs 		} else {
1696d720e6d5SJustin T. Gibbs 			/* Pointer to physical buffer */
1697d720e6d5SJustin T. Gibbs 			struct bus_dma_segment seg;
1698d720e6d5SJustin T. Gibbs 			seg.ds_addr = (bus_addr_t)csio->data_ptr;
1699d720e6d5SJustin T. Gibbs 			seg.ds_len = csio->dxfer_len;
17009e11e5beSMatt Jacob 			(*eptr)(mp, &seg, 1, 0);
1701d720e6d5SJustin T. Gibbs 		}
1702d720e6d5SJustin T. Gibbs 	} else {
1703d720e6d5SJustin T. Gibbs 		struct bus_dma_segment *segs;
1704d720e6d5SJustin T. Gibbs 
17059e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) {
1706f7dddf8aSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
1707f7dddf8aSMatt Jacob 			    "Physical segment pointers unsupported");
1708d720e6d5SJustin T. Gibbs 			mp->error = EINVAL;
17099e11e5beSMatt Jacob 		} else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) {
1710f7dddf8aSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
1711f7dddf8aSMatt Jacob 			    "Virtual segment addresses unsupported");
1712d720e6d5SJustin T. Gibbs 			mp->error = EINVAL;
1713d720e6d5SJustin T. Gibbs 		} else {
1714d720e6d5SJustin T. Gibbs 			/* Just use the segments provided */
1715d720e6d5SJustin T. Gibbs 			segs = (struct bus_dma_segment *) csio->data_ptr;
17169e11e5beSMatt Jacob 			(*eptr)(mp, segs, csio->sglist_cnt, 0);
1717d720e6d5SJustin T. Gibbs 		}
1718d720e6d5SJustin T. Gibbs 	}
1719003a310fSMatt Jacob #ifdef	ISP_TARGET_MODE
172065b024e1SMatt Jacob exit:
1721003a310fSMatt Jacob #endif
1722d720e6d5SJustin T. Gibbs 	if (mp->error) {
17234873663cSMatt Jacob 		int retval = CMD_COMPLETE;
17244873663cSMatt Jacob 		if (mp->error == MUSHERR_NOQENTRIES) {
17254873663cSMatt Jacob 			retval = CMD_EAGAIN;
17264873663cSMatt Jacob 		} else if (mp->error == EFBIG) {
17270a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_REQ_TOO_BIG);
1728d720e6d5SJustin T. Gibbs 		} else if (mp->error == EINVAL) {
17290a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_REQ_INVALID);
1730d720e6d5SJustin T. Gibbs 		} else {
17310a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_UNREC_HBA_ERROR);
1732d720e6d5SJustin T. Gibbs 		}
17334873663cSMatt Jacob 		return (retval);
17344873663cSMatt Jacob 	} else {
17350a5f7e8bSMatt Jacob 		/*
17360a5f7e8bSMatt Jacob 		 * Check to see if we weren't cancelled while sleeping on
17370a5f7e8bSMatt Jacob 		 * getting DMA resources...
17380a5f7e8bSMatt Jacob 		 */
17399e11e5beSMatt Jacob 		if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
17400a5f7e8bSMatt Jacob 			if (dp) {
17410a5f7e8bSMatt Jacob 				bus_dmamap_unload(pci->parent_dmat, *dp);
17420a5f7e8bSMatt Jacob 			}
17430a5f7e8bSMatt Jacob 			return (CMD_COMPLETE);
17440a5f7e8bSMatt Jacob 		}
17454873663cSMatt Jacob 		return (CMD_QUEUED);
1746d720e6d5SJustin T. Gibbs 	}
1747d720e6d5SJustin T. Gibbs }
1748d720e6d5SJustin T. Gibbs 
1749d720e6d5SJustin T. Gibbs static void
1750d02373f1SMatt Jacob isp_pci_dmateardown(struct ispsoftc *isp, XS_T *xs, u_int32_t handle)
1751d720e6d5SJustin T. Gibbs {
1752d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
1753469b6b9eSMatt Jacob 	bus_dmamap_t *dp = &pci->dmaps[isp_handle_index(handle)];
1754a95ae193SMatt Jacob 	if ((xs->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1755d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTREAD);
1756d720e6d5SJustin T. Gibbs 	} else {
1757d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTWRITE);
1758d720e6d5SJustin T. Gibbs 	}
1759d720e6d5SJustin T. Gibbs 	bus_dmamap_unload(pci->parent_dmat, *dp);
1760d720e6d5SJustin T. Gibbs }
1761d720e6d5SJustin T. Gibbs 
176265adb54cSMatt Jacob 
176365adb54cSMatt Jacob static void
176417e318c6SMatt Jacob isp_pci_reset1(struct ispsoftc *isp)
176565adb54cSMatt Jacob {
176665adb54cSMatt Jacob 	/* Make sure the BIOS is disabled */
176765adb54cSMatt Jacob 	isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS);
1768469b6b9eSMatt Jacob 	/* and enable interrupts */
1769469b6b9eSMatt Jacob 	ENABLE_INTS(isp);
177065adb54cSMatt Jacob }
177165adb54cSMatt Jacob 
177265adb54cSMatt Jacob static void
1773d02373f1SMatt Jacob isp_pci_dumpregs(struct ispsoftc *isp, const char *msg)
177465adb54cSMatt Jacob {
177565adb54cSMatt Jacob 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
1776d02373f1SMatt Jacob 	if (msg)
1777d02373f1SMatt Jacob 		printf("%s: %s\n", isp->isp_name, msg);
1778d02373f1SMatt Jacob 	if (IS_SCSI(isp))
1779d02373f1SMatt Jacob 		printf("    biu_conf1=%x", ISP_READ(isp, BIU_CONF1));
1780d02373f1SMatt Jacob 	else
1781d02373f1SMatt Jacob 		printf("    biu_csr=%x", ISP_READ(isp, BIU2100_CSR));
1782d02373f1SMatt Jacob 	printf(" biu_icr=%x biu_isr=%x biu_sema=%x ", ISP_READ(isp, BIU_ICR),
1783d02373f1SMatt Jacob 	    ISP_READ(isp, BIU_ISR), ISP_READ(isp, BIU_SEMA));
1784d02373f1SMatt Jacob 	printf("risc_hccr=%x\n", ISP_READ(isp, HCCR));
1785d02373f1SMatt Jacob 
1786d02373f1SMatt Jacob 
1787d02373f1SMatt Jacob 	if (IS_SCSI(isp)) {
1788d02373f1SMatt Jacob 		ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE);
1789d02373f1SMatt Jacob 		printf("    cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n",
1790d02373f1SMatt Jacob 			ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS),
1791d02373f1SMatt Jacob 			ISP_READ(isp, CDMA_FIFO_STS));
1792d02373f1SMatt Jacob 		printf("    ddma_conf=%x ddma_sts=%x ddma_fifostat=%x\n",
1793d02373f1SMatt Jacob 			ISP_READ(isp, DDMA_CONF), ISP_READ(isp, DDMA_STATUS),
1794d02373f1SMatt Jacob 			ISP_READ(isp, DDMA_FIFO_STS));
1795d02373f1SMatt Jacob 		printf("    sxp_int=%x sxp_gross=%x sxp(scsi_ctrl)=%x\n",
1796d02373f1SMatt Jacob 			ISP_READ(isp, SXP_INTERRUPT),
1797d02373f1SMatt Jacob 			ISP_READ(isp, SXP_GROSS_ERR),
1798d02373f1SMatt Jacob 			ISP_READ(isp, SXP_PINS_CTRL));
1799d02373f1SMatt Jacob 		ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE);
1800d02373f1SMatt Jacob 	}
1801d02373f1SMatt Jacob 	printf("    mbox regs: %x %x %x %x %x\n",
1802d02373f1SMatt Jacob 	    ISP_READ(isp, OUTMAILBOX0), ISP_READ(isp, OUTMAILBOX1),
1803d02373f1SMatt Jacob 	    ISP_READ(isp, OUTMAILBOX2), ISP_READ(isp, OUTMAILBOX3),
1804d02373f1SMatt Jacob 	    ISP_READ(isp, OUTMAILBOX4));
1805d02373f1SMatt Jacob 	printf("    PCI Status Command/Status=%x\n",
1806960f6939SMatt Jacob 	    pci_read_config(pci->pci_dev, PCIR_COMMAND, 1));
180765adb54cSMatt Jacob }
1808