xref: /freebsd/sys/dev/isp/isp_pci.c (revision 3486bfe084cdbbae1642e7ff025bb8f345947b7b)
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 };
243f09b1922SMatt Jacob static void isp_pci_intr __P((void *));
24465adb54cSMatt Jacob 
245960f6939SMatt Jacob static driver_t isp_pci_driver = {
246960f6939SMatt Jacob 	"isp", isp_pci_methods, sizeof (struct isp_pcisoftc)
247960f6939SMatt Jacob };
248960f6939SMatt Jacob static devclass_t isp_devclass;
249960f6939SMatt Jacob DRIVER_MODULE(isp, pci, isp_pci_driver, isp_devclass, 0, 0);
25056aef503SMatt Jacob MODULE_VERSION(isp, 1);
25165adb54cSMatt Jacob 
252960f6939SMatt Jacob static int
253960f6939SMatt Jacob isp_pci_probe(device_t dev)
25465adb54cSMatt Jacob {
255960f6939SMatt Jacob         switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) {
25656aef503SMatt Jacob 	case PCI_QLOGIC_ISP1020:
257960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1020/1040 PCI SCSI Adapter");
25865adb54cSMatt Jacob 		break;
259d59bd469SMatt Jacob 	case PCI_QLOGIC_ISP1080:
260960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1080 PCI SCSI Adapter");
261c6608df3SMatt Jacob 		break;
262c6608df3SMatt Jacob 	case PCI_QLOGIC_ISP1240:
263960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1240 PCI SCSI Adapter");
264d59bd469SMatt Jacob 		break;
26522e1dc85SMatt Jacob 	case PCI_QLOGIC_ISP1280:
266960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 1280 PCI SCSI Adapter");
267960f6939SMatt Jacob 		break;
268960f6939SMatt Jacob 	case PCI_QLOGIC_ISP12160:
269e11a1ee8SMatt Jacob 		if (pci_get_subvendor(dev) == AMI_RAID_SUBVENDOR_ID) {
270e11a1ee8SMatt Jacob 			return (ENXIO);
271e11a1ee8SMatt Jacob 		}
272960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 12160 PCI SCSI Adapter");
27322e1dc85SMatt Jacob 		break;
27465adb54cSMatt Jacob 	case PCI_QLOGIC_ISP2100:
275960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2100 PCI FC-AL Adapter");
27665adb54cSMatt Jacob 		break;
2775542fe4bSMatt Jacob 	case PCI_QLOGIC_ISP2200:
278960f6939SMatt Jacob 		device_set_desc(dev, "Qlogic ISP 2200 PCI FC-AL Adapter");
2795542fe4bSMatt Jacob 		break;
28065adb54cSMatt Jacob 	default:
281960f6939SMatt Jacob 		return (ENXIO);
28265adb54cSMatt Jacob 	}
283d02373f1SMatt Jacob 	if (device_get_unit(dev) == 0 && bootverbose) {
284d02373f1SMatt Jacob 		printf("Qlogic ISP Driver, FreeBSD Version %d.%d, "
285a95ae193SMatt Jacob 		    "Core Version %d.%d\n",
286d720e6d5SJustin T. Gibbs 		    ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR,
287d720e6d5SJustin T. Gibbs 		    ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR);
28865adb54cSMatt Jacob 	}
28956aef503SMatt Jacob 	/*
29056aef503SMatt Jacob 	 * XXXX: Here is where we might load the f/w module
29156aef503SMatt Jacob 	 * XXXX: (or increase a reference count to it).
29256aef503SMatt Jacob 	 */
293960f6939SMatt Jacob 	return (0);
29465adb54cSMatt Jacob }
29565adb54cSMatt Jacob 
296960f6939SMatt Jacob static int
297960f6939SMatt Jacob isp_pci_attach(device_t dev)
29865adb54cSMatt Jacob {
299960f6939SMatt Jacob 	struct resource *regs, *irq;
3003395b056SMatt Jacob 	int unit, bitmap, rtp, rgd, iqd, m1, m2, isp_debug;
301960f6939SMatt Jacob 	u_int32_t data, cmd, linesz, psize, basetype;
30265adb54cSMatt Jacob 	struct isp_pcisoftc *pcs;
3033395b056SMatt Jacob 	struct ispsoftc *isp = NULL;
304c6608df3SMatt Jacob 	struct ispmdvec *mdvp;
305222bb542SMatt Jacob 	bus_size_t lim;
3063395b056SMatt Jacob #ifdef	ISP_SMPLOCK
3073395b056SMatt Jacob 	int locksetup = 0;
3083395b056SMatt Jacob #endif
30965adb54cSMatt Jacob 
310222bb542SMatt Jacob 	/*
3119ba86737SMatt Jacob 	 * Figure out if we're supposed to skip this one.
3129ba86737SMatt Jacob 	 */
313960f6939SMatt Jacob 	unit = device_get_unit(dev);
3149ba86737SMatt Jacob 	if (getenv_int("isp_disable", &bitmap)) {
3159ba86737SMatt Jacob 		if (bitmap & (1 << unit)) {
316960f6939SMatt Jacob 			device_printf(dev, "not configuring\n");
317960f6939SMatt Jacob 			return (ENODEV);
3189ba86737SMatt Jacob 		}
3199ba86737SMatt Jacob 	}
3209ba86737SMatt Jacob 
3217cc0979fSDavid Malone 	pcs = malloc(sizeof (struct isp_pcisoftc), M_DEVBUF, M_NOWAIT | M_ZERO);
322960f6939SMatt Jacob 	if (pcs == NULL) {
323960f6939SMatt Jacob 		device_printf(dev, "cannot allocate softc\n");
324960f6939SMatt Jacob 		return (ENOMEM);
325960f6939SMatt Jacob 	}
326960f6939SMatt Jacob 
3279ba86737SMatt Jacob 	/*
328222bb542SMatt Jacob 	 * Figure out which we should try first - memory mapping or i/o mapping?
329222bb542SMatt Jacob 	 */
33056aef503SMatt Jacob #ifdef	__alpha__
331960f6939SMatt Jacob 	m1 = PCIM_CMD_MEMEN;
332960f6939SMatt Jacob 	m2 = PCIM_CMD_PORTEN;
333222bb542SMatt Jacob #else
334960f6939SMatt Jacob 	m1 = PCIM_CMD_PORTEN;
335960f6939SMatt Jacob 	m2 = PCIM_CMD_MEMEN;
336222bb542SMatt Jacob #endif
337222bb542SMatt Jacob 	bitmap = 0;
338222bb542SMatt Jacob 	if (getenv_int("isp_mem_map", &bitmap)) {
339960f6939SMatt Jacob 		if (bitmap & (1 << unit)) {
340960f6939SMatt Jacob 			m1 = PCIM_CMD_MEMEN;
341960f6939SMatt Jacob 			m2 = PCIM_CMD_PORTEN;
342960f6939SMatt Jacob 		}
343222bb542SMatt Jacob 	}
344222bb542SMatt Jacob 	bitmap = 0;
345222bb542SMatt Jacob 	if (getenv_int("isp_io_map", &bitmap)) {
346960f6939SMatt Jacob 		if (bitmap & (1 << unit)) {
347960f6939SMatt Jacob 			m1 = PCIM_CMD_PORTEN;
348960f6939SMatt Jacob 			m2 = PCIM_CMD_MEMEN;
349960f6939SMatt Jacob 		}
350222bb542SMatt Jacob 	}
351222bb542SMatt Jacob 
352ab6d0040SMatt Jacob 	linesz = PCI_DFLT_LNSZ;
353960f6939SMatt Jacob 	irq = regs = NULL;
354960f6939SMatt Jacob 	rgd = rtp = iqd = 0;
355960f6939SMatt Jacob 
356960f6939SMatt Jacob 	cmd = pci_read_config(dev, PCIR_COMMAND, 1);
357960f6939SMatt Jacob 	if (cmd & m1) {
358960f6939SMatt Jacob 		rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT;
359960f6939SMatt Jacob 		rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG;
360960f6939SMatt Jacob 		regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE);
36165adb54cSMatt Jacob 	}
362960f6939SMatt Jacob 	if (regs == NULL && (cmd & m2)) {
363960f6939SMatt Jacob 		rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT;
364960f6939SMatt Jacob 		rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG;
365960f6939SMatt Jacob 		regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE);
36665adb54cSMatt Jacob 	}
367960f6939SMatt Jacob 	if (regs == NULL) {
368960f6939SMatt Jacob 		device_printf(dev, "unable to map any ports\n");
369960f6939SMatt Jacob 		goto bad;
37065adb54cSMatt Jacob 	}
371222bb542SMatt Jacob 	if (bootverbose)
372f7dddf8aSMatt Jacob 		device_printf(dev, "using %s space register mapping\n",
373960f6939SMatt Jacob 		    (rgd == IO_MAP_REG)? "I/O" : "Memory");
374960f6939SMatt Jacob 	pcs->pci_dev = dev;
375960f6939SMatt Jacob 	pcs->pci_reg = regs;
376960f6939SMatt Jacob 	pcs->pci_st = rman_get_bustag(regs);
377960f6939SMatt Jacob 	pcs->pci_sh = rman_get_bushandle(regs);
37865adb54cSMatt Jacob 
379d59bd469SMatt Jacob 	pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF;
380d59bd469SMatt Jacob 	pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF;
381d59bd469SMatt Jacob 	pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF;
382d59bd469SMatt Jacob 	pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF;
383d59bd469SMatt Jacob 	pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF;
384c6608df3SMatt Jacob 	mdvp = &mdvec;
385c6608df3SMatt Jacob 	basetype = ISP_HA_SCSI_UNKNOWN;
386c6608df3SMatt Jacob 	psize = sizeof (sdparam);
387222bb542SMatt Jacob 	lim = BUS_SPACE_MAXSIZE_32BIT;
38856aef503SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP1020) {
389c6608df3SMatt Jacob 		mdvp = &mdvec;
390c6608df3SMatt Jacob 		basetype = ISP_HA_SCSI_UNKNOWN;
391c6608df3SMatt Jacob 		psize = sizeof (sdparam);
392222bb542SMatt Jacob 		lim = BUS_SPACE_MAXSIZE_24BIT;
393d59bd469SMatt Jacob 	}
394960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP1080) {
395c6608df3SMatt Jacob 		mdvp = &mdvec_1080;
396c6608df3SMatt Jacob 		basetype = ISP_HA_SCSI_1080;
397c6608df3SMatt Jacob 		psize = sizeof (sdparam);
398c6608df3SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
399c6608df3SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
400c6608df3SMatt Jacob 	}
401960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP1240) {
402c6608df3SMatt Jacob 		mdvp = &mdvec_1080;
40322e1dc85SMatt Jacob 		basetype = ISP_HA_SCSI_1240;
40422e1dc85SMatt Jacob 		psize = 2 * sizeof (sdparam);
40522e1dc85SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
40622e1dc85SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
40722e1dc85SMatt Jacob 	}
408960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP1280) {
40922e1dc85SMatt Jacob 		mdvp = &mdvec_1080;
41022e1dc85SMatt Jacob 		basetype = ISP_HA_SCSI_1280;
411c6608df3SMatt Jacob 		psize = 2 * sizeof (sdparam);
412d59bd469SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
413d59bd469SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
414d59bd469SMatt Jacob 	}
415960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP12160) {
416960f6939SMatt Jacob 		mdvp = &mdvec_12160;
417960f6939SMatt Jacob 		basetype = ISP_HA_SCSI_12160;
418960f6939SMatt Jacob 		psize = 2 * sizeof (sdparam);
419960f6939SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
420960f6939SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
421960f6939SMatt Jacob 	}
422960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP2100) {
423c6608df3SMatt Jacob 		mdvp = &mdvec_2100;
424c6608df3SMatt Jacob 		basetype = ISP_HA_FC_2100;
425c6608df3SMatt Jacob 		psize = sizeof (fcparam);
426d59bd469SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
427d59bd469SMatt Jacob 		    PCI_MBOX_REGS2100_OFF;
428960f6939SMatt Jacob 		if (pci_get_revid(dev) < 3) {
429ab6d0040SMatt Jacob 			/*
430ab6d0040SMatt Jacob 			 * XXX: Need to get the actual revision
431ab6d0040SMatt Jacob 			 * XXX: number of the 2100 FB. At any rate,
432ab6d0040SMatt Jacob 			 * XXX: lower cache line size for early revision
433ab6d0040SMatt Jacob 			 * XXX; boards.
434ab6d0040SMatt Jacob 			 */
435ab6d0040SMatt Jacob 			linesz = 1;
436ab6d0040SMatt Jacob 		}
43765adb54cSMatt Jacob 	}
438960f6939SMatt Jacob 	if (pci_get_devid(dev) == PCI_QLOGIC_ISP2200) {
439222bb542SMatt Jacob 		mdvp = &mdvec_2200;
440222bb542SMatt Jacob 		basetype = ISP_HA_FC_2200;
441222bb542SMatt Jacob 		psize = sizeof (fcparam);
442222bb542SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
443222bb542SMatt Jacob 		    PCI_MBOX_REGS2100_OFF;
444222bb542SMatt Jacob 	}
445c6608df3SMatt Jacob 	isp = &pcs->pci_isp;
4467cc0979fSDavid Malone 	isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT | M_ZERO);
447c6608df3SMatt Jacob 	if (isp->isp_param == NULL) {
448960f6939SMatt Jacob 		device_printf(dev, "cannot allocate parameter data\n");
449960f6939SMatt Jacob 		goto bad;
450c6608df3SMatt Jacob 	}
451c6608df3SMatt Jacob 	isp->isp_mdvec = mdvp;
452c6608df3SMatt Jacob 	isp->isp_type = basetype;
453960f6939SMatt Jacob 	isp->isp_revision = pci_get_revid(dev);
454c6608df3SMatt Jacob 	(void) snprintf(isp->isp_name, sizeof (isp->isp_name), "isp%d", unit);
455c6608df3SMatt Jacob 	isp->isp_osinfo.unit = unit;
45665adb54cSMatt Jacob 
45756aef503SMatt Jacob 	/*
45856aef503SMatt Jacob 	 * Try and find firmware for this device.
45956aef503SMatt Jacob 	 */
46056aef503SMatt Jacob 
46156aef503SMatt Jacob 	if (isp_get_firmware_p) {
46256aef503SMatt Jacob 		int device = (int) pci_get_device(dev);
46356aef503SMatt Jacob #ifdef	ISP_TARGET_MODE
46456aef503SMatt Jacob 		(*isp_get_firmware_p)(0, 1, device, &mdvp->dv_ispfw);
46556aef503SMatt Jacob #else
46656aef503SMatt Jacob 		(*isp_get_firmware_p)(0, 0, device, &mdvp->dv_ispfw);
46756aef503SMatt Jacob #endif
46856aef503SMatt Jacob 	}
46956aef503SMatt Jacob 
47056aef503SMatt Jacob 	/*
471d951bbcaSMatt Jacob 	 * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER
472d951bbcaSMatt Jacob 	 * are set.
473d951bbcaSMatt Jacob 	 */
474960f6939SMatt Jacob 	cmd |= PCIM_CMD_SEREN | PCIM_CMD_PERRESPEN |
475960f6939SMatt Jacob 		PCIM_CMD_BUSMASTEREN | PCIM_CMD_INVEN;
476960f6939SMatt Jacob 	pci_write_config(dev, PCIR_COMMAND, cmd, 1);
477ab6d0040SMatt Jacob 
478d951bbcaSMatt Jacob 	/*
479222bb542SMatt Jacob 	 * Make sure the Cache Line Size register is set sensibly.
480d951bbcaSMatt Jacob 	 */
481960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_CACHELNSZ, 1);
482ab6d0040SMatt Jacob 	if (data != linesz) {
483d951bbcaSMatt Jacob 		data = PCI_DFLT_LNSZ;
484d02373f1SMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, "set PCI line size to %d", data);
485960f6939SMatt Jacob 		pci_write_config(dev, PCIR_CACHELNSZ, data, 1);
486d951bbcaSMatt Jacob 	}
487ab6d0040SMatt Jacob 
488d951bbcaSMatt Jacob 	/*
489d951bbcaSMatt Jacob 	 * Make sure the Latency Timer is sane.
490d951bbcaSMatt Jacob 	 */
491960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_LATTIMER, 1);
492d951bbcaSMatt Jacob 	if (data < PCI_DFLT_LTNCY) {
493d951bbcaSMatt Jacob 		data = PCI_DFLT_LTNCY;
494d02373f1SMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, "set PCI latency to %d", data);
495960f6939SMatt Jacob 		pci_write_config(dev, PCIR_LATTIMER, data, 1);
496d951bbcaSMatt Jacob 	}
497ab6d0040SMatt Jacob 
498ab6d0040SMatt Jacob 	/*
499ab6d0040SMatt Jacob 	 * Make sure we've disabled the ROM.
500ab6d0040SMatt Jacob 	 */
501960f6939SMatt Jacob 	data = pci_read_config(dev, PCIR_ROMADDR, 4);
502ab6d0040SMatt Jacob 	data &= ~1;
503960f6939SMatt Jacob 	pci_write_config(dev, PCIR_ROMADDR, data, 4);
50405fbcbb0SMatt Jacob 
505d951bbcaSMatt Jacob 
506086646f7SJustin T. Gibbs 	if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
507222bb542SMatt Jacob 	    BUS_SPACE_MAXADDR, NULL, NULL, lim + 1,
508222bb542SMatt Jacob 	    255, lim, 0, &pcs->parent_dmat) != 0) {
509f7dddf8aSMatt Jacob 		device_printf(dev, "could not create master dma tag\n");
510960f6939SMatt Jacob 		free(isp->isp_param, M_DEVBUF);
511d720e6d5SJustin T. Gibbs 		free(pcs, M_DEVBUF);
512960f6939SMatt Jacob 		return (ENXIO);
51365adb54cSMatt Jacob 	}
51465adb54cSMatt Jacob 
515960f6939SMatt Jacob 	iqd = 0;
516960f6939SMatt Jacob 	irq = bus_alloc_resource(dev, SYS_RES_IRQ, &iqd, 0, ~0,
517960f6939SMatt Jacob 	    1, RF_ACTIVE | RF_SHAREABLE);
518960f6939SMatt Jacob 	if (irq == NULL) {
519960f6939SMatt Jacob 		device_printf(dev, "could not allocate interrupt\n");
520960f6939SMatt Jacob 		goto bad;
521960f6939SMatt Jacob 	}
522960f6939SMatt Jacob 
523222bb542SMatt Jacob 	if (getenv_int("isp_no_fwload", &bitmap)) {
524222bb542SMatt Jacob 		if (bitmap & (1 << unit))
525222bb542SMatt Jacob 			isp->isp_confopts |= ISP_CFG_NORELOAD;
526222bb542SMatt Jacob 	}
527222bb542SMatt Jacob 	if (getenv_int("isp_fwload", &bitmap)) {
528222bb542SMatt Jacob 		if (bitmap & (1 << unit))
529222bb542SMatt Jacob 			isp->isp_confopts &= ~ISP_CFG_NORELOAD;
530222bb542SMatt Jacob 	}
531222bb542SMatt Jacob 	if (getenv_int("isp_no_nvram", &bitmap)) {
532222bb542SMatt Jacob 		if (bitmap & (1 << unit))
533222bb542SMatt Jacob 			isp->isp_confopts |= ISP_CFG_NONVRAM;
534222bb542SMatt Jacob 	}
535222bb542SMatt Jacob 	if (getenv_int("isp_nvram", &bitmap)) {
536222bb542SMatt Jacob 		if (bitmap & (1 << unit))
537222bb542SMatt Jacob 			isp->isp_confopts &= ~ISP_CFG_NONVRAM;
538222bb542SMatt Jacob 	}
539222bb542SMatt Jacob 	if (getenv_int("isp_fcduplex", &bitmap)) {
540222bb542SMatt Jacob 		if (bitmap & (1 << unit))
541222bb542SMatt Jacob 			isp->isp_confopts |= ISP_CFG_FULL_DUPLEX;
542222bb542SMatt Jacob 	}
543222bb542SMatt Jacob 	if (getenv_int("isp_no_fcduplex", &bitmap)) {
544222bb542SMatt Jacob 		if (bitmap & (1 << unit))
545222bb542SMatt Jacob 			isp->isp_confopts &= ~ISP_CFG_FULL_DUPLEX;
546222bb542SMatt Jacob 	}
547960f6939SMatt Jacob 	if (getenv_int("isp_nport", &bitmap)) {
548960f6939SMatt Jacob 		if (bitmap & (1 << unit))
549960f6939SMatt Jacob 			isp->isp_confopts |= ISP_CFG_NPORT;
550960f6939SMatt Jacob 	}
551222bb542SMatt Jacob 	/*
5529637d68cSMatt Jacob 	 * Look for overriding WWN. This is a Node WWN so it binds to
5539637d68cSMatt Jacob 	 * all FC instances. A Port WWN will be constructed from it
5549637d68cSMatt Jacob 	 * as appropriate.
555222bb542SMatt Jacob 	 */
5569637d68cSMatt Jacob 	if (!getenv_quad("isp_wwn", (quad_t *) &isp->isp_osinfo.default_wwn)) {
5579637d68cSMatt Jacob 		int i;
5589637d68cSMatt Jacob 		u_int64_t seed = (u_int64_t) (intptr_t) isp;
559222bb542SMatt Jacob 
5609637d68cSMatt Jacob 		seed <<= 16;
5619637d68cSMatt Jacob 		seed &= ((1LL << 48) - 1LL);
562222bb542SMatt Jacob 		/*
563222bb542SMatt Jacob 		 * This isn't very random, but it's the best we can do for
5649637d68cSMatt Jacob 		 * the real edge case of cards that don't have WWNs. If
5659637d68cSMatt Jacob 		 * you recompile a new vers.c, you'll get a different WWN.
566222bb542SMatt Jacob 		 */
5679637d68cSMatt Jacob 		for (i = 0; version[i] != 0; i++) {
5689637d68cSMatt Jacob 			seed += version[i];
5699637d68cSMatt Jacob 		}
5709637d68cSMatt Jacob 		/*
571d02373f1SMatt Jacob 		 * Make sure the top nibble has something vaguely sensible
572d02373f1SMatt Jacob 		 * (NAA == Locally Administered)
5739637d68cSMatt Jacob 		 */
574d02373f1SMatt Jacob 		isp->isp_osinfo.default_wwn |= (3LL << 60) | seed;
5759637d68cSMatt Jacob 	} else {
5769637d68cSMatt Jacob 		isp->isp_confopts |= ISP_CFG_OWNWWN;
577222bb542SMatt Jacob 	}
578d02373f1SMatt Jacob 	isp_debug = 0;
579a95ae193SMatt Jacob 	(void) getenv_int("isp_debug", &isp_debug);
580f09b1922SMatt Jacob 
581f09b1922SMatt Jacob #ifdef	ISP_SMPLOCK
582f09b1922SMatt Jacob 	/* Make sure the lock is set up. */
583f09b1922SMatt Jacob 	mtx_init(&isp->isp_osinfo.lock, "isp", MTX_DEF);
584f09b1922SMatt Jacob 	locksetup++;
585f09b1922SMatt Jacob #endif
586f09b1922SMatt Jacob 
587f09b1922SMatt Jacob #ifdef	ISP_SMPLOCK
588f09b1922SMatt Jacob 	if (bus_setup_intr(dev, irq, INTR_TYPE_CAM | INTR_MPSAFE,
589f09b1922SMatt Jacob 	    isp_pci_intr, isp, &pcs->ih)) {
590960f6939SMatt Jacob 		device_printf(dev, "could not setup interrupt\n");
591960f6939SMatt Jacob 		goto bad;
592960f6939SMatt Jacob 	}
593f09b1922SMatt Jacob #else
594f09b1922SMatt Jacob 	if (bus_setup_intr(dev, irq, INTR_TYPE_CAM,
595f09b1922SMatt Jacob 	    isp_pci_intr, isp, &pcs->ih)) {
596f09b1922SMatt Jacob 		device_printf(dev, "could not setup interrupt\n");
597f09b1922SMatt Jacob 		goto bad;
598f09b1922SMatt Jacob 	}
599f09b1922SMatt Jacob #endif
600960f6939SMatt Jacob 
60105fbcbb0SMatt Jacob 	/*
602d02373f1SMatt Jacob 	 * Set up logging levels.
603d02373f1SMatt Jacob 	 */
604d02373f1SMatt Jacob 	if (isp_debug) {
605d02373f1SMatt Jacob 		isp->isp_dblev = isp_debug;
606d02373f1SMatt Jacob 	} else {
607d02373f1SMatt Jacob 		isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR;
608d02373f1SMatt Jacob 	}
609d02373f1SMatt Jacob 	if (bootverbose)
610f7dddf8aSMatt Jacob 		isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO;
611d02373f1SMatt Jacob 
612d02373f1SMatt Jacob 	/*
61305fbcbb0SMatt Jacob 	 * Make sure we're in reset state.
61405fbcbb0SMatt Jacob 	 */
6153395b056SMatt Jacob 	ISP_LOCK(isp);
61665adb54cSMatt Jacob 	isp_reset(isp);
617d02373f1SMatt Jacob 
61865adb54cSMatt Jacob 	if (isp->isp_state != ISP_RESETSTATE) {
6193395b056SMatt Jacob 		ISP_UNLOCK(isp);
620960f6939SMatt Jacob 		goto bad;
62165adb54cSMatt Jacob 	}
62265adb54cSMatt Jacob 	isp_init(isp);
62365adb54cSMatt Jacob 	if (isp->isp_state != ISP_INITSTATE) {
624d59bd469SMatt Jacob 		/* If we're a Fibre Channel Card, we allow deferred attach */
625222bb542SMatt Jacob 		if (IS_SCSI(isp)) {
62665adb54cSMatt Jacob 			isp_uninit(isp);
6273395b056SMatt Jacob 			ISP_UNLOCK(isp);
628960f6939SMatt Jacob 			goto bad;
629d59bd469SMatt Jacob 		}
63065adb54cSMatt Jacob 	}
63165adb54cSMatt Jacob 	isp_attach(isp);
63265adb54cSMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE) {
633d59bd469SMatt Jacob 		/* If we're a Fibre Channel Card, we allow deferred attach */
63492c49d78SMatt Jacob 		if (IS_SCSI(isp)) {
63565adb54cSMatt Jacob 			isp_uninit(isp);
6363395b056SMatt Jacob 			ISP_UNLOCK(isp);
637960f6939SMatt Jacob 			goto bad;
638960f6939SMatt Jacob 		}
639960f6939SMatt Jacob 	}
64056aef503SMatt Jacob 	/*
64156aef503SMatt Jacob 	 * XXXX: Here is where we might unload the f/w module
64256aef503SMatt Jacob 	 * XXXX: (or decrease the reference count to it).
64356aef503SMatt Jacob 	 */
6443395b056SMatt Jacob 	ISP_UNLOCK(isp);
645960f6939SMatt Jacob 	return (0);
646960f6939SMatt Jacob 
647960f6939SMatt Jacob bad:
648960f6939SMatt Jacob 
649960f6939SMatt Jacob 	if (pcs && pcs->ih) {
650960f6939SMatt Jacob 		(void) bus_teardown_intr(dev, irq, pcs->ih);
651960f6939SMatt Jacob 	}
652960f6939SMatt Jacob 
6533395b056SMatt Jacob #ifdef	ISP_SMPLOCK
6543395b056SMatt Jacob 	if (locksetup && isp) {
6553395b056SMatt Jacob 		mtx_destroy(&isp->isp_osinfo.lock);
6563395b056SMatt Jacob 	}
6573395b056SMatt Jacob #endif
6583395b056SMatt Jacob 
659960f6939SMatt Jacob 	if (irq) {
660960f6939SMatt Jacob 		(void) bus_release_resource(dev, SYS_RES_IRQ, iqd, irq);
661960f6939SMatt Jacob 	}
6623395b056SMatt Jacob 
6633395b056SMatt Jacob 
664960f6939SMatt Jacob 	if (regs) {
665960f6939SMatt Jacob 		(void) bus_release_resource(dev, rtp, rgd, regs);
666960f6939SMatt Jacob 	}
6673395b056SMatt Jacob 
668960f6939SMatt Jacob 	if (pcs) {
669960f6939SMatt Jacob 		if (pcs->pci_isp.isp_param)
670960f6939SMatt Jacob 			free(pcs->pci_isp.isp_param, M_DEVBUF);
67165adb54cSMatt Jacob 		free(pcs, M_DEVBUF);
67265adb54cSMatt Jacob 	}
6733395b056SMatt Jacob 
67456aef503SMatt Jacob 	/*
67556aef503SMatt Jacob 	 * XXXX: Here is where we might unload the f/w module
67656aef503SMatt Jacob 	 * XXXX: (or decrease the reference count to it).
67756aef503SMatt Jacob 	 */
678960f6939SMatt Jacob 	return (ENXIO);
67965adb54cSMatt Jacob }
68065adb54cSMatt Jacob 
681f09b1922SMatt Jacob static void
682f09b1922SMatt Jacob isp_pci_intr(void *arg)
683f09b1922SMatt Jacob {
684f09b1922SMatt Jacob 	struct ispsoftc *isp = arg;
685f09b1922SMatt Jacob 	ISP_LOCK(isp);
686f09b1922SMatt Jacob 	(void) isp_intr(isp);
687f09b1922SMatt Jacob 	ISP_UNLOCK(isp);
688f09b1922SMatt Jacob }
689f09b1922SMatt Jacob 
69065adb54cSMatt Jacob static u_int16_t
691d59bd469SMatt Jacob isp_pci_rd_reg(isp, regoff)
692d59bd469SMatt Jacob 	struct ispsoftc *isp;
693d59bd469SMatt Jacob 	int regoff;
69465adb54cSMatt Jacob {
69565adb54cSMatt Jacob 	u_int16_t rv;
69665adb54cSMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
697d59bd469SMatt Jacob 	int offset, oldconf = 0;
69865adb54cSMatt Jacob 
699d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
70065adb54cSMatt Jacob 		/*
70165adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
70265adb54cSMatt Jacob 		 */
703d59bd469SMatt Jacob 		oldconf = isp_pci_rd_reg(isp, BIU_CONF1);
704d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP);
70565adb54cSMatt Jacob 	}
706d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
707d59bd469SMatt Jacob 	offset += (regoff & 0xff);
70865adb54cSMatt Jacob 	rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset);
709d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
710d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf);
71165adb54cSMatt Jacob 	}
71265adb54cSMatt Jacob 	return (rv);
71365adb54cSMatt Jacob }
71465adb54cSMatt Jacob 
71565adb54cSMatt Jacob static void
716d59bd469SMatt Jacob isp_pci_wr_reg(isp, regoff, val)
717d59bd469SMatt Jacob 	struct ispsoftc *isp;
718d59bd469SMatt Jacob 	int regoff;
719d59bd469SMatt Jacob 	u_int16_t val;
72065adb54cSMatt Jacob {
72165adb54cSMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
722d59bd469SMatt Jacob 	int offset, oldconf = 0;
723d59bd469SMatt Jacob 
724d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
72565adb54cSMatt Jacob 		/*
72665adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
72765adb54cSMatt Jacob 		 */
728d59bd469SMatt Jacob 		oldconf = isp_pci_rd_reg(isp, BIU_CONF1);
729d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP);
73065adb54cSMatt Jacob 	}
731d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
732d59bd469SMatt Jacob 	offset += (regoff & 0xff);
73365adb54cSMatt Jacob 	bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val);
734d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
735d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf);
73665adb54cSMatt Jacob 	}
73765adb54cSMatt Jacob }
73865adb54cSMatt Jacob 
739d59bd469SMatt Jacob static u_int16_t
740d59bd469SMatt Jacob isp_pci_rd_reg_1080(isp, regoff)
741d59bd469SMatt Jacob 	struct ispsoftc *isp;
742d59bd469SMatt Jacob 	int regoff;
743d59bd469SMatt Jacob {
74422e1dc85SMatt Jacob 	u_int16_t rv, oc = 0;
745d59bd469SMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
74622e1dc85SMatt Jacob 	int offset;
747d59bd469SMatt Jacob 
74822e1dc85SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
74922e1dc85SMatt Jacob 	    (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
75022e1dc85SMatt Jacob 		u_int16_t tc;
751d59bd469SMatt Jacob 		/*
752d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
753d59bd469SMatt Jacob 		 */
754d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
75522e1dc85SMatt Jacob 		tc = oc & ~BIU_PCI1080_CONF1_DMA;
75622e1dc85SMatt Jacob 		if (regoff & SXP_BANK1_SELECT)
75722e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP1;
75822e1dc85SMatt Jacob 		else
75922e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP0;
76022e1dc85SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, tc);
761d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
762d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
763d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA);
764d59bd469SMatt Jacob 	}
765d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
766d59bd469SMatt Jacob 	offset += (regoff & 0xff);
767d59bd469SMatt Jacob 	rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset);
76822e1dc85SMatt Jacob 	if (oc) {
769d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc);
770d59bd469SMatt Jacob 	}
771d59bd469SMatt Jacob 	return (rv);
772d59bd469SMatt Jacob }
773d59bd469SMatt Jacob 
774d59bd469SMatt Jacob static void
775d59bd469SMatt Jacob isp_pci_wr_reg_1080(isp, regoff, val)
776d59bd469SMatt Jacob 	struct ispsoftc *isp;
777d59bd469SMatt Jacob 	int regoff;
778d59bd469SMatt Jacob 	u_int16_t val;
779d59bd469SMatt Jacob {
780d59bd469SMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
781d59bd469SMatt Jacob 	int offset, oc = 0;
782d59bd469SMatt Jacob 
78322e1dc85SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
78422e1dc85SMatt Jacob 	    (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
78522e1dc85SMatt Jacob 		u_int16_t tc;
786d59bd469SMatt Jacob 		/*
787d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
788d59bd469SMatt Jacob 		 */
789d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
79022e1dc85SMatt Jacob 		tc = oc & ~BIU_PCI1080_CONF1_DMA;
79122e1dc85SMatt Jacob 		if (regoff & SXP_BANK1_SELECT)
79222e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP1;
79322e1dc85SMatt Jacob 		else
79422e1dc85SMatt Jacob 			tc |= BIU_PCI1080_CONF1_SXP0;
79522e1dc85SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, tc);
796d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
797d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
798d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA);
799d59bd469SMatt Jacob 	}
800d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
801d59bd469SMatt Jacob 	offset += (regoff & 0xff);
802d59bd469SMatt Jacob 	bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val);
80322e1dc85SMatt Jacob 	if (oc) {
804d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc);
805d59bd469SMatt Jacob 	}
806d59bd469SMatt Jacob }
807d59bd469SMatt Jacob 
808d720e6d5SJustin T. Gibbs static void isp_map_rquest __P((void *, bus_dma_segment_t *, int, int));
809d720e6d5SJustin T. Gibbs static void isp_map_result __P((void *, bus_dma_segment_t *, int, int));
810d720e6d5SJustin T. Gibbs static void isp_map_fcscrt __P((void *, bus_dma_segment_t *, int, int));
811d720e6d5SJustin T. Gibbs 
812222bb542SMatt Jacob struct imush {
813222bb542SMatt Jacob 	struct ispsoftc *isp;
814222bb542SMatt Jacob 	int error;
815222bb542SMatt Jacob };
816222bb542SMatt Jacob 
817d720e6d5SJustin T. Gibbs static void
81817e318c6SMatt Jacob isp_map_rquest(void *arg, bus_dma_segment_t *segs, int nseg, int error)
819d720e6d5SJustin T. Gibbs {
820222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
821222bb542SMatt Jacob 	if (error) {
822222bb542SMatt Jacob 		imushp->error = error;
823222bb542SMatt Jacob 	} else {
824222bb542SMatt Jacob 		imushp->isp->isp_rquest_dma = segs->ds_addr;
825222bb542SMatt Jacob 	}
826d720e6d5SJustin T. Gibbs }
827d720e6d5SJustin T. Gibbs 
828d720e6d5SJustin T. Gibbs static void
82917e318c6SMatt Jacob isp_map_result(void *arg, bus_dma_segment_t *segs, int nseg, int error)
830d720e6d5SJustin T. Gibbs {
831222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
832222bb542SMatt Jacob 	if (error) {
833222bb542SMatt Jacob 		imushp->error = error;
834222bb542SMatt Jacob 	} else {
835222bb542SMatt Jacob 		imushp->isp->isp_result_dma = segs->ds_addr;
836222bb542SMatt Jacob 	}
837d720e6d5SJustin T. Gibbs }
838d720e6d5SJustin T. Gibbs 
839d720e6d5SJustin T. Gibbs static void
84017e318c6SMatt Jacob isp_map_fcscrt(void *arg, bus_dma_segment_t *segs, int nseg, int error)
841d720e6d5SJustin T. Gibbs {
842222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
843222bb542SMatt Jacob 	if (error) {
844222bb542SMatt Jacob 		imushp->error = error;
845222bb542SMatt Jacob 	} else {
846222bb542SMatt Jacob 		fcparam *fcp = imushp->isp->isp_param;
847d720e6d5SJustin T. Gibbs 		fcp->isp_scdma = segs->ds_addr;
848d720e6d5SJustin T. Gibbs 	}
849222bb542SMatt Jacob }
850d720e6d5SJustin T. Gibbs 
851d720e6d5SJustin T. Gibbs static int
85217e318c6SMatt Jacob isp_pci_mbxdma(struct ispsoftc *isp)
853d720e6d5SJustin T. Gibbs {
854d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
855d720e6d5SJustin T. Gibbs 	caddr_t base;
856d720e6d5SJustin T. Gibbs 	u_int32_t len;
857d720e6d5SJustin T. Gibbs 	int i, error;
858222bb542SMatt Jacob 	bus_size_t lim;
859222bb542SMatt Jacob 	struct imush im;
860222bb542SMatt Jacob 
861222bb542SMatt Jacob 
862a95ae193SMatt Jacob 	/*
863a95ae193SMatt Jacob 	 * Already been here? If so, leave...
864a95ae193SMatt Jacob 	 */
865a95ae193SMatt Jacob 	if (isp->isp_rquest) {
866a95ae193SMatt Jacob 		return (0);
867a95ae193SMatt Jacob 	}
868a95ae193SMatt Jacob 
869d02373f1SMatt Jacob 	len = sizeof (XS_T **) * isp->isp_maxcmds;
8707cc0979fSDavid Malone 	isp->isp_xflist = (XS_T **) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
871a95ae193SMatt Jacob 	if (isp->isp_xflist == NULL) {
872d02373f1SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array");
873a95ae193SMatt Jacob 		return (1);
874a95ae193SMatt Jacob 	}
875a95ae193SMatt Jacob 	len = sizeof (bus_dmamap_t) * isp->isp_maxcmds;
876a95ae193SMatt Jacob 	pci->dmaps = (bus_dmamap_t *) malloc(len, M_DEVBUF,  M_WAITOK);
877a95ae193SMatt Jacob 	if (pci->dmaps == NULL) {
878d02373f1SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "can't alloc dma maps");
879a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
880a95ae193SMatt Jacob 		return (1);
881a95ae193SMatt Jacob 	}
882a95ae193SMatt Jacob 
88322e1dc85SMatt Jacob 	if (IS_FC(isp) || IS_ULTRA2(isp))
884222bb542SMatt Jacob 		lim = BUS_SPACE_MAXADDR + 1;
885222bb542SMatt Jacob 	else
886222bb542SMatt Jacob 		lim = BUS_SPACE_MAXADDR_24BIT + 1;
887d720e6d5SJustin T. Gibbs 
888d720e6d5SJustin T. Gibbs 	/*
889d720e6d5SJustin T. Gibbs 	 * Allocate and map the request, result queues, plus FC scratch area.
890d720e6d5SJustin T. Gibbs 	 */
891d02373f1SMatt Jacob 	len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
892d02373f1SMatt Jacob 	len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
893222bb542SMatt Jacob 	if (IS_FC(isp)) {
894d720e6d5SJustin T. Gibbs 		len += ISP2100_SCRLEN;
895d720e6d5SJustin T. Gibbs 	}
896222bb542SMatt Jacob 	if (bus_dma_tag_create(pci->parent_dmat, PAGE_SIZE, lim,
897222bb542SMatt Jacob 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, len, 1,
898222bb542SMatt Jacob 	    BUS_SPACE_MAXSIZE_32BIT, 0, &pci->cntrol_dmat) != 0) {
899f7dddf8aSMatt Jacob 		isp_prt(isp, ISP_LOGERR,
900f7dddf8aSMatt Jacob 		    "cannot create a dma tag for control spaces");
901a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
902a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
903d720e6d5SJustin T. Gibbs 		return (1);
904d720e6d5SJustin T. Gibbs 	}
905d720e6d5SJustin T. Gibbs 	if (bus_dmamem_alloc(pci->cntrol_dmat, (void **)&base,
906d720e6d5SJustin T. Gibbs 	    BUS_DMA_NOWAIT, &pci->cntrol_dmap) != 0) {
907f7dddf8aSMatt Jacob 		isp_prt(isp, ISP_LOGERR,
9083486bfe0SMatt Jacob 		    "cannot allocate %d bytes of CCB memory", len);
909a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
910a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
911d720e6d5SJustin T. Gibbs 		return (1);
912d720e6d5SJustin T. Gibbs 	}
913d720e6d5SJustin T. Gibbs 
914d720e6d5SJustin T. Gibbs 	isp->isp_rquest = base;
915222bb542SMatt Jacob 	im.isp = isp;
916222bb542SMatt Jacob 	im.error = 0;
917d720e6d5SJustin T. Gibbs 	bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_rquest,
918d02373f1SMatt Jacob 	    ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)), isp_map_rquest, &im, 0);
919222bb542SMatt Jacob 	if (im.error) {
920f7dddf8aSMatt Jacob 		isp_prt(isp, ISP_LOGERR,
921f7dddf8aSMatt Jacob 		    "error %d loading dma map for DMA request queue", im.error);
922a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
923a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
924a95ae193SMatt Jacob 		isp->isp_rquest = NULL;
925222bb542SMatt Jacob 		return (1);
926222bb542SMatt Jacob 	}
927d02373f1SMatt Jacob 	isp->isp_result = base + ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
928222bb542SMatt Jacob 	im.error = 0;
929d720e6d5SJustin T. Gibbs 	bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_result,
930d02373f1SMatt Jacob 	    ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)), isp_map_result, &im, 0);
931222bb542SMatt Jacob 	if (im.error) {
932f7dddf8aSMatt Jacob 		isp_prt(isp, ISP_LOGERR,
933f7dddf8aSMatt Jacob 		    "error %d loading dma map for DMA result queue", im.error);
934a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
935a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
936a95ae193SMatt Jacob 		isp->isp_rquest = NULL;
937222bb542SMatt Jacob 		return (1);
938222bb542SMatt Jacob 	}
939d720e6d5SJustin T. Gibbs 
940a95ae193SMatt Jacob 	for (i = 0; i < isp->isp_maxcmds; i++) {
941d720e6d5SJustin T. Gibbs 		error = bus_dmamap_create(pci->parent_dmat, 0, &pci->dmaps[i]);
942d720e6d5SJustin T. Gibbs 		if (error) {
943f7dddf8aSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
944f7dddf8aSMatt Jacob 			    "error %d creating per-cmd DMA maps", error);
945a95ae193SMatt Jacob 			free(isp->isp_xflist, M_DEVBUF);
946a95ae193SMatt Jacob 			free(pci->dmaps, M_DEVBUF);
947a95ae193SMatt Jacob 			isp->isp_rquest = NULL;
948d720e6d5SJustin T. Gibbs 			return (1);
949d720e6d5SJustin T. Gibbs 		}
950d720e6d5SJustin T. Gibbs 	}
951a95ae193SMatt Jacob 
952222bb542SMatt Jacob 	if (IS_FC(isp)) {
95392c49d78SMatt Jacob 		fcparam *fcp = (fcparam *) isp->isp_param;
95492c49d78SMatt Jacob 		fcp->isp_scratch = base +
955d02373f1SMatt Jacob 			ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)) +
956d02373f1SMatt Jacob 			ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
957222bb542SMatt Jacob 		im.error = 0;
95892c49d78SMatt Jacob 		bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap,
959222bb542SMatt Jacob 		    fcp->isp_scratch, ISP2100_SCRLEN, isp_map_fcscrt, &im, 0);
960222bb542SMatt Jacob 		if (im.error) {
961f7dddf8aSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
962f7dddf8aSMatt Jacob 			    "error %d loading FC scratch area", im.error);
963a95ae193SMatt Jacob 			free(isp->isp_xflist, M_DEVBUF);
964a95ae193SMatt Jacob 			free(pci->dmaps, M_DEVBUF);
965a95ae193SMatt Jacob 			isp->isp_rquest = NULL;
966222bb542SMatt Jacob 			return (1);
967222bb542SMatt Jacob 		}
96892c49d78SMatt Jacob 	}
969d720e6d5SJustin T. Gibbs 	return (0);
970d720e6d5SJustin T. Gibbs }
971d720e6d5SJustin T. Gibbs 
972d720e6d5SJustin T. Gibbs typedef struct {
973d720e6d5SJustin T. Gibbs 	struct ispsoftc *isp;
9749e11e5beSMatt Jacob 	void *cmd_token;
9759e11e5beSMatt Jacob 	void *rq;
9769637d68cSMatt Jacob 	u_int16_t *iptrp;
9779637d68cSMatt Jacob 	u_int16_t optr;
978d720e6d5SJustin T. Gibbs 	u_int error;
979d720e6d5SJustin T. Gibbs } mush_t;
980d720e6d5SJustin T. Gibbs 
9814873663cSMatt Jacob #define	MUSHERR_NOQENTRIES	-2
9824873663cSMatt Jacob 
9839e11e5beSMatt Jacob #ifdef	ISP_TARGET_MODE
9849e11e5beSMatt Jacob /*
9859e11e5beSMatt Jacob  * We need to handle DMA for target mode differently from initiator mode.
9869e11e5beSMatt Jacob  *
9879e11e5beSMatt Jacob  * DMA mapping and construction and submission of CTIO Request Entries
9889e11e5beSMatt Jacob  * and rendevous for completion are very tightly coupled because we start
9899e11e5beSMatt Jacob  * out by knowing (per platform) how much data we have to move, but we
9909e11e5beSMatt Jacob  * don't know, up front, how many DMA mapping segments will have to be used
9919e11e5beSMatt Jacob  * cover that data, so we don't know how many CTIO Request Entries we
9929e11e5beSMatt Jacob  * will end up using. Further, for performance reasons we may want to
9939e11e5beSMatt Jacob  * (on the last CTIO for Fibre Channel), send status too (if all went well).
9949e11e5beSMatt Jacob  *
9959e11e5beSMatt Jacob  * The standard vector still goes through isp_pci_dmasetup, but the callback
9969e11e5beSMatt Jacob  * for the DMA mapping routines comes here instead with the whole transfer
9979e11e5beSMatt Jacob  * mapped and a pointer to a partially filled in already allocated request
9989e11e5beSMatt Jacob  * queue entry. We finish the job.
9999e11e5beSMatt Jacob  */
100005fbcbb0SMatt Jacob static void tdma_mk __P((void *, bus_dma_segment_t *, int, int));
100105fbcbb0SMatt Jacob static void tdma_mkfc __P((void *, bus_dma_segment_t *, int, int));
10029e11e5beSMatt Jacob 
1003d720e6d5SJustin T. Gibbs static void
100405fbcbb0SMatt Jacob tdma_mk(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
1005d720e6d5SJustin T. Gibbs {
1006d720e6d5SJustin T. Gibbs 	mush_t *mp;
10079e11e5beSMatt Jacob 	struct ccb_scsiio *csio;
1008d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci;
1009d720e6d5SJustin T. Gibbs 	bus_dmamap_t *dp;
101005fbcbb0SMatt Jacob 	u_int8_t scsi_status;
10119e11e5beSMatt Jacob 	ct_entry_t *cto;
101205fbcbb0SMatt Jacob 	u_int32_t handle, totxfr, sflags;
101305fbcbb0SMatt Jacob 	int nctios, send_status;
101405fbcbb0SMatt Jacob 	int32_t resid;
1015d720e6d5SJustin T. Gibbs 
1016d720e6d5SJustin T. Gibbs 	mp = (mush_t *) arg;
1017d720e6d5SJustin T. Gibbs 	if (error) {
1018d720e6d5SJustin T. Gibbs 		mp->error = error;
1019d720e6d5SJustin T. Gibbs 		return;
1020d720e6d5SJustin T. Gibbs 	}
10219e11e5beSMatt Jacob 	csio = mp->cmd_token;
10229e11e5beSMatt Jacob 	cto = mp->rq;
10239e11e5beSMatt Jacob 
102465b024e1SMatt Jacob 	cto->ct_xfrlen = 0;
102565b024e1SMatt Jacob 	cto->ct_seg_count = 0;
102665b024e1SMatt Jacob 	cto->ct_header.rqs_entry_count = 1;
102705fbcbb0SMatt Jacob 	MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg));
102805fbcbb0SMatt Jacob 
102905fbcbb0SMatt Jacob 	if (nseg == 0) {
103005fbcbb0SMatt Jacob 		cto->ct_header.rqs_seqno = 1;
103105fbcbb0SMatt Jacob 		ISP_TDQE(mp->isp, "tdma_mk[no data]", *mp->iptrp, cto);
1032d02373f1SMatt Jacob 		isp_prt(mp->isp, ISP_LOGTDEBUG1,
1033d02373f1SMatt Jacob 		    "CTIO lun %d->iid%d flgs 0x%x sts 0x%x ssts 0x%x res %d",
103465b024e1SMatt Jacob 		    csio->ccb_h.target_lun, cto->ct_iid, cto->ct_flags,
103565b024e1SMatt Jacob 		    cto->ct_status, cto->ct_scsi_status, cto->ct_resid);
103605fbcbb0SMatt Jacob 		ISP_SWIZ_CTIO(mp->isp, cto, cto);
103765b024e1SMatt Jacob 		return;
103865b024e1SMatt Jacob 	}
103965b024e1SMatt Jacob 
104065b024e1SMatt Jacob 	nctios = nseg / ISP_RQDSEG;
104165b024e1SMatt Jacob 	if (nseg % ISP_RQDSEG) {
104265b024e1SMatt Jacob 		nctios++;
104365b024e1SMatt Jacob 	}
104465b024e1SMatt Jacob 
104505fbcbb0SMatt Jacob 	/*
104605fbcbb0SMatt Jacob 	 * Save handle, and potentially any SCSI status, which we'll reinsert
104705fbcbb0SMatt Jacob 	 * on the last CTIO we're going to send.
104805fbcbb0SMatt Jacob 	 */
104905fbcbb0SMatt Jacob 	handle = cto->ct_reserved;
105005fbcbb0SMatt Jacob 	cto->ct_reserved = 0;
105105fbcbb0SMatt Jacob 	cto->ct_header.rqs_seqno = 0;
105205fbcbb0SMatt Jacob 	send_status = (cto->ct_flags & CT_SENDSTATUS) != 0;
105305fbcbb0SMatt Jacob 
105405fbcbb0SMatt Jacob 	if (send_status) {
105505fbcbb0SMatt Jacob 		sflags = cto->ct_flags & (CT_SENDSTATUS | CT_CCINCR);
105605fbcbb0SMatt Jacob 		cto->ct_flags &= ~(CT_SENDSTATUS | CT_CCINCR);
105705fbcbb0SMatt Jacob 		/*
105805fbcbb0SMatt Jacob 		 * Preserve residual.
105905fbcbb0SMatt Jacob 		 */
106005fbcbb0SMatt Jacob 		resid = cto->ct_resid;
106105fbcbb0SMatt Jacob 
106205fbcbb0SMatt Jacob 		/*
106305fbcbb0SMatt Jacob 		 * Save actual SCSI status.
106405fbcbb0SMatt Jacob 		 */
106505fbcbb0SMatt Jacob 		scsi_status = cto->ct_scsi_status;
106605fbcbb0SMatt Jacob 
106705fbcbb0SMatt Jacob 		/*
106805fbcbb0SMatt Jacob 		 * We can't do a status at the same time as a data CTIO, so
106905fbcbb0SMatt Jacob 		 * we need to synthesize an extra CTIO at this level.
107005fbcbb0SMatt Jacob 		 */
107105fbcbb0SMatt Jacob 		nctios++;
107205fbcbb0SMatt Jacob 	} else {
107305fbcbb0SMatt Jacob 		sflags = scsi_status = resid = 0;
107405fbcbb0SMatt Jacob 	}
107505fbcbb0SMatt Jacob 
107605fbcbb0SMatt Jacob 	totxfr = cto->ct_resid = 0;
107705fbcbb0SMatt Jacob 	cto->ct_scsi_status = 0;
107805fbcbb0SMatt Jacob 
10799e11e5beSMatt Jacob 	pci = (struct isp_pcisoftc *)mp->isp;
1080469b6b9eSMatt Jacob 	dp = &pci->dmaps[isp_handle_index(handle)];
10819e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1082d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
1083d720e6d5SJustin T. Gibbs 	} else {
1084d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
1085d720e6d5SJustin T. Gibbs 	}
1086d720e6d5SJustin T. Gibbs 
10879e11e5beSMatt Jacob 
10889e11e5beSMatt Jacob 	while (nctios--) {
108905fbcbb0SMatt Jacob 		int seglim;
10909e11e5beSMatt Jacob 
10919e11e5beSMatt Jacob 		seglim = nseg;
109205fbcbb0SMatt Jacob 		if (seglim) {
109305fbcbb0SMatt Jacob 			int seg;
109405fbcbb0SMatt Jacob 
10959e11e5beSMatt Jacob 			if (seglim > ISP_RQDSEG)
10969e11e5beSMatt Jacob 				seglim = ISP_RQDSEG;
10979e11e5beSMatt Jacob 
109805fbcbb0SMatt Jacob 			for (seg = 0; seg < seglim; seg++, nseg--) {
109905fbcbb0SMatt Jacob 				/*
110005fbcbb0SMatt Jacob 				 * Unlike normal initiator commands, we don't
110105fbcbb0SMatt Jacob 				 * do any swizzling here.
110205fbcbb0SMatt Jacob 				 */
11039e11e5beSMatt Jacob 				cto->ct_dataseg[seg].ds_count = dm_segs->ds_len;
110405fbcbb0SMatt Jacob 				cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr;
11059e11e5beSMatt Jacob 				cto->ct_xfrlen += dm_segs->ds_len;
110605fbcbb0SMatt Jacob 				totxfr += dm_segs->ds_len;
11079e11e5beSMatt Jacob 				dm_segs++;
11089e11e5beSMatt Jacob 			}
11099e11e5beSMatt Jacob 			cto->ct_seg_count = seg;
11109e11e5beSMatt Jacob 		} else {
111105fbcbb0SMatt Jacob 			/*
111205fbcbb0SMatt Jacob 			 * This case should only happen when we're sending an
111305fbcbb0SMatt Jacob 			 * extra CTIO with final status.
111405fbcbb0SMatt Jacob 			 */
111505fbcbb0SMatt Jacob 			if (send_status == 0) {
1116f7dddf8aSMatt Jacob 				isp_prt(mp->isp, ISP_LOGWARN,
1117f7dddf8aSMatt Jacob 				    "tdma_mk ran out of segments");
111805fbcbb0SMatt Jacob 				mp->error = EINVAL;
111905fbcbb0SMatt Jacob 				return;
11209e11e5beSMatt Jacob 			}
112105fbcbb0SMatt Jacob 		}
112205fbcbb0SMatt Jacob 
112305fbcbb0SMatt Jacob 		/*
112405fbcbb0SMatt Jacob 		 * At this point, the fields ct_lun, ct_iid, ct_tagval,
112505fbcbb0SMatt Jacob 		 * ct_tagtype, and ct_timeout have been carried over
112605fbcbb0SMatt Jacob 		 * unchanged from what our caller had set.
112705fbcbb0SMatt Jacob 		 *
112805fbcbb0SMatt Jacob 		 * The dataseg fields and the seg_count fields we just got
112905fbcbb0SMatt Jacob 		 * through setting. The data direction we've preserved all
113005fbcbb0SMatt Jacob 		 * along and only clear it if we're now sending status.
113105fbcbb0SMatt Jacob 		 */
11329e11e5beSMatt Jacob 
11339e11e5beSMatt Jacob 		if (nctios == 0) {
11349e11e5beSMatt Jacob 			/*
113505fbcbb0SMatt Jacob 			 * We're the last in a sequence of CTIOs, so mark
113605fbcbb0SMatt Jacob 			 * this CTIO and save the handle to the CCB such that
113705fbcbb0SMatt Jacob 			 * when this CTIO completes we can free dma resources
113805fbcbb0SMatt Jacob 			 * and do whatever else we need to do to finish the
113905fbcbb0SMatt Jacob 			 * rest of the command.
11409e11e5beSMatt Jacob 			 */
11419e11e5beSMatt Jacob 			cto->ct_reserved = handle;
114205fbcbb0SMatt Jacob 			cto->ct_header.rqs_seqno = 1;
114305fbcbb0SMatt Jacob 
114405fbcbb0SMatt Jacob 			if (send_status) {
11459e11e5beSMatt Jacob 				cto->ct_scsi_status = scsi_status;
114605fbcbb0SMatt Jacob 				cto->ct_flags |= sflags | CT_NO_DATA;;
114705fbcbb0SMatt Jacob 				cto->ct_resid = resid;
114842426921SMatt Jacob 			}
1149d02373f1SMatt Jacob 			if (send_status) {
1150d02373f1SMatt Jacob 				isp_prt(mp->isp, ISP_LOGTDEBUG1,
1151d02373f1SMatt Jacob 				    "CTIO lun%d for ID %d ct_flags 0x%x scsi "
1152d02373f1SMatt Jacob 				    "status %x resid %d",
1153d02373f1SMatt Jacob 				    csio->ccb_h.target_lun,
115405fbcbb0SMatt Jacob 				    cto->ct_iid, cto->ct_flags,
115505fbcbb0SMatt Jacob 				    cto->ct_scsi_status, cto->ct_resid);
1156d02373f1SMatt Jacob 			} else {
1157d02373f1SMatt Jacob 				isp_prt(mp->isp, ISP_LOGTDEBUG1,
1158d02373f1SMatt Jacob 				    "CTIO lun%d for ID%d ct_flags 0x%x",
1159d02373f1SMatt Jacob 				    csio->ccb_h.target_lun,
116005fbcbb0SMatt Jacob 				    cto->ct_iid, cto->ct_flags);
116105fbcbb0SMatt Jacob 			}
116205fbcbb0SMatt Jacob 			ISP_TDQE(mp->isp, "last tdma_mk", *mp->iptrp, cto);
116305fbcbb0SMatt Jacob 			ISP_SWIZ_CTIO(mp->isp, cto, cto);
11649e11e5beSMatt Jacob 		} else {
11659e11e5beSMatt Jacob 			ct_entry_t     *octo = cto;
116605fbcbb0SMatt Jacob 
116705fbcbb0SMatt Jacob 			/*
116805fbcbb0SMatt Jacob 			 * Make sure handle fields are clean
116905fbcbb0SMatt Jacob 			 */
11709e11e5beSMatt Jacob 			cto->ct_reserved = 0;
11719e11e5beSMatt Jacob 			cto->ct_header.rqs_seqno = 0;
117205fbcbb0SMatt Jacob 
1173d02373f1SMatt Jacob 			isp_prt(mp->isp, ISP_LOGTDEBUG1,
1174d02373f1SMatt Jacob 			    "CTIO lun%d for ID%d ct_flags 0x%x",
1175d02373f1SMatt Jacob 			    csio->ccb_h.target_lun, cto->ct_iid, cto->ct_flags);
117605fbcbb0SMatt Jacob 			ISP_TDQE(mp->isp, "tdma_mk", *mp->iptrp, cto);
117705fbcbb0SMatt Jacob 
117805fbcbb0SMatt Jacob 			/*
117905fbcbb0SMatt Jacob 			 * Get a new CTIO
118005fbcbb0SMatt Jacob 			 */
11819e11e5beSMatt Jacob 			cto = (ct_entry_t *)
11829e11e5beSMatt Jacob 			    ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
11839e11e5beSMatt Jacob 			*mp->iptrp =
1184d02373f1SMatt Jacob 			    ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp));
11859e11e5beSMatt Jacob 			if (*mp->iptrp == mp->optr) {
1186f7dddf8aSMatt Jacob 				isp_prt(mp->isp, ISP_LOGWARN,
1187f7dddf8aSMatt Jacob 				    "Queue Overflow in tdma_mk");
11889e11e5beSMatt Jacob 				mp->error = MUSHERR_NOQENTRIES;
11899e11e5beSMatt Jacob 				return;
11909e11e5beSMatt Jacob 			}
11919e11e5beSMatt Jacob 			/*
11929e11e5beSMatt Jacob 			 * Fill in the new CTIO with info from the old one.
11939e11e5beSMatt Jacob 			 */
11949e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
11959e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_count = 1;
11969e11e5beSMatt Jacob 			cto->ct_header.rqs_flags = 0;
11979e11e5beSMatt Jacob 			cto->ct_lun = octo->ct_lun;
11989e11e5beSMatt Jacob 			cto->ct_iid = octo->ct_iid;
11999e11e5beSMatt Jacob 			cto->ct_reserved2 = octo->ct_reserved2;
12009e11e5beSMatt Jacob 			cto->ct_tgt = octo->ct_tgt;
120105fbcbb0SMatt Jacob 			cto->ct_flags = octo->ct_flags;
12029e11e5beSMatt Jacob 			cto->ct_status = 0;
12039e11e5beSMatt Jacob 			cto->ct_scsi_status = 0;
12049e11e5beSMatt Jacob 			cto->ct_tag_val = octo->ct_tag_val;
12059e11e5beSMatt Jacob 			cto->ct_tag_type = octo->ct_tag_type;
12069e11e5beSMatt Jacob 			cto->ct_xfrlen = 0;
12079e11e5beSMatt Jacob 			cto->ct_resid = 0;
12089e11e5beSMatt Jacob 			cto->ct_timeout = octo->ct_timeout;
12099e11e5beSMatt Jacob 			cto->ct_seg_count = 0;
121005fbcbb0SMatt Jacob 			MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg));
121105fbcbb0SMatt Jacob 			/*
121205fbcbb0SMatt Jacob 			 * Now swizzle the old one for the consumption of the
121305fbcbb0SMatt Jacob 			 * chip.
121405fbcbb0SMatt Jacob 			 */
121505fbcbb0SMatt Jacob 			ISP_SWIZ_CTIO(mp->isp, octo, octo);
12169e11e5beSMatt Jacob 		}
12179e11e5beSMatt Jacob 	}
12189e11e5beSMatt Jacob }
12199e11e5beSMatt Jacob 
12209e11e5beSMatt Jacob static void
122105fbcbb0SMatt Jacob tdma_mkfc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
12229e11e5beSMatt Jacob {
12239e11e5beSMatt Jacob 	mush_t *mp;
12249e11e5beSMatt Jacob 	struct ccb_scsiio *csio;
12259e11e5beSMatt Jacob 	struct isp_pcisoftc *pci;
12269e11e5beSMatt Jacob 	bus_dmamap_t *dp;
12279e11e5beSMatt Jacob 	ct2_entry_t *cto;
122865b024e1SMatt Jacob 	u_int16_t scsi_status, send_status, send_sense;
122905fbcbb0SMatt Jacob 	u_int32_t handle, totxfr, datalen;
123065b024e1SMatt Jacob 	u_int8_t sense[QLTM_SENSELEN];
12319e11e5beSMatt Jacob 	int nctios;
12329e11e5beSMatt Jacob 
12339e11e5beSMatt Jacob 	mp = (mush_t *) arg;
12349e11e5beSMatt Jacob 	if (error) {
12359e11e5beSMatt Jacob 		mp->error = error;
12369e11e5beSMatt Jacob 		return;
12379e11e5beSMatt Jacob 	}
12389e11e5beSMatt Jacob 
123965b024e1SMatt Jacob 	csio = mp->cmd_token;
124065b024e1SMatt Jacob 	cto = mp->rq;
124165b024e1SMatt Jacob 
124265b024e1SMatt Jacob 	if (nseg == 0) {
124365b024e1SMatt Jacob 		if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE1) {
1244f7dddf8aSMatt Jacob 			isp_prt(mp->isp, ISP_LOGWARN,
1245f7dddf8aSMatt Jacob 			    "dma2_tgt_fc, a status CTIO2 without MODE1 "
1246f7dddf8aSMatt Jacob 			    "set (0x%x)", cto->ct_flags);
124765b024e1SMatt Jacob 			mp->error = EINVAL;
124865b024e1SMatt Jacob 			return;
124965b024e1SMatt Jacob 		}
125065b024e1SMatt Jacob 	 	cto->ct_header.rqs_entry_count = 1;
125105fbcbb0SMatt Jacob 		cto->ct_header.rqs_seqno = 1;
125265b024e1SMatt Jacob 		/* ct_reserved contains the handle set by caller */
125365b024e1SMatt Jacob 		/*
125465b024e1SMatt Jacob 		 * We preserve ct_lun, ct_iid, ct_rxid. We set the data
125565b024e1SMatt Jacob 		 * flags to NO DATA and clear relative offset flags.
125665b024e1SMatt Jacob 		 * We preserve the ct_resid and the response area.
125765b024e1SMatt Jacob 		 */
125865b024e1SMatt Jacob 		cto->ct_flags |= CT2_NO_DATA;
125905fbcbb0SMatt Jacob 		if (cto->ct_resid > 0)
126005fbcbb0SMatt Jacob 			cto->ct_flags |= CT2_DATA_UNDER;
126105fbcbb0SMatt Jacob 		else if (cto->ct_resid < 0)
126205fbcbb0SMatt Jacob 			cto->ct_flags |= CT2_DATA_OVER;
126365b024e1SMatt Jacob 		cto->ct_seg_count = 0;
126465b024e1SMatt Jacob 		cto->ct_reloff = 0;
126565b024e1SMatt Jacob 		ISP_TDQE(mp->isp, "dma2_tgt_fc[no data]", *mp->iptrp, cto);
1266d02373f1SMatt Jacob 		isp_prt(mp->isp, ISP_LOGTDEBUG1,
1267d02373f1SMatt Jacob 		    "CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x sts 0x%x ssts "
1268d02373f1SMatt Jacob 		    "0x%x res %d", cto->ct_rxid, csio->ccb_h.target_lun,
1269d02373f1SMatt Jacob 		    cto->ct_iid, cto->ct_flags, cto->ct_status,
127065b024e1SMatt Jacob 		    cto->rsp.m1.ct_scsi_status, cto->ct_resid);
127165b024e1SMatt Jacob 		ISP_SWIZ_CTIO2(isp, cto, cto);
12729e11e5beSMatt Jacob 		return;
12739e11e5beSMatt Jacob 	}
12749e11e5beSMatt Jacob 
127565b024e1SMatt Jacob 	if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE0) {
1276f7dddf8aSMatt Jacob 		isp_prt(mp->isp, ISP_LOGWARN,
1277f7dddf8aSMatt Jacob 		    "dma2_tgt_fc, a data CTIO2 without MODE0 set "
1278f7dddf8aSMatt Jacob 		    "(0x%x)", cto->ct_flags);
127965b024e1SMatt Jacob 		mp->error = EINVAL;
128065b024e1SMatt Jacob 		return;
128165b024e1SMatt Jacob 	}
128265b024e1SMatt Jacob 
128365b024e1SMatt Jacob 
128465b024e1SMatt Jacob 	nctios = nseg / ISP_RQDSEG_T2;
128565b024e1SMatt Jacob 	if (nseg % ISP_RQDSEG_T2) {
128665b024e1SMatt Jacob 		nctios++;
128765b024e1SMatt Jacob 	}
128865b024e1SMatt Jacob 
12899e11e5beSMatt Jacob 	/*
129065b024e1SMatt Jacob 	 * Save the handle, status, reloff, and residual. We'll reinsert the
129165b024e1SMatt Jacob 	 * handle into the last CTIO2 we're going to send, and reinsert status
129265b024e1SMatt Jacob 	 * and residual (and possibly sense data) if that's to be sent as well.
129365b024e1SMatt Jacob 	 *
129465b024e1SMatt Jacob 	 * We preserve ct_reloff and adjust it for each data CTIO2 we send past
129565b024e1SMatt Jacob 	 * the first one. This is needed so that the FCP DATA IUs being sent
129665b024e1SMatt Jacob 	 * out have the correct offset (they can arrive at the other end out
129765b024e1SMatt Jacob 	 * of order).
12989e11e5beSMatt Jacob 	 */
129965b024e1SMatt Jacob 
13009e11e5beSMatt Jacob 	handle = cto->ct_reserved;
13019e11e5beSMatt Jacob 	cto->ct_reserved = 0;
130265b024e1SMatt Jacob 
130365b024e1SMatt Jacob 	if ((send_status = (cto->ct_flags & CT2_SENDSTATUS)) != 0) {
13049e11e5beSMatt Jacob 		cto->ct_flags &= ~CT2_SENDSTATUS;
13059e11e5beSMatt Jacob 
130665b024e1SMatt Jacob 		/*
130705fbcbb0SMatt Jacob 		 * Preserve residual, which is actually the total count.
130865b024e1SMatt Jacob 		 */
130905fbcbb0SMatt Jacob 		datalen = cto->ct_resid;
131065b024e1SMatt Jacob 
131165b024e1SMatt Jacob 		/*
131265b024e1SMatt Jacob 		 * Save actual SCSI status. We'll reinsert the
131365b024e1SMatt Jacob 		 * CT2_SNSLEN_VALID later if appropriate.
131465b024e1SMatt Jacob 		 */
131565b024e1SMatt Jacob 		scsi_status = cto->rsp.m0.ct_scsi_status & 0xff;
131665b024e1SMatt Jacob 		send_sense = cto->rsp.m0.ct_scsi_status & CT2_SNSLEN_VALID;
131765b024e1SMatt Jacob 
131865b024e1SMatt Jacob 		/*
131965b024e1SMatt Jacob 		 * If we're sending status and have a CHECK CONDTION and
132065b024e1SMatt Jacob 		 * have sense data,  we send one more CTIO2 with just the
132165b024e1SMatt Jacob 		 * status and sense data. The upper layers have stashed
132265b024e1SMatt Jacob 		 * the sense data in the dataseg structure for us.
132365b024e1SMatt Jacob 		 */
132465b024e1SMatt Jacob 
132565b024e1SMatt Jacob 		if ((scsi_status & 0xf) == SCSI_STATUS_CHECK_COND &&
132665b024e1SMatt Jacob 		    send_sense) {
132765b024e1SMatt Jacob 			bcopy(cto->rsp.m0.ct_dataseg, sense, QLTM_SENSELEN);
132865b024e1SMatt Jacob 			nctios++;
132965b024e1SMatt Jacob 		}
133065b024e1SMatt Jacob 	} else {
133105fbcbb0SMatt Jacob 		scsi_status = send_sense = datalen = 0;
133265b024e1SMatt Jacob 	}
133365b024e1SMatt Jacob 
133465b024e1SMatt Jacob 	totxfr = cto->ct_resid = 0;
133565b024e1SMatt Jacob 	cto->rsp.m0.ct_scsi_status = 0;
133665b024e1SMatt Jacob 	bzero(&cto->rsp, sizeof (cto->rsp));
133765b024e1SMatt Jacob 
13389e11e5beSMatt Jacob 	pci = (struct isp_pcisoftc *)mp->isp;
1339469b6b9eSMatt Jacob 	dp = &pci->dmaps[isp_handle_index(handle)];
13409e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
13419e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
13429e11e5beSMatt Jacob 	} else {
13439e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
13449e11e5beSMatt Jacob 	}
13459e11e5beSMatt Jacob 
13469e11e5beSMatt Jacob 	while (nctios--) {
13479e11e5beSMatt Jacob 		int seg, seglim;
13489e11e5beSMatt Jacob 
13499e11e5beSMatt Jacob 		seglim = nseg;
135065b024e1SMatt Jacob 		if (seglim) {
13519e11e5beSMatt Jacob 			if (seglim > ISP_RQDSEG_T2)
13529e11e5beSMatt Jacob 				seglim = ISP_RQDSEG_T2;
13539e11e5beSMatt Jacob 
13549e11e5beSMatt Jacob 			for (seg = 0; seg < seglim; seg++) {
135565b024e1SMatt Jacob 				cto->rsp.m0.ct_dataseg[seg].ds_base =
135665b024e1SMatt Jacob 				    dm_segs->ds_addr;
135765b024e1SMatt Jacob 				cto->rsp.m0.ct_dataseg[seg].ds_count =
135865b024e1SMatt Jacob 				    dm_segs->ds_len;
13599e11e5beSMatt Jacob 				cto->rsp.m0.ct_xfrlen += dm_segs->ds_len;
136065b024e1SMatt Jacob 				totxfr += dm_segs->ds_len;
13619e11e5beSMatt Jacob 				dm_segs++;
13629e11e5beSMatt Jacob 			}
13639e11e5beSMatt Jacob 			cto->ct_seg_count = seg;
13649e11e5beSMatt Jacob 		} else {
136565b024e1SMatt Jacob 			/*
136665b024e1SMatt Jacob 			 * This case should only happen when we're sending a
136765b024e1SMatt Jacob 			 * synthesized MODE1 final status with sense data.
136865b024e1SMatt Jacob 			 */
136965b024e1SMatt Jacob 			if (send_sense == 0) {
1370f7dddf8aSMatt Jacob 				isp_prt(mp->isp, ISP_LOGWARN,
1371f7dddf8aSMatt Jacob 				    "dma2_tgt_fc ran out of segments, "
1372f7dddf8aSMatt Jacob 				    "no SENSE DATA");
137365b024e1SMatt Jacob 				mp->error = EINVAL;
137465b024e1SMatt Jacob 				return;
137565b024e1SMatt Jacob 			}
13769e11e5beSMatt Jacob 		}
13779e11e5beSMatt Jacob 
13789e11e5beSMatt Jacob 		/*
137965b024e1SMatt Jacob 		 * At this point, the fields ct_lun, ct_iid, ct_rxid,
138065b024e1SMatt Jacob 		 * ct_timeout have been carried over unchanged from what
138165b024e1SMatt Jacob 		 * our caller had set.
138265b024e1SMatt Jacob 		 *
138365b024e1SMatt Jacob 		 * The field ct_reloff is either what the caller set, or
138465b024e1SMatt Jacob 		 * what we've added to below.
138565b024e1SMatt Jacob 		 *
138665b024e1SMatt Jacob 		 * The dataseg fields and the seg_count fields we just got
138765b024e1SMatt Jacob 		 * through setting. The data direction we've preserved all
138865b024e1SMatt Jacob 		 * along and only clear it if we're sending a MODE1 status
138965b024e1SMatt Jacob 		 * as the last CTIO.
139065b024e1SMatt Jacob 		 *
139165b024e1SMatt Jacob 		 */
139265b024e1SMatt Jacob 
139365b024e1SMatt Jacob 		if (nctios == 0) {
139465b024e1SMatt Jacob 
139565b024e1SMatt Jacob 			/*
139665b024e1SMatt Jacob 			 * We're the last in a sequence of CTIO2s, so mark this
139765b024e1SMatt Jacob 			 * CTIO2 and save the handle to the CCB such that when
139865b024e1SMatt Jacob 			 * this CTIO2 completes we can free dma resources and
13999e11e5beSMatt Jacob 			 * do whatever else we need to do to finish the rest
14009e11e5beSMatt Jacob 			 * of the command.
14019e11e5beSMatt Jacob 			 */
140265b024e1SMatt Jacob 
14039e11e5beSMatt Jacob 			cto->ct_reserved = handle;
140465b024e1SMatt Jacob 			cto->ct_header.rqs_seqno = 1;
140565b024e1SMatt Jacob 
140665b024e1SMatt Jacob 			if (send_status) {
140765b024e1SMatt Jacob 				if (send_sense) {
140865b024e1SMatt Jacob 					bcopy(sense, cto->rsp.m1.ct_resp,
140965b024e1SMatt Jacob 					    QLTM_SENSELEN);
141065b024e1SMatt Jacob 					cto->rsp.m1.ct_senselen =
141165b024e1SMatt Jacob 					    QLTM_SENSELEN;
141265b024e1SMatt Jacob 					scsi_status |= CT2_SNSLEN_VALID;
141365b024e1SMatt Jacob 					cto->rsp.m1.ct_scsi_status =
141465b024e1SMatt Jacob 					    scsi_status;
141565b024e1SMatt Jacob 					cto->ct_flags &= CT2_FLAG_MMASK;
141665b024e1SMatt Jacob 					cto->ct_flags |= CT2_FLAG_MODE1 |
141765b024e1SMatt Jacob 					    CT2_NO_DATA| CT2_SENDSTATUS;
141865b024e1SMatt Jacob 				} else {
141965b024e1SMatt Jacob 					cto->rsp.m0.ct_scsi_status =
142065b024e1SMatt Jacob 					    scsi_status;
142165b024e1SMatt Jacob 					cto->ct_flags |= CT2_SENDSTATUS;
142265b024e1SMatt Jacob 				}
142305fbcbb0SMatt Jacob 				/*
142405fbcbb0SMatt Jacob 				 * Get 'real' residual and set flags based
142505fbcbb0SMatt Jacob 				 * on it.
142605fbcbb0SMatt Jacob 				 */
142705fbcbb0SMatt Jacob 				cto->ct_resid = datalen - totxfr;
142805fbcbb0SMatt Jacob 				if (cto->ct_resid > 0)
142905fbcbb0SMatt Jacob 					cto->ct_flags |= CT2_DATA_UNDER;
143005fbcbb0SMatt Jacob 				else if (cto->ct_resid < 0)
143105fbcbb0SMatt Jacob 					cto->ct_flags |= CT2_DATA_OVER;
143265b024e1SMatt Jacob 			}
14339e11e5beSMatt Jacob 			ISP_TDQE(mp->isp, "last dma2_tgt_fc", *mp->iptrp, cto);
1434d02373f1SMatt Jacob 			isp_prt(mp->isp, ISP_LOGTDEBUG1,
1435d02373f1SMatt Jacob 			    "CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x sts 0x%x"
1436d02373f1SMatt Jacob 			    " ssts 0x%x res %d", cto->ct_rxid,
143765b024e1SMatt Jacob 			    csio->ccb_h.target_lun, (int) cto->ct_iid,
143842426921SMatt Jacob 			    cto->ct_flags, cto->ct_status,
143965b024e1SMatt Jacob 			    cto->rsp.m1.ct_scsi_status, cto->ct_resid);
144065b024e1SMatt Jacob 			ISP_SWIZ_CTIO2(isp, cto, cto);
14419e11e5beSMatt Jacob 		} else {
14429e11e5beSMatt Jacob 			ct2_entry_t *octo = cto;
144365b024e1SMatt Jacob 
144465b024e1SMatt Jacob 			/*
144565b024e1SMatt Jacob 			 * Make sure handle fields are clean
144665b024e1SMatt Jacob 			 */
14479e11e5beSMatt Jacob 			cto->ct_reserved = 0;
14489e11e5beSMatt Jacob 			cto->ct_header.rqs_seqno = 0;
144965b024e1SMatt Jacob 
14509e11e5beSMatt Jacob 			ISP_TDQE(mp->isp, "dma2_tgt_fc", *mp->iptrp, cto);
1451d02373f1SMatt Jacob 			isp_prt(mp->isp, ISP_LOGTDEBUG1,
1452d02373f1SMatt Jacob 			    "CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x",
1453d02373f1SMatt Jacob 			    cto->ct_rxid, csio->ccb_h.target_lun,
1454d02373f1SMatt Jacob 			    (int) cto->ct_iid, cto->ct_flags);
145565b024e1SMatt Jacob 			/*
145665b024e1SMatt Jacob 			 * Get a new CTIO2
145765b024e1SMatt Jacob 			 */
14589e11e5beSMatt Jacob 			cto = (ct2_entry_t *)
14599e11e5beSMatt Jacob 			    ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
14609e11e5beSMatt Jacob 			*mp->iptrp =
1461d02373f1SMatt Jacob 			    ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp));
14629e11e5beSMatt Jacob 			if (*mp->iptrp == mp->optr) {
1463f7dddf8aSMatt Jacob 				isp_prt(mp->isp, ISP_LOGWARN,
1464f7dddf8aSMatt Jacob 				    "Queue Overflow in dma2_tgt_fc");
14659e11e5beSMatt Jacob 				mp->error = MUSHERR_NOQENTRIES;
14669e11e5beSMatt Jacob 				return;
14679e11e5beSMatt Jacob 			}
146865b024e1SMatt Jacob 
14699e11e5beSMatt Jacob 			/*
147065b024e1SMatt Jacob 			 * Fill in the new CTIO2 with info from the old one.
14719e11e5beSMatt Jacob 			 */
14729e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
14739e11e5beSMatt Jacob 			cto->ct_header.rqs_entry_count = 1;
14749e11e5beSMatt Jacob 			cto->ct_header.rqs_flags = 0;
147565b024e1SMatt Jacob 			/* ct_header.rqs_seqno && ct_reserved done later */
14769e11e5beSMatt Jacob 			cto->ct_lun = octo->ct_lun;
14779e11e5beSMatt Jacob 			cto->ct_iid = octo->ct_iid;
14789e11e5beSMatt Jacob 			cto->ct_rxid = octo->ct_rxid;
147965b024e1SMatt Jacob 			cto->ct_flags = octo->ct_flags;
14809e11e5beSMatt Jacob 			cto->ct_status = 0;
14819e11e5beSMatt Jacob 			cto->ct_resid = 0;
14829e11e5beSMatt Jacob 			cto->ct_timeout = octo->ct_timeout;
14839e11e5beSMatt Jacob 			cto->ct_seg_count = 0;
148465b024e1SMatt Jacob 			/*
148565b024e1SMatt Jacob 			 * Adjust the new relative offset by the amount which
148665b024e1SMatt Jacob 			 * is recorded in the data segment of the old CTIO2 we
148765b024e1SMatt Jacob 			 * just finished filling out.
148865b024e1SMatt Jacob 			 */
148965b024e1SMatt Jacob 			cto->ct_reloff += octo->rsp.m0.ct_xfrlen;
14909e11e5beSMatt Jacob 			bzero(&cto->rsp, sizeof (cto->rsp));
149165b024e1SMatt Jacob 			ISP_SWIZ_CTIO2(isp, cto, cto);
14929e11e5beSMatt Jacob 		}
14939e11e5beSMatt Jacob 	}
14949e11e5beSMatt Jacob }
14959e11e5beSMatt Jacob #endif
14969e11e5beSMatt Jacob 
14979e11e5beSMatt Jacob static void dma2 __P((void *, bus_dma_segment_t *, int, int));
14989e11e5beSMatt Jacob 
14999e11e5beSMatt Jacob static void
15009e11e5beSMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
15019e11e5beSMatt Jacob {
15029e11e5beSMatt Jacob 	mush_t *mp;
15039e11e5beSMatt Jacob 	struct ccb_scsiio *csio;
15049e11e5beSMatt Jacob 	struct isp_pcisoftc *pci;
15059e11e5beSMatt Jacob 	bus_dmamap_t *dp;
15069e11e5beSMatt Jacob 	bus_dma_segment_t *eseg;
15079e11e5beSMatt Jacob 	ispreq_t *rq;
15089e11e5beSMatt Jacob 	ispcontreq_t *crq;
15099e11e5beSMatt Jacob 	int seglim, datalen;
15109e11e5beSMatt Jacob 
15119e11e5beSMatt Jacob 	mp = (mush_t *) arg;
15129e11e5beSMatt Jacob 	if (error) {
15139e11e5beSMatt Jacob 		mp->error = error;
15149e11e5beSMatt Jacob 		return;
15159e11e5beSMatt Jacob 	}
15169e11e5beSMatt Jacob 
15179e11e5beSMatt Jacob 	if (nseg < 1) {
1518f7dddf8aSMatt Jacob 		isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg);
15199e11e5beSMatt Jacob 		mp->error = EFAULT;
15209e11e5beSMatt Jacob 		return;
15219e11e5beSMatt Jacob 	}
15229e11e5beSMatt Jacob 	csio = mp->cmd_token;
15239e11e5beSMatt Jacob 	rq = mp->rq;
15249e11e5beSMatt Jacob 	pci = (struct isp_pcisoftc *)mp->isp;
1525469b6b9eSMatt Jacob 	dp = &pci->dmaps[isp_handle_index(rq->req_handle)];
15269e11e5beSMatt Jacob 
15279e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
15289e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
15299e11e5beSMatt Jacob 	} else {
15309e11e5beSMatt Jacob 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
15319e11e5beSMatt Jacob 	}
15329e11e5beSMatt Jacob 
15339e11e5beSMatt Jacob 	datalen = XS_XFRLEN(csio);
15349e11e5beSMatt Jacob 
15359e11e5beSMatt Jacob 	/*
15369e11e5beSMatt Jacob 	 * We're passed an initial partially filled in entry that
15379e11e5beSMatt Jacob 	 * has most fields filled in except for data transfer
15389e11e5beSMatt Jacob 	 * related values.
15399e11e5beSMatt Jacob 	 *
15409e11e5beSMatt Jacob 	 * Our job is to fill in the initial request queue entry and
15419e11e5beSMatt Jacob 	 * then to start allocating and filling in continuation entries
15429e11e5beSMatt Jacob 	 * until we've covered the entire transfer.
15439e11e5beSMatt Jacob 	 */
15449e11e5beSMatt Jacob 
15459e11e5beSMatt Jacob 	if (IS_FC(mp->isp)) {
1546d720e6d5SJustin T. Gibbs 		seglim = ISP_RQDSEG_T2;
1547d720e6d5SJustin T. Gibbs 		((ispreqt2_t *)rq)->req_totalcnt = datalen;
15489e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
15499e11e5beSMatt Jacob 			((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_IN;
15509e11e5beSMatt Jacob 		} else {
15519e11e5beSMatt Jacob 			((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_OUT;
15529e11e5beSMatt Jacob 		}
1553d720e6d5SJustin T. Gibbs 	} else {
1554e142669aSMatt Jacob 		if (csio->cdb_len > 12) {
1555e142669aSMatt Jacob 			seglim = 0;
1556e142669aSMatt Jacob 		} else {
1557d720e6d5SJustin T. Gibbs 			seglim = ISP_RQDSEG;
1558e142669aSMatt Jacob 		}
15599e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
15609e11e5beSMatt Jacob 			rq->req_flags |= REQFLAG_DATA_IN;
15619e11e5beSMatt Jacob 		} else {
15629e11e5beSMatt Jacob 			rq->req_flags |= REQFLAG_DATA_OUT;
15639e11e5beSMatt Jacob 		}
1564d720e6d5SJustin T. Gibbs 	}
1565d720e6d5SJustin T. Gibbs 
1566d720e6d5SJustin T. Gibbs 	eseg = dm_segs + nseg;
1567d720e6d5SJustin T. Gibbs 
1568d720e6d5SJustin T. Gibbs 	while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) {
15699e11e5beSMatt Jacob 		if (IS_FC(mp->isp)) {
1570d720e6d5SJustin T. Gibbs 			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
1571d720e6d5SJustin T. Gibbs 			rq2->req_dataseg[rq2->req_seg_count].ds_base =
1572d720e6d5SJustin T. Gibbs 			    dm_segs->ds_addr;
1573d720e6d5SJustin T. Gibbs 			rq2->req_dataseg[rq2->req_seg_count].ds_count =
1574d720e6d5SJustin T. Gibbs 			    dm_segs->ds_len;
1575d720e6d5SJustin T. Gibbs 		} else {
1576d720e6d5SJustin T. Gibbs 			rq->req_dataseg[rq->req_seg_count].ds_base =
1577d720e6d5SJustin T. Gibbs 				dm_segs->ds_addr;
1578d720e6d5SJustin T. Gibbs 			rq->req_dataseg[rq->req_seg_count].ds_count =
1579d720e6d5SJustin T. Gibbs 				dm_segs->ds_len;
1580d720e6d5SJustin T. Gibbs 		}
1581d720e6d5SJustin T. Gibbs 		datalen -= dm_segs->ds_len;
1582d720e6d5SJustin T. Gibbs #if	0
15839e11e5beSMatt Jacob 		if (IS_FC(mp->isp)) {
1584d720e6d5SJustin T. Gibbs 			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
1585d720e6d5SJustin T. Gibbs 			printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n",
15869e11e5beSMatt Jacob 			    mp->isp->isp_name, rq->req_seg_count,
1587d720e6d5SJustin T. Gibbs 			    rq2->req_dataseg[rq2->req_seg_count].ds_count,
1588d720e6d5SJustin T. Gibbs 			    rq2->req_dataseg[rq2->req_seg_count].ds_base);
1589d720e6d5SJustin T. Gibbs 		} else {
1590d720e6d5SJustin T. Gibbs 			printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n",
15919e11e5beSMatt Jacob 			    mp->isp->isp_name, rq->req_seg_count,
1592d720e6d5SJustin T. Gibbs 			    rq->req_dataseg[rq->req_seg_count].ds_count,
1593d720e6d5SJustin T. Gibbs 			    rq->req_dataseg[rq->req_seg_count].ds_base);
1594d720e6d5SJustin T. Gibbs 		}
1595d720e6d5SJustin T. Gibbs #endif
1596d720e6d5SJustin T. Gibbs 		rq->req_seg_count++;
1597d720e6d5SJustin T. Gibbs 		dm_segs++;
1598d720e6d5SJustin T. Gibbs 	}
1599d720e6d5SJustin T. Gibbs 
1600d720e6d5SJustin T. Gibbs 	while (datalen > 0 && dm_segs != eseg) {
16019e11e5beSMatt Jacob 		crq = (ispcontreq_t *)
16029e11e5beSMatt Jacob 		    ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
1603d02373f1SMatt Jacob 		*mp->iptrp = ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp));
16049e11e5beSMatt Jacob 		if (*mp->iptrp == mp->optr) {
16054873663cSMatt Jacob #if	0
16069e11e5beSMatt Jacob 			printf("%s: Request Queue Overflow++\n",
16079e11e5beSMatt Jacob 			    mp->isp->isp_name);
16084873663cSMatt Jacob #endif
16094873663cSMatt Jacob 			mp->error = MUSHERR_NOQENTRIES;
1610d720e6d5SJustin T. Gibbs 			return;
1611d720e6d5SJustin T. Gibbs 		}
1612d720e6d5SJustin T. Gibbs 		rq->req_header.rqs_entry_count++;
1613d720e6d5SJustin T. Gibbs 		bzero((void *)crq, sizeof (*crq));
1614d720e6d5SJustin T. Gibbs 		crq->req_header.rqs_entry_count = 1;
1615d720e6d5SJustin T. Gibbs 		crq->req_header.rqs_entry_type = RQSTYPE_DATASEG;
1616d720e6d5SJustin T. Gibbs 
1617d720e6d5SJustin T. Gibbs 		seglim = 0;
1618d720e6d5SJustin T. Gibbs 		while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) {
1619d720e6d5SJustin T. Gibbs 			crq->req_dataseg[seglim].ds_base =
1620d720e6d5SJustin T. Gibbs 			    dm_segs->ds_addr;
1621d720e6d5SJustin T. Gibbs 			crq->req_dataseg[seglim].ds_count =
1622d720e6d5SJustin T. Gibbs 			    dm_segs->ds_len;
1623d720e6d5SJustin T. Gibbs #if	0
1624d720e6d5SJustin T. Gibbs 			printf("%s: seg%d[%d] cnt 0x%x paddr 0x%08x\n",
16259e11e5beSMatt Jacob 			    mp->isp->isp_name, rq->req_header.rqs_entry_count-1,
1626d720e6d5SJustin T. Gibbs 			    seglim, crq->req_dataseg[seglim].ds_count,
1627d720e6d5SJustin T. Gibbs 			    crq->req_dataseg[seglim].ds_base);
1628d720e6d5SJustin T. Gibbs #endif
1629d720e6d5SJustin T. Gibbs 			rq->req_seg_count++;
1630d720e6d5SJustin T. Gibbs 			dm_segs++;
1631d720e6d5SJustin T. Gibbs 			seglim++;
1632d720e6d5SJustin T. Gibbs 			datalen -= dm_segs->ds_len;
1633d720e6d5SJustin T. Gibbs 		}
1634d720e6d5SJustin T. Gibbs 	}
1635d720e6d5SJustin T. Gibbs }
1636d720e6d5SJustin T. Gibbs 
1637d720e6d5SJustin T. Gibbs static int
16389e11e5beSMatt Jacob isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq,
16399637d68cSMatt Jacob 	u_int16_t *iptrp, u_int16_t optr)
1640d720e6d5SJustin T. Gibbs {
1641d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
16420a5f7e8bSMatt Jacob 	bus_dmamap_t *dp = NULL;
1643d720e6d5SJustin T. Gibbs 	mush_t mush, *mp;
16449e11e5beSMatt Jacob 	void (*eptr) __P((void *, bus_dma_segment_t *, int, int));
1645d720e6d5SJustin T. Gibbs 
164665b024e1SMatt Jacob #ifdef	ISP_TARGET_MODE
164765b024e1SMatt Jacob 	if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) {
164865b024e1SMatt Jacob 		if (IS_FC(isp)) {
164905fbcbb0SMatt Jacob 			eptr = tdma_mkfc;
165065b024e1SMatt Jacob 		} else {
165105fbcbb0SMatt Jacob 			eptr = tdma_mk;
165265b024e1SMatt Jacob 		}
165305fbcbb0SMatt Jacob 		if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE ||
165405fbcbb0SMatt Jacob 		    (csio->dxfer_len == 0)) {
165565b024e1SMatt Jacob 			rq->req_seg_count = 1;
165665b024e1SMatt Jacob 			mp = &mush;
165765b024e1SMatt Jacob 			mp->isp = isp;
165865b024e1SMatt Jacob 			mp->cmd_token = csio;
165965b024e1SMatt Jacob 			mp->rq = rq;
166065b024e1SMatt Jacob 			mp->iptrp = iptrp;
166165b024e1SMatt Jacob 			mp->optr = optr;
166265b024e1SMatt Jacob 			mp->error = 0;
166365b024e1SMatt Jacob 			(*eptr)(mp, NULL, 0, 0);
166465b024e1SMatt Jacob 			goto exit;
166565b024e1SMatt Jacob 		}
166665b024e1SMatt Jacob 	} else
166765b024e1SMatt Jacob #endif
166865b024e1SMatt Jacob 	eptr = dma2;
166965b024e1SMatt Jacob 
167042426921SMatt Jacob 	/*
167142426921SMatt Jacob 	 * NB: if we need to do request queue entry swizzling,
167242426921SMatt Jacob 	 * NB: this is where it would need to be done for cmds
167342426921SMatt Jacob 	 * NB: that move no data. For commands that move data,
167442426921SMatt Jacob 	 * NB: swizzling would take place in those functions.
167542426921SMatt Jacob 	 */
167605fbcbb0SMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE ||
167705fbcbb0SMatt Jacob 	    (csio->dxfer_len == 0)) {
167842426921SMatt Jacob 		rq->req_seg_count = 1;
167942426921SMatt Jacob 		return (CMD_QUEUED);
168042426921SMatt Jacob 	}
168142426921SMatt Jacob 
1682d720e6d5SJustin T. Gibbs 	/*
1683d720e6d5SJustin T. Gibbs 	 * Do a virtual grapevine step to collect info for
16844873663cSMatt Jacob 	 * the callback dma allocation that we have to use...
1685d720e6d5SJustin T. Gibbs 	 */
1686d720e6d5SJustin T. Gibbs 	mp = &mush;
1687d720e6d5SJustin T. Gibbs 	mp->isp = isp;
16889e11e5beSMatt Jacob 	mp->cmd_token = csio;
1689d720e6d5SJustin T. Gibbs 	mp->rq = rq;
1690d720e6d5SJustin T. Gibbs 	mp->iptrp = iptrp;
1691d720e6d5SJustin T. Gibbs 	mp->optr = optr;
1692d720e6d5SJustin T. Gibbs 	mp->error = 0;
1693d720e6d5SJustin T. Gibbs 
16949e11e5beSMatt Jacob 	if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
16959e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) {
16964873663cSMatt Jacob 			int error, s;
1697469b6b9eSMatt Jacob 			dp = &pci->dmaps[isp_handle_index(rq->req_handle)];
1698d720e6d5SJustin T. Gibbs 			s = splsoftvm();
1699d720e6d5SJustin T. Gibbs 			error = bus_dmamap_load(pci->parent_dmat, *dp,
17009e11e5beSMatt Jacob 			    csio->data_ptr, csio->dxfer_len, eptr, mp, 0);
1701d720e6d5SJustin T. Gibbs 			if (error == EINPROGRESS) {
1702d720e6d5SJustin T. Gibbs 				bus_dmamap_unload(pci->parent_dmat, *dp);
1703d720e6d5SJustin T. Gibbs 				mp->error = EINVAL;
1704f7dddf8aSMatt Jacob 				isp_prt(isp, ISP_LOGERR,
1705f7dddf8aSMatt Jacob 				    "deferred dma allocation not supported");
1706d720e6d5SJustin T. Gibbs 			} else if (error && mp->error == 0) {
17070a5f7e8bSMatt Jacob #ifdef	DIAGNOSTIC
17080a5f7e8bSMatt Jacob 				printf("%s: error %d in dma mapping code\n",
17090a5f7e8bSMatt Jacob 				    isp->isp_name, error);
17100a5f7e8bSMatt Jacob #endif
1711d720e6d5SJustin T. Gibbs 				mp->error = error;
1712d720e6d5SJustin T. Gibbs 			}
17134873663cSMatt Jacob 			splx(s);
1714d720e6d5SJustin T. Gibbs 		} else {
1715d720e6d5SJustin T. Gibbs 			/* Pointer to physical buffer */
1716d720e6d5SJustin T. Gibbs 			struct bus_dma_segment seg;
1717d720e6d5SJustin T. Gibbs 			seg.ds_addr = (bus_addr_t)csio->data_ptr;
1718d720e6d5SJustin T. Gibbs 			seg.ds_len = csio->dxfer_len;
17199e11e5beSMatt Jacob 			(*eptr)(mp, &seg, 1, 0);
1720d720e6d5SJustin T. Gibbs 		}
1721d720e6d5SJustin T. Gibbs 	} else {
1722d720e6d5SJustin T. Gibbs 		struct bus_dma_segment *segs;
1723d720e6d5SJustin T. Gibbs 
17249e11e5beSMatt Jacob 		if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) {
1725f7dddf8aSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
1726f7dddf8aSMatt Jacob 			    "Physical segment pointers unsupported");
1727d720e6d5SJustin T. Gibbs 			mp->error = EINVAL;
17289e11e5beSMatt Jacob 		} else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) {
1729f7dddf8aSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
1730f7dddf8aSMatt Jacob 			    "Virtual segment addresses unsupported");
1731d720e6d5SJustin T. Gibbs 			mp->error = EINVAL;
1732d720e6d5SJustin T. Gibbs 		} else {
1733d720e6d5SJustin T. Gibbs 			/* Just use the segments provided */
1734d720e6d5SJustin T. Gibbs 			segs = (struct bus_dma_segment *) csio->data_ptr;
17359e11e5beSMatt Jacob 			(*eptr)(mp, segs, csio->sglist_cnt, 0);
1736d720e6d5SJustin T. Gibbs 		}
1737d720e6d5SJustin T. Gibbs 	}
1738003a310fSMatt Jacob #ifdef	ISP_TARGET_MODE
173965b024e1SMatt Jacob exit:
1740003a310fSMatt Jacob #endif
1741d720e6d5SJustin T. Gibbs 	if (mp->error) {
17424873663cSMatt Jacob 		int retval = CMD_COMPLETE;
17434873663cSMatt Jacob 		if (mp->error == MUSHERR_NOQENTRIES) {
17444873663cSMatt Jacob 			retval = CMD_EAGAIN;
17454873663cSMatt Jacob 		} else if (mp->error == EFBIG) {
17460a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_REQ_TOO_BIG);
1747d720e6d5SJustin T. Gibbs 		} else if (mp->error == EINVAL) {
17480a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_REQ_INVALID);
1749d720e6d5SJustin T. Gibbs 		} else {
17500a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_UNREC_HBA_ERROR);
1751d720e6d5SJustin T. Gibbs 		}
17524873663cSMatt Jacob 		return (retval);
17534873663cSMatt Jacob 	} else {
17540a5f7e8bSMatt Jacob 		/*
17550a5f7e8bSMatt Jacob 		 * Check to see if we weren't cancelled while sleeping on
17560a5f7e8bSMatt Jacob 		 * getting DMA resources...
17570a5f7e8bSMatt Jacob 		 */
17589e11e5beSMatt Jacob 		if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
17590a5f7e8bSMatt Jacob 			if (dp) {
17600a5f7e8bSMatt Jacob 				bus_dmamap_unload(pci->parent_dmat, *dp);
17610a5f7e8bSMatt Jacob 			}
17620a5f7e8bSMatt Jacob 			return (CMD_COMPLETE);
17630a5f7e8bSMatt Jacob 		}
17644873663cSMatt Jacob 		return (CMD_QUEUED);
1765d720e6d5SJustin T. Gibbs 	}
1766d720e6d5SJustin T. Gibbs }
1767d720e6d5SJustin T. Gibbs 
1768d720e6d5SJustin T. Gibbs static void
1769d02373f1SMatt Jacob isp_pci_dmateardown(struct ispsoftc *isp, XS_T *xs, u_int32_t handle)
1770d720e6d5SJustin T. Gibbs {
1771d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
1772469b6b9eSMatt Jacob 	bus_dmamap_t *dp = &pci->dmaps[isp_handle_index(handle)];
1773a95ae193SMatt Jacob 	if ((xs->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1774d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTREAD);
1775d720e6d5SJustin T. Gibbs 	} else {
1776d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTWRITE);
1777d720e6d5SJustin T. Gibbs 	}
1778d720e6d5SJustin T. Gibbs 	bus_dmamap_unload(pci->parent_dmat, *dp);
1779d720e6d5SJustin T. Gibbs }
1780d720e6d5SJustin T. Gibbs 
178165adb54cSMatt Jacob 
178265adb54cSMatt Jacob static void
178317e318c6SMatt Jacob isp_pci_reset1(struct ispsoftc *isp)
178465adb54cSMatt Jacob {
178565adb54cSMatt Jacob 	/* Make sure the BIOS is disabled */
178665adb54cSMatt Jacob 	isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS);
1787469b6b9eSMatt Jacob 	/* and enable interrupts */
1788469b6b9eSMatt Jacob 	ENABLE_INTS(isp);
178965adb54cSMatt Jacob }
179065adb54cSMatt Jacob 
179165adb54cSMatt Jacob static void
1792d02373f1SMatt Jacob isp_pci_dumpregs(struct ispsoftc *isp, const char *msg)
179365adb54cSMatt Jacob {
179465adb54cSMatt Jacob 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
1795d02373f1SMatt Jacob 	if (msg)
1796d02373f1SMatt Jacob 		printf("%s: %s\n", isp->isp_name, msg);
1797d02373f1SMatt Jacob 	if (IS_SCSI(isp))
1798d02373f1SMatt Jacob 		printf("    biu_conf1=%x", ISP_READ(isp, BIU_CONF1));
1799d02373f1SMatt Jacob 	else
1800d02373f1SMatt Jacob 		printf("    biu_csr=%x", ISP_READ(isp, BIU2100_CSR));
1801d02373f1SMatt Jacob 	printf(" biu_icr=%x biu_isr=%x biu_sema=%x ", ISP_READ(isp, BIU_ICR),
1802d02373f1SMatt Jacob 	    ISP_READ(isp, BIU_ISR), ISP_READ(isp, BIU_SEMA));
1803d02373f1SMatt Jacob 	printf("risc_hccr=%x\n", ISP_READ(isp, HCCR));
1804d02373f1SMatt Jacob 
1805d02373f1SMatt Jacob 
1806d02373f1SMatt Jacob 	if (IS_SCSI(isp)) {
1807d02373f1SMatt Jacob 		ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE);
1808d02373f1SMatt Jacob 		printf("    cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n",
1809d02373f1SMatt Jacob 			ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS),
1810d02373f1SMatt Jacob 			ISP_READ(isp, CDMA_FIFO_STS));
1811d02373f1SMatt Jacob 		printf("    ddma_conf=%x ddma_sts=%x ddma_fifostat=%x\n",
1812d02373f1SMatt Jacob 			ISP_READ(isp, DDMA_CONF), ISP_READ(isp, DDMA_STATUS),
1813d02373f1SMatt Jacob 			ISP_READ(isp, DDMA_FIFO_STS));
1814d02373f1SMatt Jacob 		printf("    sxp_int=%x sxp_gross=%x sxp(scsi_ctrl)=%x\n",
1815d02373f1SMatt Jacob 			ISP_READ(isp, SXP_INTERRUPT),
1816d02373f1SMatt Jacob 			ISP_READ(isp, SXP_GROSS_ERR),
1817d02373f1SMatt Jacob 			ISP_READ(isp, SXP_PINS_CTRL));
1818d02373f1SMatt Jacob 		ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE);
1819d02373f1SMatt Jacob 	}
1820d02373f1SMatt Jacob 	printf("    mbox regs: %x %x %x %x %x\n",
1821d02373f1SMatt Jacob 	    ISP_READ(isp, OUTMAILBOX0), ISP_READ(isp, OUTMAILBOX1),
1822d02373f1SMatt Jacob 	    ISP_READ(isp, OUTMAILBOX2), ISP_READ(isp, OUTMAILBOX3),
1823d02373f1SMatt Jacob 	    ISP_READ(isp, OUTMAILBOX4));
1824d02373f1SMatt Jacob 	printf("    PCI Status Command/Status=%x\n",
1825960f6939SMatt Jacob 	    pci_read_config(pci->pci_dev, PCIR_COMMAND, 1));
182665adb54cSMatt Jacob }
1827