xref: /freebsd/sys/dev/isp/isp_pci.c (revision fed92c475e9ca96f3fde40db98869e4d8ad24f7e)
1c3aac50fSPeter Wemm /* $FreeBSD$ */
265adb54cSMatt Jacob /*
365adb54cSMatt Jacob  * PCI specific probe and attach routines for Qlogic ISP SCSI adapters.
465adb54cSMatt Jacob  * FreeBSD Version.
565adb54cSMatt Jacob  *
665adb54cSMatt Jacob  *---------------------------------------
7222bb542SMatt Jacob  * Copyright (c) 1997, 1998, 1999 by Matthew Jacob
865adb54cSMatt Jacob  * NASA/Ames Research Center
965adb54cSMatt Jacob  * All rights reserved.
1065adb54cSMatt Jacob  *---------------------------------------
1165adb54cSMatt Jacob  *
1265adb54cSMatt Jacob  * Redistribution and use in source and binary forms, with or without
1365adb54cSMatt Jacob  * modification, are permitted provided that the following conditions
1465adb54cSMatt Jacob  * are met:
1565adb54cSMatt Jacob  * 1. Redistributions of source code must retain the above copyright
1665adb54cSMatt Jacob  *    notice immediately at the beginning of the file, without modification,
1765adb54cSMatt Jacob  *    this list of conditions, and the following disclaimer.
1865adb54cSMatt Jacob  * 2. Redistributions in binary form must reproduce the above copyright
1965adb54cSMatt Jacob  *    notice, this list of conditions and the following disclaimer in the
2065adb54cSMatt Jacob  *    documentation and/or other materials provided with the distribution.
2165adb54cSMatt Jacob  * 3. The name of the author may not be used to endorse or promote products
2265adb54cSMatt Jacob  *    derived from this software without specific prior written permission.
2365adb54cSMatt Jacob  *
2465adb54cSMatt Jacob  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2565adb54cSMatt Jacob  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2665adb54cSMatt Jacob  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2765adb54cSMatt Jacob  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2865adb54cSMatt Jacob  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2965adb54cSMatt Jacob  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3065adb54cSMatt Jacob  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3165adb54cSMatt Jacob  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3265adb54cSMatt Jacob  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3365adb54cSMatt Jacob  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3465adb54cSMatt Jacob  * SUCH DAMAGE.
3565adb54cSMatt Jacob  */
3665adb54cSMatt Jacob #include <dev/isp/isp_freebsd.h>
3765adb54cSMatt Jacob #include <dev/isp/asm_pci.h>
38d720e6d5SJustin T. Gibbs #include <sys/malloc.h>
39d720e6d5SJustin T. Gibbs #include <vm/vm.h>
40d720e6d5SJustin T. Gibbs #include <vm/pmap.h>
41d720e6d5SJustin T. Gibbs 
4265adb54cSMatt Jacob 
4365adb54cSMatt Jacob #include <pci/pcireg.h>
4465adb54cSMatt Jacob #include <pci/pcivar.h>
4565adb54cSMatt Jacob 
46d720e6d5SJustin T. Gibbs #include <machine/bus_memio.h>
47d720e6d5SJustin T. Gibbs #include <machine/bus_pio.h>
48d720e6d5SJustin T. Gibbs #include <machine/bus.h>
49a95ae193SMatt Jacob #include <machine/md_var.h>
50d59bd469SMatt Jacob 
5165adb54cSMatt Jacob static u_int16_t isp_pci_rd_reg __P((struct ispsoftc *, int));
5265adb54cSMatt Jacob static void isp_pci_wr_reg __P((struct ispsoftc *, int, u_int16_t));
53d59bd469SMatt Jacob #ifndef ISP_DISABLE_1080_SUPPORT
54d59bd469SMatt Jacob static u_int16_t isp_pci_rd_reg_1080 __P((struct ispsoftc *, int));
55d59bd469SMatt Jacob static void isp_pci_wr_reg_1080 __P((struct ispsoftc *, int, u_int16_t));
56d59bd469SMatt Jacob #endif
5765adb54cSMatt Jacob static int isp_pci_mbxdma __P((struct ispsoftc *));
5865adb54cSMatt Jacob static int isp_pci_dmasetup __P((struct ispsoftc *, ISP_SCSI_XFER_T *,
5965adb54cSMatt Jacob 	ispreq_t *, u_int8_t *, u_int8_t));
60d720e6d5SJustin T. Gibbs static void
61d720e6d5SJustin T. Gibbs isp_pci_dmateardown __P((struct ispsoftc *, ISP_SCSI_XFER_T *, u_int32_t));
6265adb54cSMatt Jacob 
6365adb54cSMatt Jacob static void isp_pci_reset1 __P((struct ispsoftc *));
6465adb54cSMatt Jacob static void isp_pci_dumpregs __P((struct ispsoftc *));
6565adb54cSMatt Jacob 
66fed92c47SMatt Jacob #ifndef	ISP_CODE_ORG
67fed92c47SMatt Jacob #define	ISP_CODE_ORG		0x1000
68fed92c47SMatt Jacob #endif
69fed92c47SMatt Jacob #ifndef	ISP_1040_RISC_CODE
70fed92c47SMatt Jacob #define	ISP_1040_RISC_CODE	NULL
71fed92c47SMatt Jacob #endif
72fed92c47SMatt Jacob #ifndef	ISP_1080_RISC_CODE
73fed92c47SMatt Jacob #define	ISP_1080_RISC_CODE	NULL
74fed92c47SMatt Jacob #endif
75fed92c47SMatt Jacob #ifndef	ISP_2100_RISC_CODE
76fed92c47SMatt Jacob #define	ISP_2100_RISC_CODE	NULL
77fed92c47SMatt Jacob #endif
78fed92c47SMatt Jacob #ifndef	ISP_2200_RISC_CODE
79fed92c47SMatt Jacob #define	ISP_2200_RISC_CODE	NULL
80fed92c47SMatt Jacob #endif
81fed92c47SMatt Jacob 
82d59bd469SMatt Jacob #ifndef ISP_DISABLE_1020_SUPPORT
8365adb54cSMatt Jacob static struct ispmdvec mdvec = {
8465adb54cSMatt Jacob 	isp_pci_rd_reg,
8565adb54cSMatt Jacob 	isp_pci_wr_reg,
8665adb54cSMatt Jacob 	isp_pci_mbxdma,
8765adb54cSMatt Jacob 	isp_pci_dmasetup,
88d720e6d5SJustin T. Gibbs 	isp_pci_dmateardown,
8965adb54cSMatt Jacob 	NULL,
9065adb54cSMatt Jacob 	isp_pci_reset1,
9165adb54cSMatt Jacob 	isp_pci_dumpregs,
92fed92c47SMatt Jacob 	ISP_1040_RISC_CODE,
93fed92c47SMatt Jacob 	0,
9465adb54cSMatt Jacob 	ISP_CODE_ORG,
95a95ae193SMatt Jacob 	0,
96285e230dSMatt Jacob 	BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64,
97d720e6d5SJustin T. Gibbs 	0
9865adb54cSMatt Jacob };
99d59bd469SMatt Jacob #endif
10065adb54cSMatt Jacob 
101d59bd469SMatt Jacob #ifndef ISP_DISABLE_1080_SUPPORT
102d59bd469SMatt Jacob static struct ispmdvec mdvec_1080 = {
103d59bd469SMatt Jacob 	isp_pci_rd_reg_1080,
104d59bd469SMatt Jacob 	isp_pci_wr_reg_1080,
105d59bd469SMatt Jacob 	isp_pci_mbxdma,
106d59bd469SMatt Jacob 	isp_pci_dmasetup,
107d59bd469SMatt Jacob 	isp_pci_dmateardown,
108d59bd469SMatt Jacob 	NULL,
109d59bd469SMatt Jacob 	isp_pci_reset1,
110d59bd469SMatt Jacob 	isp_pci_dumpregs,
111fed92c47SMatt Jacob 	ISP_1080_RISC_CODE,
112fed92c47SMatt Jacob 	0,
113fed92c47SMatt Jacob 	ISP_CODE_ORG,
114a95ae193SMatt Jacob 	0,
115d59bd469SMatt Jacob 	BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64,
116d59bd469SMatt Jacob 	0
117d59bd469SMatt Jacob };
118d59bd469SMatt Jacob #endif
119d59bd469SMatt Jacob 
120d59bd469SMatt Jacob #ifndef ISP_DISABLE_2100_SUPPORT
12165adb54cSMatt Jacob static struct ispmdvec mdvec_2100 = {
12265adb54cSMatt Jacob 	isp_pci_rd_reg,
12365adb54cSMatt Jacob 	isp_pci_wr_reg,
12465adb54cSMatt Jacob 	isp_pci_mbxdma,
12565adb54cSMatt Jacob 	isp_pci_dmasetup,
126d720e6d5SJustin T. Gibbs 	isp_pci_dmateardown,
12765adb54cSMatt Jacob 	NULL,
12865adb54cSMatt Jacob 	isp_pci_reset1,
12965adb54cSMatt Jacob 	isp_pci_dumpregs,
130fed92c47SMatt Jacob 	ISP_2100_RISC_CODE,
131fed92c47SMatt Jacob 	0,
132fed92c47SMatt Jacob 	ISP_CODE_ORG,
133a95ae193SMatt Jacob 	0,
134a95ae193SMatt Jacob 	0,
135d720e6d5SJustin T. Gibbs 	0
13665adb54cSMatt Jacob };
1375542fe4bSMatt Jacob #endif
138222bb542SMatt Jacob 
13986cb5d6bSMatt Jacob #ifndef	ISP_DISABLE_2200_SUPPORT
140222bb542SMatt Jacob static struct ispmdvec mdvec_2200 = {
141222bb542SMatt Jacob 	isp_pci_rd_reg,
142222bb542SMatt Jacob 	isp_pci_wr_reg,
143222bb542SMatt Jacob 	isp_pci_mbxdma,
144222bb542SMatt Jacob 	isp_pci_dmasetup,
145222bb542SMatt Jacob 	isp_pci_dmateardown,
146222bb542SMatt Jacob 	NULL,
147222bb542SMatt Jacob 	isp_pci_reset1,
148222bb542SMatt Jacob 	isp_pci_dumpregs,
149fed92c47SMatt Jacob 	ISP_2200_RISC_CODE,
150fed92c47SMatt Jacob 	0,
151fed92c47SMatt Jacob 	ISP_CODE_ORG,
152a95ae193SMatt Jacob 	0,
153222bb542SMatt Jacob 	0,
154222bb542SMatt Jacob 	0
155222bb542SMatt Jacob };
156d59bd469SMatt Jacob #endif
15765adb54cSMatt Jacob 
158d951bbcaSMatt Jacob #ifndef	SCSI_ISP_PREFER_MEM_MAP
159d951bbcaSMatt Jacob #define	SCSI_ISP_PREFER_MEM_MAP	0
160d951bbcaSMatt Jacob #endif
161d951bbcaSMatt Jacob 
16265adb54cSMatt Jacob #ifndef	PCIM_CMD_INVEN
16365adb54cSMatt Jacob #define	PCIM_CMD_INVEN			0x10
16465adb54cSMatt Jacob #endif
16565adb54cSMatt Jacob #ifndef	PCIM_CMD_BUSMASTEREN
16665adb54cSMatt Jacob #define	PCIM_CMD_BUSMASTEREN		0x0004
16765adb54cSMatt Jacob #endif
168d951bbcaSMatt Jacob #ifndef	PCIM_CMD_PERRESPEN
169d951bbcaSMatt Jacob #define	PCIM_CMD_PERRESPEN		0x0040
170d951bbcaSMatt Jacob #endif
171d951bbcaSMatt Jacob #ifndef	PCIM_CMD_SEREN
172d951bbcaSMatt Jacob #define	PCIM_CMD_SEREN			0x0100
173d951bbcaSMatt Jacob #endif
174d951bbcaSMatt Jacob 
175d951bbcaSMatt Jacob #ifndef	PCIR_COMMAND
176d951bbcaSMatt Jacob #define	PCIR_COMMAND			0x04
177d951bbcaSMatt Jacob #endif
178d951bbcaSMatt Jacob 
179d951bbcaSMatt Jacob #ifndef	PCIR_CACHELNSZ
180d951bbcaSMatt Jacob #define	PCIR_CACHELNSZ			0x0c
181d951bbcaSMatt Jacob #endif
182d951bbcaSMatt Jacob 
183d951bbcaSMatt Jacob #ifndef	PCIR_LATTIMER
184d951bbcaSMatt Jacob #define	PCIR_LATTIMER			0x0d
185d951bbcaSMatt Jacob #endif
186d951bbcaSMatt Jacob 
187ab6d0040SMatt Jacob #ifndef	PCIR_ROMADDR
188ab6d0040SMatt Jacob #define	PCIR_ROMADDR			0x30
189ab6d0040SMatt Jacob #endif
190ab6d0040SMatt Jacob 
19165adb54cSMatt Jacob #ifndef	PCI_VENDOR_QLOGIC
19265adb54cSMatt Jacob #define	PCI_VENDOR_QLOGIC	0x1077
19365adb54cSMatt Jacob #endif
19465adb54cSMatt Jacob 
19565adb54cSMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1020
19665adb54cSMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1020	0x1020
19765adb54cSMatt Jacob #endif
19865adb54cSMatt Jacob 
199d59bd469SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1080
200d59bd469SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1080	0x1080
201d59bd469SMatt Jacob #endif
202d59bd469SMatt Jacob 
203d59bd469SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1240
204d59bd469SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1240	0x1240
205d59bd469SMatt Jacob #endif
20665adb54cSMatt Jacob 
20765adb54cSMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP2100
20865adb54cSMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2100	0x2100
20965adb54cSMatt Jacob #endif
21065adb54cSMatt Jacob 
211222bb542SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP2200
212222bb542SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2200	0x2200
213222bb542SMatt Jacob #endif
214222bb542SMatt Jacob 
215d59bd469SMatt Jacob #define	PCI_QLOGIC_ISP	((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC)
216d59bd469SMatt Jacob 
217d59bd469SMatt Jacob #define	PCI_QLOGIC_ISP1080	\
218d59bd469SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC)
219d59bd469SMatt Jacob 
220d59bd469SMatt Jacob #define	PCI_QLOGIC_ISP1240	\
221d59bd469SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC)
222d59bd469SMatt Jacob 
22365adb54cSMatt Jacob #define	PCI_QLOGIC_ISP2100	\
22465adb54cSMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC)
22565adb54cSMatt Jacob 
226222bb542SMatt Jacob #define	PCI_QLOGIC_ISP2200	\
227222bb542SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2200 << 16) | PCI_VENDOR_QLOGIC)
228222bb542SMatt Jacob 
22965adb54cSMatt Jacob #define	IO_MAP_REG	0x10
23065adb54cSMatt Jacob #define	MEM_MAP_REG	0x14
23165adb54cSMatt Jacob 
232d951bbcaSMatt Jacob #define	PCI_DFLT_LTNCY	0x40
233d951bbcaSMatt Jacob #define	PCI_DFLT_LNSZ	0x10
23465adb54cSMatt Jacob 
235222bb542SMatt Jacob static const char *isp_pci_probe __P((pcici_t tag, pcidi_t type));
23665adb54cSMatt Jacob static void isp_pci_attach __P((pcici_t config_d, int unit));
23765adb54cSMatt Jacob 
238d720e6d5SJustin T. Gibbs /* This distinguishing define is not right, but it does work */
239a185f9b1SMatt Jacob #ifdef __alpha__
240a185f9b1SMatt Jacob #define IO_SPACE_MAPPING	ALPHA_BUS_SPACE_IO
241a185f9b1SMatt Jacob #define MEM_SPACE_MAPPING	ALPHA_BUS_SPACE_MEM
242a185f9b1SMatt Jacob #else
243a185f9b1SMatt Jacob #define IO_SPACE_MAPPING	I386_BUS_SPACE_IO
244a185f9b1SMatt Jacob #define MEM_SPACE_MAPPING	I386_BUS_SPACE_MEM
245a185f9b1SMatt Jacob #endif
24665adb54cSMatt Jacob 
24765adb54cSMatt Jacob struct isp_pcisoftc {
24865adb54cSMatt Jacob 	struct ispsoftc			pci_isp;
24965adb54cSMatt Jacob         pcici_t				pci_id;
25065adb54cSMatt Jacob 	bus_space_tag_t			pci_st;
25165adb54cSMatt Jacob 	bus_space_handle_t		pci_sh;
252d59bd469SMatt Jacob 	int16_t				pci_poff[_NREG_BLKS];
253d720e6d5SJustin T. Gibbs 	bus_dma_tag_t			parent_dmat;
254d720e6d5SJustin T. Gibbs 	bus_dma_tag_t			cntrol_dmat;
255d720e6d5SJustin T. Gibbs 	bus_dmamap_t			cntrol_dmap;
256a95ae193SMatt Jacob 	bus_dmamap_t			*dmaps;
25765adb54cSMatt Jacob };
25865adb54cSMatt Jacob 
259d720e6d5SJustin T. Gibbs static u_long ispunit;
26065adb54cSMatt Jacob 
26166235db5SEivind Eklund static struct pci_device isp_pci_driver = {
26265adb54cSMatt Jacob 	"isp",
26365adb54cSMatt Jacob 	isp_pci_probe,
26465adb54cSMatt Jacob 	isp_pci_attach,
265d720e6d5SJustin T. Gibbs 	&ispunit,
26665adb54cSMatt Jacob 	NULL
26765adb54cSMatt Jacob };
26896b3554eSPeter Wemm COMPAT_PCI_DRIVER (isp_pci, isp_pci_driver);
26965adb54cSMatt Jacob 
27065adb54cSMatt Jacob 
271222bb542SMatt Jacob static const char *
27217e318c6SMatt Jacob isp_pci_probe(pcici_t tag, pcidi_t type)
27365adb54cSMatt Jacob {
27465adb54cSMatt Jacob 	static int oneshot = 1;
27565adb54cSMatt Jacob 	char *x;
27665adb54cSMatt Jacob 
27765adb54cSMatt Jacob         switch (type) {
278d59bd469SMatt Jacob #ifndef	ISP_DISABLE_1020_SUPPORT
27965adb54cSMatt Jacob 	case PCI_QLOGIC_ISP:
280d59bd469SMatt Jacob 		x = "Qlogic ISP 1020/1040 PCI SCSI Adapter";
28165adb54cSMatt Jacob 		break;
282d59bd469SMatt Jacob #endif
283d59bd469SMatt Jacob #ifndef	ISP_DISABLE_1080_SUPPORT
284d59bd469SMatt Jacob 	case PCI_QLOGIC_ISP1080:
285c6608df3SMatt Jacob 		x = "Qlogic ISP 1080 PCI SCSI Adapter";
286c6608df3SMatt Jacob 		break;
287c6608df3SMatt Jacob 	case PCI_QLOGIC_ISP1240:
288c6608df3SMatt Jacob 		x = "Qlogic ISP 1240 PCI SCSI Adapter";
289d59bd469SMatt Jacob 		break;
290d59bd469SMatt Jacob #endif
291d59bd469SMatt Jacob #ifndef	ISP_DISABLE_2100_SUPPORT
29265adb54cSMatt Jacob 	case PCI_QLOGIC_ISP2100:
29365adb54cSMatt Jacob 		x = "Qlogic ISP 2100 PCI FC-AL Adapter";
29465adb54cSMatt Jacob 		break;
295d59bd469SMatt Jacob #endif
2965542fe4bSMatt Jacob #ifndef	ISP_DISABLE_2200_SUPPORT
2975542fe4bSMatt Jacob 	case PCI_QLOGIC_ISP2200:
2985542fe4bSMatt Jacob 		x = "Qlogic ISP 2200 PCI FC-AL Adapter";
2995542fe4bSMatt Jacob 		break;
3005542fe4bSMatt Jacob #endif
30165adb54cSMatt Jacob 	default:
30265adb54cSMatt Jacob 		return (NULL);
30365adb54cSMatt Jacob 	}
30465adb54cSMatt Jacob 	if (oneshot) {
30565adb54cSMatt Jacob 		oneshot = 0;
306a95ae193SMatt Jacob 		CFGPRINTF("Qlogic ISP Driver, FreeBSD Version %d.%d, "
307a95ae193SMatt Jacob 		    "Core Version %d.%d\n",
308d720e6d5SJustin T. Gibbs 		    ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR,
309d720e6d5SJustin T. Gibbs 		    ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR);
31065adb54cSMatt Jacob 	}
31165adb54cSMatt Jacob 	return (x);
31265adb54cSMatt Jacob }
31365adb54cSMatt Jacob 
31465adb54cSMatt Jacob static void
315222bb542SMatt Jacob isp_pci_attach(pcici_t cfid, int unit)
31665adb54cSMatt Jacob {
317222bb542SMatt Jacob 	int mapped, prefer_mem_map, bitmap;
318a185f9b1SMatt Jacob 	pci_port_t io_port;
319c6608df3SMatt Jacob 	u_int32_t data, linesz, psize, basetype;
32065adb54cSMatt Jacob 	struct isp_pcisoftc *pcs;
32165adb54cSMatt Jacob 	struct ispsoftc *isp;
32265adb54cSMatt Jacob 	vm_offset_t vaddr, paddr;
323c6608df3SMatt Jacob 	struct ispmdvec *mdvp;
324222bb542SMatt Jacob 	bus_size_t lim;
32565adb54cSMatt Jacob 	ISP_LOCKVAL_DECL;
32665adb54cSMatt Jacob 
32765adb54cSMatt Jacob 	pcs = malloc(sizeof (struct isp_pcisoftc), M_DEVBUF, M_NOWAIT);
32865adb54cSMatt Jacob 	if (pcs == NULL) {
3299bffbcd4SBruce Evans 		printf("isp%d: cannot allocate softc\n", unit);
33065adb54cSMatt Jacob 		return;
33165adb54cSMatt Jacob 	}
33265adb54cSMatt Jacob 	bzero(pcs, sizeof (struct isp_pcisoftc));
33365adb54cSMatt Jacob 
334222bb542SMatt Jacob 	/*
3359ba86737SMatt Jacob 	 * Figure out if we're supposed to skip this one.
3369ba86737SMatt Jacob 	 */
3379ba86737SMatt Jacob 	if (getenv_int("isp_disable", &bitmap)) {
3389ba86737SMatt Jacob 		if (bitmap & (1 << unit)) {
3399ba86737SMatt Jacob 			printf("isp%d: not configuring\n", unit);
3409ba86737SMatt Jacob 			return;
3419ba86737SMatt Jacob 		}
3429ba86737SMatt Jacob 	}
3439ba86737SMatt Jacob 
3449ba86737SMatt Jacob 	/*
345222bb542SMatt Jacob 	 * Figure out which we should try first - memory mapping or i/o mapping?
346222bb542SMatt Jacob 	 */
347222bb542SMatt Jacob #if	SCSI_ISP_PREFER_MEM_MAP == 1
348222bb542SMatt Jacob 	prefer_mem_map = 1;
349222bb542SMatt Jacob #else
350222bb542SMatt Jacob 	prefer_mem_map = 0;
351222bb542SMatt Jacob #endif
352222bb542SMatt Jacob 	bitmap = 0;
353222bb542SMatt Jacob 	if (getenv_int("isp_mem_map", &bitmap)) {
354222bb542SMatt Jacob 		if (bitmap & (1 << unit))
355222bb542SMatt Jacob 			prefer_mem_map = 1;
356222bb542SMatt Jacob 	}
357222bb542SMatt Jacob 	bitmap = 0;
358222bb542SMatt Jacob 	if (getenv_int("isp_io_map", &bitmap)) {
359222bb542SMatt Jacob 		if (bitmap & (1 << unit))
360222bb542SMatt Jacob 			prefer_mem_map = 0;
361222bb542SMatt Jacob 	}
362222bb542SMatt Jacob 
36365adb54cSMatt Jacob 	vaddr = paddr = NULL;
36465adb54cSMatt Jacob 	mapped = 0;
365ab6d0040SMatt Jacob 	linesz = PCI_DFLT_LNSZ;
366d951bbcaSMatt Jacob 	/*
367d951bbcaSMatt Jacob 	 * Note that pci_conf_read is a 32 bit word aligned function.
368d951bbcaSMatt Jacob 	 */
369222bb542SMatt Jacob 	data = pci_conf_read(cfid, PCIR_COMMAND);
370222bb542SMatt Jacob 	if (prefer_mem_map) {
371222bb542SMatt Jacob 		if (data & PCI_COMMAND_MEM_ENABLE) {
372222bb542SMatt Jacob 			if (pci_map_mem(cfid, MEM_MAP_REG, &vaddr, &paddr)) {
373a185f9b1SMatt Jacob 				pcs->pci_st = MEM_SPACE_MAPPING;
374a185f9b1SMatt Jacob 				pcs->pci_sh = vaddr;
37565adb54cSMatt Jacob 				mapped++;
37665adb54cSMatt Jacob 			}
37765adb54cSMatt Jacob 		}
378a185f9b1SMatt Jacob 		if (mapped == 0 && (data & PCI_COMMAND_IO_ENABLE)) {
379222bb542SMatt Jacob 			if (pci_map_port(cfid, PCI_MAP_REG_START, &io_port)) {
380a185f9b1SMatt Jacob 				pcs->pci_st = IO_SPACE_MAPPING;
381a185f9b1SMatt Jacob 				pcs->pci_sh = io_port;
38265adb54cSMatt Jacob 				mapped++;
38365adb54cSMatt Jacob 			}
38465adb54cSMatt Jacob 		}
385222bb542SMatt Jacob 	} else {
386222bb542SMatt Jacob 		if (data & PCI_COMMAND_IO_ENABLE) {
387222bb542SMatt Jacob 			if (pci_map_port(cfid, PCI_MAP_REG_START, &io_port)) {
388d951bbcaSMatt Jacob 				pcs->pci_st = IO_SPACE_MAPPING;
389d951bbcaSMatt Jacob 				pcs->pci_sh = io_port;
390d951bbcaSMatt Jacob 				mapped++;
391d951bbcaSMatt Jacob 			}
392d951bbcaSMatt Jacob 		}
393d951bbcaSMatt Jacob 		if (mapped == 0 && (data & PCI_COMMAND_MEM_ENABLE)) {
394222bb542SMatt Jacob 			if (pci_map_mem(cfid, MEM_MAP_REG, &vaddr, &paddr)) {
395d951bbcaSMatt Jacob 				pcs->pci_st = MEM_SPACE_MAPPING;
396d951bbcaSMatt Jacob 				pcs->pci_sh = vaddr;
397d951bbcaSMatt Jacob 				mapped++;
398d951bbcaSMatt Jacob 			}
399d951bbcaSMatt Jacob 		}
400222bb542SMatt Jacob 	}
40165adb54cSMatt Jacob 	if (mapped == 0) {
4029bffbcd4SBruce Evans 		printf("isp%d: unable to map any ports!\n", unit);
40365adb54cSMatt Jacob 		free(pcs, M_DEVBUF);
40465adb54cSMatt Jacob 		return;
40565adb54cSMatt Jacob 	}
406222bb542SMatt Jacob 	if (bootverbose)
40765adb54cSMatt Jacob 		printf("isp%d: using %s space register mapping\n", unit,
408a185f9b1SMatt Jacob 		    pcs->pci_st == IO_SPACE_MAPPING? "I/O" : "Memory");
40965adb54cSMatt Jacob 
410222bb542SMatt Jacob 	data = pci_conf_read(cfid, PCI_ID_REG);
411d59bd469SMatt Jacob 	pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF;
412d59bd469SMatt Jacob 	pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF;
413d59bd469SMatt Jacob 	pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF;
414d59bd469SMatt Jacob 	pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF;
415d59bd469SMatt Jacob 	pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF;
416c6608df3SMatt Jacob 	/*
417c6608df3SMatt Jacob  	 * GCC!
418c6608df3SMatt Jacob 	 */
419c6608df3SMatt Jacob 	mdvp = &mdvec;
420c6608df3SMatt Jacob 	basetype = ISP_HA_SCSI_UNKNOWN;
421c6608df3SMatt Jacob 	psize = sizeof (sdparam);
422222bb542SMatt Jacob 	lim = BUS_SPACE_MAXSIZE_32BIT;
423d59bd469SMatt Jacob #ifndef	ISP_DISABLE_1020_SUPPORT
42465adb54cSMatt Jacob 	if (data == PCI_QLOGIC_ISP) {
425c6608df3SMatt Jacob 		mdvp = &mdvec;
426c6608df3SMatt Jacob 		basetype = ISP_HA_SCSI_UNKNOWN;
427c6608df3SMatt Jacob 		psize = sizeof (sdparam);
428222bb542SMatt Jacob 		lim = BUS_SPACE_MAXSIZE_24BIT;
429d59bd469SMatt Jacob 	}
430d59bd469SMatt Jacob #endif
431d59bd469SMatt Jacob #ifndef	ISP_DISABLE_1080_SUPPORT
432c6608df3SMatt Jacob 	if (data == PCI_QLOGIC_ISP1080) {
433c6608df3SMatt Jacob 		mdvp = &mdvec_1080;
434c6608df3SMatt Jacob 		basetype = ISP_HA_SCSI_1080;
435c6608df3SMatt Jacob 		psize = sizeof (sdparam);
436c6608df3SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
437c6608df3SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
438c6608df3SMatt Jacob 	}
439c6608df3SMatt Jacob 	if (data == PCI_QLOGIC_ISP1240) {
440c6608df3SMatt Jacob 		mdvp = &mdvec_1080;
441c6608df3SMatt Jacob 		basetype = ISP_HA_SCSI_12X0;
442c6608df3SMatt Jacob 		psize = 2 * sizeof (sdparam);
443d59bd469SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
444d59bd469SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
445d59bd469SMatt Jacob 	}
446d59bd469SMatt Jacob #endif
447d59bd469SMatt Jacob #ifndef	ISP_DISABLE_2100_SUPPORT
448d59bd469SMatt Jacob 	if (data == PCI_QLOGIC_ISP2100) {
449c6608df3SMatt Jacob 		mdvp = &mdvec_2100;
450c6608df3SMatt Jacob 		basetype = ISP_HA_FC_2100;
451c6608df3SMatt Jacob 		psize = sizeof (fcparam);
452d59bd469SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
453d59bd469SMatt Jacob 		    PCI_MBOX_REGS2100_OFF;
454222bb542SMatt Jacob 		data = pci_conf_read(cfid, PCI_CLASS_REG);
455ab6d0040SMatt Jacob 		if ((data & 0xff) < 3) {
456ab6d0040SMatt Jacob 			/*
457ab6d0040SMatt Jacob 			 * XXX: Need to get the actual revision
458ab6d0040SMatt Jacob 			 * XXX: number of the 2100 FB. At any rate,
459ab6d0040SMatt Jacob 			 * XXX: lower cache line size for early revision
460ab6d0040SMatt Jacob 			 * XXX; boards.
461ab6d0040SMatt Jacob 			 */
462ab6d0040SMatt Jacob 			linesz = 1;
463ab6d0040SMatt Jacob 		}
46465adb54cSMatt Jacob 	}
4655542fe4bSMatt Jacob #endif
4665542fe4bSMatt Jacob #ifndef	ISP_DISABLE_2200_SUPPORT
467222bb542SMatt Jacob 	if (data == PCI_QLOGIC_ISP2200) {
468222bb542SMatt Jacob 		mdvp = &mdvec_2200;
469222bb542SMatt Jacob 		basetype = ISP_HA_FC_2200;
470222bb542SMatt Jacob 		psize = sizeof (fcparam);
471222bb542SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
472222bb542SMatt Jacob 		    PCI_MBOX_REGS2100_OFF;
473222bb542SMatt Jacob 	}
474d59bd469SMatt Jacob #endif
475c6608df3SMatt Jacob 	isp = &pcs->pci_isp;
476c6608df3SMatt Jacob 	isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT);
477c6608df3SMatt Jacob 	if (isp->isp_param == NULL) {
478c6608df3SMatt Jacob 		printf("isp%d: cannot allocate parameter data\n", unit);
479c6608df3SMatt Jacob 		return;
480c6608df3SMatt Jacob 	}
481c6608df3SMatt Jacob 	bzero(isp->isp_param, psize);
482c6608df3SMatt Jacob 	isp->isp_mdvec = mdvp;
483c6608df3SMatt Jacob 	isp->isp_type = basetype;
484c6608df3SMatt Jacob 	(void) snprintf(isp->isp_name, sizeof (isp->isp_name), "isp%d", unit);
485c6608df3SMatt Jacob 	isp->isp_osinfo.unit = unit;
48665adb54cSMatt Jacob 
487d951bbcaSMatt Jacob 	ISP_LOCK(isp);
488ab6d0040SMatt Jacob 
489d951bbcaSMatt Jacob 	/*
490d951bbcaSMatt Jacob 	 * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER
491d951bbcaSMatt Jacob 	 * are set.
492d951bbcaSMatt Jacob 	 */
493222bb542SMatt Jacob 	data = pci_cfgread(cfid, PCIR_COMMAND, 2);
494d951bbcaSMatt Jacob 	data |=	PCIM_CMD_SEREN		|
495d951bbcaSMatt Jacob 		PCIM_CMD_PERRESPEN	|
496d951bbcaSMatt Jacob 		PCIM_CMD_BUSMASTEREN	|
497d951bbcaSMatt Jacob 		PCIM_CMD_INVEN;
498222bb542SMatt Jacob 	pci_cfgwrite(cfid, PCIR_COMMAND, 2, data);
499ab6d0040SMatt Jacob 
500d951bbcaSMatt Jacob 	/*
501222bb542SMatt Jacob 	 * Make sure the Cache Line Size register is set sensibly.
502d951bbcaSMatt Jacob 	 */
503222bb542SMatt Jacob 	data = pci_cfgread(cfid, PCIR_CACHELNSZ, 1);
504ab6d0040SMatt Jacob 	if (data != linesz) {
505d951bbcaSMatt Jacob 		data = PCI_DFLT_LNSZ;
506a95ae193SMatt Jacob 		CFGPRINTF("%s: set PCI line size to %d\n", isp->isp_name, data);
507222bb542SMatt Jacob 		pci_cfgwrite(cfid, PCIR_CACHELNSZ, data, 1);
508d951bbcaSMatt Jacob 	}
509ab6d0040SMatt Jacob 
510d951bbcaSMatt Jacob 	/*
511d951bbcaSMatt Jacob 	 * Make sure the Latency Timer is sane.
512d951bbcaSMatt Jacob 	 */
513222bb542SMatt Jacob 	data = pci_cfgread(cfid, PCIR_LATTIMER, 1);
514d951bbcaSMatt Jacob 	if (data < PCI_DFLT_LTNCY) {
515d951bbcaSMatt Jacob 		data = PCI_DFLT_LTNCY;
516a95ae193SMatt Jacob 		CFGPRINTF("%s: set PCI latency to %d\n", isp->isp_name, data);
517222bb542SMatt Jacob 		pci_cfgwrite(cfid, PCIR_LATTIMER, data, 1);
518d951bbcaSMatt Jacob 	}
519ab6d0040SMatt Jacob 
520ab6d0040SMatt Jacob 	/*
521ab6d0040SMatt Jacob 	 * Make sure we've disabled the ROM.
522ab6d0040SMatt Jacob 	 */
523222bb542SMatt Jacob 	data = pci_cfgread(cfid, PCIR_ROMADDR, 4);
524ab6d0040SMatt Jacob 	data &= ~1;
525222bb542SMatt Jacob 	pci_cfgwrite(cfid, PCIR_ROMADDR, data, 4);
526d951bbcaSMatt Jacob 	ISP_UNLOCK(isp);
527d951bbcaSMatt Jacob 
528086646f7SJustin T. Gibbs 	if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
529222bb542SMatt Jacob 	    BUS_SPACE_MAXADDR, NULL, NULL, lim + 1,
530222bb542SMatt Jacob 	    255, lim, 0, &pcs->parent_dmat) != 0) {
531d720e6d5SJustin T. Gibbs 		printf("%s: could not create master dma tag\n", isp->isp_name);
532d720e6d5SJustin T. Gibbs 		free(pcs, M_DEVBUF);
533d720e6d5SJustin T. Gibbs 		return;
534d720e6d5SJustin T. Gibbs 	}
535222bb542SMatt Jacob 	if (pci_map_int(cfid, (void (*)(void *))isp_intr,
53665adb54cSMatt Jacob 	    (void *)isp, &IMASK) == 0) {
5379bffbcd4SBruce Evans 		printf("%s: could not map interrupt\n", isp->isp_name);
53865adb54cSMatt Jacob 		free(pcs, M_DEVBUF);
53965adb54cSMatt Jacob 		return;
54065adb54cSMatt Jacob 	}
54165adb54cSMatt Jacob 
542222bb542SMatt Jacob 	pcs->pci_id = cfid;
543d951bbcaSMatt Jacob #ifdef	SCSI_ISP_NO_FWLOAD_MASK
544d951bbcaSMatt Jacob 	if (SCSI_ISP_NO_FWLOAD_MASK && (SCSI_ISP_NO_FWLOAD_MASK & (1 << unit)))
545d951bbcaSMatt Jacob 		isp->isp_confopts |= ISP_CFG_NORELOAD;
546d951bbcaSMatt Jacob #endif
547222bb542SMatt Jacob 	if (getenv_int("isp_no_fwload", &bitmap)) {
548222bb542SMatt Jacob 		if (bitmap & (1 << unit))
549222bb542SMatt Jacob 			isp->isp_confopts |= ISP_CFG_NORELOAD;
550222bb542SMatt Jacob 	}
551222bb542SMatt Jacob 	if (getenv_int("isp_fwload", &bitmap)) {
552222bb542SMatt Jacob 		if (bitmap & (1 << unit))
553222bb542SMatt Jacob 			isp->isp_confopts &= ~ISP_CFG_NORELOAD;
554222bb542SMatt Jacob 	}
555222bb542SMatt Jacob 
556d951bbcaSMatt Jacob #ifdef	SCSI_ISP_NO_NVRAM_MASK
557ab6d0040SMatt Jacob 	if (SCSI_ISP_NO_NVRAM_MASK && (SCSI_ISP_NO_NVRAM_MASK & (1 << unit))) {
558ab6d0040SMatt Jacob 		printf("%s: ignoring NVRAM\n", isp->isp_name);
559d951bbcaSMatt Jacob 		isp->isp_confopts |= ISP_CFG_NONVRAM;
560ab6d0040SMatt Jacob 	}
561d951bbcaSMatt Jacob #endif
562222bb542SMatt Jacob 	if (getenv_int("isp_no_nvram", &bitmap)) {
563222bb542SMatt Jacob 		if (bitmap & (1 << unit))
564222bb542SMatt Jacob 			isp->isp_confopts |= ISP_CFG_NONVRAM;
565222bb542SMatt Jacob 	}
566222bb542SMatt Jacob 	if (getenv_int("isp_nvram", &bitmap)) {
567222bb542SMatt Jacob 		if (bitmap & (1 << unit))
568222bb542SMatt Jacob 			isp->isp_confopts &= ~ISP_CFG_NONVRAM;
569222bb542SMatt Jacob 	}
570222bb542SMatt Jacob 
571222bb542SMatt Jacob #ifdef	SCSI_ISP_FCDUPLEX
572222bb542SMatt Jacob 	if (IS_FC(isp)) {
573222bb542SMatt Jacob 		if (SCSI_ISP_FCDUPLEX && (SCSI_ISP_FCDUPLEX & (1 << unit))) {
574222bb542SMatt Jacob 			isp->isp_confopts |= ISP_CFG_FULL_DUPLEX;
575222bb542SMatt Jacob 		}
576222bb542SMatt Jacob 	}
577222bb542SMatt Jacob #endif
578222bb542SMatt Jacob 	if (getenv_int("isp_fcduplex", &bitmap)) {
579222bb542SMatt Jacob 		if (bitmap & (1 << unit))
580222bb542SMatt Jacob 			isp->isp_confopts |= ISP_CFG_FULL_DUPLEX;
581222bb542SMatt Jacob 	}
582222bb542SMatt Jacob 	if (getenv_int("isp_no_fcduplex", &bitmap)) {
583222bb542SMatt Jacob 		if (bitmap & (1 << unit))
584222bb542SMatt Jacob 			isp->isp_confopts &= ~ISP_CFG_FULL_DUPLEX;
585222bb542SMatt Jacob 	}
586222bb542SMatt Jacob 
587222bb542SMatt Jacob 	if (getenv_int("isp_seed", &isp->isp_osinfo.seed)) {
588222bb542SMatt Jacob 		isp->isp_osinfo.seed <<= 8;
589222bb542SMatt Jacob 		isp->isp_osinfo.seed += (unit + 1);
590222bb542SMatt Jacob 	} else {
591222bb542SMatt Jacob 		/*
592222bb542SMatt Jacob 		 * poor man's attempt at pseudo randomness.
593222bb542SMatt Jacob 		 */
594d009ccfaSBruce Evans 		long i = (intptr_t) isp;
595222bb542SMatt Jacob 
596222bb542SMatt Jacob 		i >>= 5;
597222bb542SMatt Jacob 		i &= 0x7;
598222bb542SMatt Jacob 
599222bb542SMatt Jacob 		/*
600222bb542SMatt Jacob 		 * This isn't very random, but it's the best we can do for
601222bb542SMatt Jacob 		 * the real edge case of cards that don't have WWNs.
602222bb542SMatt Jacob 		 */
603222bb542SMatt Jacob 		isp->isp_osinfo.seed += ((int) cfid->bus) << 16;
604222bb542SMatt Jacob 		isp->isp_osinfo.seed += ((int) cfid->slot) << 8;
605222bb542SMatt Jacob 		isp->isp_osinfo.seed += ((int) cfid->func);
606222bb542SMatt Jacob 		while (version[i])
607222bb542SMatt Jacob 			isp->isp_osinfo.seed += (int) version[i++];
608222bb542SMatt Jacob 		isp->isp_osinfo.seed <<= 8;
609222bb542SMatt Jacob 		isp->isp_osinfo.seed += (unit + 1);
610222bb542SMatt Jacob 	}
611a95ae193SMatt Jacob 	(void) getenv_int("isp_debug", &isp_debug);
612d720e6d5SJustin T. Gibbs 	ISP_LOCK(isp);
61365adb54cSMatt Jacob 	isp_reset(isp);
61465adb54cSMatt Jacob 	if (isp->isp_state != ISP_RESETSTATE) {
615222bb542SMatt Jacob 		(void) pci_unmap_int(cfid);
616d720e6d5SJustin T. Gibbs 		ISP_UNLOCK(isp);
61765adb54cSMatt Jacob 		free(pcs, M_DEVBUF);
61865adb54cSMatt Jacob 		return;
61965adb54cSMatt Jacob 	}
62065adb54cSMatt Jacob 	isp_init(isp);
62165adb54cSMatt Jacob 	if (isp->isp_state != ISP_INITSTATE) {
622d59bd469SMatt Jacob 		/* If we're a Fibre Channel Card, we allow deferred attach */
623222bb542SMatt Jacob 		if (IS_SCSI(isp)) {
62465adb54cSMatt Jacob 			isp_uninit(isp);
625222bb542SMatt Jacob 			(void) pci_unmap_int(cfid); /* Does nothing */
626c6608df3SMatt Jacob 			ISP_UNLOCK(isp);
62765adb54cSMatt Jacob 			free(pcs, M_DEVBUF);
628c6608df3SMatt Jacob 			return;
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);
636222bb542SMatt Jacob 			(void) pci_unmap_int(cfid); /* Does nothing */
637c6608df3SMatt Jacob 			ISP_UNLOCK(isp);
63865adb54cSMatt Jacob 			free(pcs, M_DEVBUF);
639c6608df3SMatt Jacob 			return;
64065adb54cSMatt Jacob 		}
641d59bd469SMatt Jacob 	}
642d720e6d5SJustin T. Gibbs 	ISP_UNLOCK(isp);
643e37c0455SDoug Rabson #ifdef __alpha__
644d951bbcaSMatt Jacob 	/*
645d951bbcaSMatt Jacob 	 * THIS SHOULD NOT HAVE TO BE HERE
646d951bbcaSMatt Jacob 	 */
647222bb542SMatt Jacob 	alpha_register_pci_scsi(cfid->bus, cfid->slot, isp->isp_sim);
648e37c0455SDoug Rabson #endif
64965adb54cSMatt Jacob }
65065adb54cSMatt Jacob 
65165adb54cSMatt Jacob static u_int16_t
652d59bd469SMatt Jacob isp_pci_rd_reg(isp, regoff)
653d59bd469SMatt Jacob 	struct ispsoftc *isp;
654d59bd469SMatt Jacob 	int regoff;
65565adb54cSMatt Jacob {
65665adb54cSMatt Jacob 	u_int16_t rv;
65765adb54cSMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
658d59bd469SMatt Jacob 	int offset, oldconf = 0;
65965adb54cSMatt Jacob 
660d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
66165adb54cSMatt Jacob 		/*
66265adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
66365adb54cSMatt Jacob 		 */
664d59bd469SMatt Jacob 		oldconf = isp_pci_rd_reg(isp, BIU_CONF1);
665d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP);
66665adb54cSMatt Jacob 	}
667d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
668d59bd469SMatt Jacob 	offset += (regoff & 0xff);
66965adb54cSMatt Jacob 	rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset);
670d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
671d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf);
67265adb54cSMatt Jacob 	}
67365adb54cSMatt Jacob 	return (rv);
67465adb54cSMatt Jacob }
67565adb54cSMatt Jacob 
67665adb54cSMatt Jacob static void
677d59bd469SMatt Jacob isp_pci_wr_reg(isp, regoff, val)
678d59bd469SMatt Jacob 	struct ispsoftc *isp;
679d59bd469SMatt Jacob 	int regoff;
680d59bd469SMatt Jacob 	u_int16_t val;
68165adb54cSMatt Jacob {
68265adb54cSMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
683d59bd469SMatt Jacob 	int offset, oldconf = 0;
684d59bd469SMatt Jacob 
685d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
68665adb54cSMatt Jacob 		/*
68765adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
68865adb54cSMatt Jacob 		 */
689d59bd469SMatt Jacob 		oldconf = isp_pci_rd_reg(isp, BIU_CONF1);
690d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP);
69165adb54cSMatt Jacob 	}
692d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
693d59bd469SMatt Jacob 	offset += (regoff & 0xff);
69465adb54cSMatt Jacob 	bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val);
695d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
696d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf);
69765adb54cSMatt Jacob 	}
69865adb54cSMatt Jacob }
69965adb54cSMatt Jacob 
700d59bd469SMatt Jacob #ifndef	ISP_DISABLE_1080_SUPPORT
701d59bd469SMatt Jacob static u_int16_t
702d59bd469SMatt Jacob isp_pci_rd_reg_1080(isp, regoff)
703d59bd469SMatt Jacob 	struct ispsoftc *isp;
704d59bd469SMatt Jacob 	int regoff;
705d59bd469SMatt Jacob {
706d59bd469SMatt Jacob 	u_int16_t rv;
707d59bd469SMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
708d59bd469SMatt Jacob 	int offset, oc = 0;
709d59bd469SMatt Jacob 
710d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
711d59bd469SMatt Jacob 		/*
712d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
713d59bd469SMatt Jacob 		 */
714d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
715d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_SXP);
716d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
717d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
718d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA);
719d59bd469SMatt Jacob 	}
720d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
721d59bd469SMatt Jacob 	offset += (regoff & 0xff);
722d59bd469SMatt Jacob 	rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset);
723d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
724d59bd469SMatt Jacob 	    ((regoff & _BLK_REG_MASK) == DMA_BLOCK)) {
725d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc);
726d59bd469SMatt Jacob 	}
727d59bd469SMatt Jacob 	return (rv);
728d59bd469SMatt Jacob }
729d59bd469SMatt Jacob 
730d59bd469SMatt Jacob static void
731d59bd469SMatt Jacob isp_pci_wr_reg_1080(isp, regoff, val)
732d59bd469SMatt Jacob 	struct ispsoftc *isp;
733d59bd469SMatt Jacob 	int regoff;
734d59bd469SMatt Jacob 	u_int16_t val;
735d59bd469SMatt Jacob {
736d59bd469SMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
737d59bd469SMatt Jacob 	int offset, oc = 0;
738d59bd469SMatt Jacob 
739d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
740d59bd469SMatt Jacob 		/*
741d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
742d59bd469SMatt Jacob 		 */
743d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
744d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_SXP);
745d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
746d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
747d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA);
748d59bd469SMatt Jacob 	}
749d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
750d59bd469SMatt Jacob 	offset += (regoff & 0xff);
751d59bd469SMatt Jacob 	bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val);
752d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
753d59bd469SMatt Jacob 	    ((regoff & _BLK_REG_MASK) == DMA_BLOCK)) {
754d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc);
755d59bd469SMatt Jacob 	}
756d59bd469SMatt Jacob }
757d59bd469SMatt Jacob #endif
758d59bd469SMatt Jacob 
759d59bd469SMatt Jacob 
760d720e6d5SJustin T. Gibbs static void isp_map_rquest __P((void *, bus_dma_segment_t *, int, int));
761d720e6d5SJustin T. Gibbs static void isp_map_result __P((void *, bus_dma_segment_t *, int, int));
762d720e6d5SJustin T. Gibbs static void isp_map_fcscrt __P((void *, bus_dma_segment_t *, int, int));
763d720e6d5SJustin T. Gibbs 
764222bb542SMatt Jacob struct imush {
765222bb542SMatt Jacob 	struct ispsoftc *isp;
766222bb542SMatt Jacob 	int error;
767222bb542SMatt Jacob };
768222bb542SMatt Jacob 
769d720e6d5SJustin T. Gibbs static void
77017e318c6SMatt Jacob isp_map_rquest(void *arg, bus_dma_segment_t *segs, int nseg, int error)
771d720e6d5SJustin T. Gibbs {
772222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
773222bb542SMatt Jacob 	if (error) {
774222bb542SMatt Jacob 		imushp->error = error;
775222bb542SMatt Jacob 	} else {
776222bb542SMatt Jacob 		imushp->isp->isp_rquest_dma = segs->ds_addr;
777222bb542SMatt Jacob 	}
778d720e6d5SJustin T. Gibbs }
779d720e6d5SJustin T. Gibbs 
780d720e6d5SJustin T. Gibbs static void
78117e318c6SMatt Jacob isp_map_result(void *arg, bus_dma_segment_t *segs, int nseg, int error)
782d720e6d5SJustin T. Gibbs {
783222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
784222bb542SMatt Jacob 	if (error) {
785222bb542SMatt Jacob 		imushp->error = error;
786222bb542SMatt Jacob 	} else {
787222bb542SMatt Jacob 		imushp->isp->isp_result_dma = segs->ds_addr;
788222bb542SMatt Jacob 	}
789d720e6d5SJustin T. Gibbs }
790d720e6d5SJustin T. Gibbs 
791d720e6d5SJustin T. Gibbs static void
79217e318c6SMatt Jacob isp_map_fcscrt(void *arg, bus_dma_segment_t *segs, int nseg, int error)
793d720e6d5SJustin T. Gibbs {
794222bb542SMatt Jacob 	struct imush *imushp = (struct imush *) arg;
795222bb542SMatt Jacob 	if (error) {
796222bb542SMatt Jacob 		imushp->error = error;
797222bb542SMatt Jacob 	} else {
798222bb542SMatt Jacob 		fcparam *fcp = imushp->isp->isp_param;
799d720e6d5SJustin T. Gibbs 		fcp->isp_scdma = segs->ds_addr;
800d720e6d5SJustin T. Gibbs 	}
801222bb542SMatt Jacob }
802d720e6d5SJustin T. Gibbs 
803d720e6d5SJustin T. Gibbs static int
80417e318c6SMatt Jacob isp_pci_mbxdma(struct ispsoftc *isp)
805d720e6d5SJustin T. Gibbs {
806d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
807d720e6d5SJustin T. Gibbs 	caddr_t base;
808d720e6d5SJustin T. Gibbs 	u_int32_t len;
809d720e6d5SJustin T. Gibbs 	int i, error;
810222bb542SMatt Jacob 	bus_size_t lim;
811222bb542SMatt Jacob 	struct imush im;
812222bb542SMatt Jacob 
813222bb542SMatt Jacob 
814a95ae193SMatt Jacob 	/*
815a95ae193SMatt Jacob 	 * Already been here? If so, leave...
816a95ae193SMatt Jacob 	 */
817a95ae193SMatt Jacob 	if (isp->isp_rquest) {
818a95ae193SMatt Jacob 		return (0);
819a95ae193SMatt Jacob 	}
820a95ae193SMatt Jacob 
821a95ae193SMatt Jacob 	len = sizeof (ISP_SCSI_XFER_T **) * isp->isp_maxcmds;
822a95ae193SMatt Jacob 	isp->isp_xflist = (ISP_SCSI_XFER_T **) malloc(len, M_DEVBUF, M_WAITOK);
823a95ae193SMatt Jacob 	if (isp->isp_xflist == NULL) {
824a95ae193SMatt Jacob 		printf("%s: can't alloc xflist array\n", isp->isp_name);
825a95ae193SMatt Jacob 		return (1);
826a95ae193SMatt Jacob 	}
827a95ae193SMatt Jacob 	bzero(isp->isp_xflist, len);
828a95ae193SMatt Jacob 	len = sizeof (bus_dmamap_t) * isp->isp_maxcmds;
829a95ae193SMatt Jacob 	pci->dmaps = (bus_dmamap_t *) malloc(len, M_DEVBUF,  M_WAITOK);
830a95ae193SMatt Jacob 	if (pci->dmaps == NULL) {
831a95ae193SMatt Jacob 		printf("%s: can't alloc dma maps\n", isp->isp_name);
832a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
833a95ae193SMatt Jacob 		return (1);
834a95ae193SMatt Jacob 	}
835a95ae193SMatt Jacob 
836222bb542SMatt Jacob 	if (IS_FC(isp) || IS_1080(isp) || IS_12X0(isp))
837222bb542SMatt Jacob 		lim = BUS_SPACE_MAXADDR + 1;
838222bb542SMatt Jacob 	else
839222bb542SMatt Jacob 		lim = BUS_SPACE_MAXADDR_24BIT + 1;
840d720e6d5SJustin T. Gibbs 
841d720e6d5SJustin T. Gibbs 	/*
842d720e6d5SJustin T. Gibbs 	 * Allocate and map the request, result queues, plus FC scratch area.
843d720e6d5SJustin T. Gibbs 	 */
844d720e6d5SJustin T. Gibbs 	len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN);
845d720e6d5SJustin T. Gibbs 	len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN);
846222bb542SMatt Jacob 	if (IS_FC(isp)) {
847d720e6d5SJustin T. Gibbs 		len += ISP2100_SCRLEN;
848d720e6d5SJustin T. Gibbs 	}
849222bb542SMatt Jacob 	if (bus_dma_tag_create(pci->parent_dmat, PAGE_SIZE, lim,
850222bb542SMatt Jacob 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, len, 1,
851222bb542SMatt Jacob 	    BUS_SPACE_MAXSIZE_32BIT, 0, &pci->cntrol_dmat) != 0) {
852d720e6d5SJustin T. Gibbs 		printf("%s: cannot create a dma tag for control spaces\n",
853d720e6d5SJustin T. Gibbs 		    isp->isp_name);
854a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
855a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
856d720e6d5SJustin T. Gibbs 		return (1);
857d720e6d5SJustin T. Gibbs 	}
858d720e6d5SJustin T. Gibbs 	if (bus_dmamem_alloc(pci->cntrol_dmat, (void **)&base,
859d720e6d5SJustin T. Gibbs 	    BUS_DMA_NOWAIT, &pci->cntrol_dmap) != 0) {
8604873663cSMatt Jacob 		printf("%s: cannot allocate %d bytes of CCB memory\n",
8614873663cSMatt Jacob 		    isp->isp_name, len);
862a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
863a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
864d720e6d5SJustin T. Gibbs 		return (1);
865d720e6d5SJustin T. Gibbs 	}
866d720e6d5SJustin T. Gibbs 
867d720e6d5SJustin T. Gibbs 	isp->isp_rquest = base;
868222bb542SMatt Jacob 	im.isp = isp;
869222bb542SMatt Jacob 	im.error = 0;
870d720e6d5SJustin T. Gibbs 	bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_rquest,
871222bb542SMatt Jacob 	    ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN), isp_map_rquest, &im, 0);
872222bb542SMatt Jacob 	if (im.error) {
873222bb542SMatt Jacob 		printf("%s: error %d loading dma map for DMA request queue\n",
874222bb542SMatt Jacob 		    isp->isp_name, im.error);
875a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
876a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
877a95ae193SMatt Jacob 		isp->isp_rquest = NULL;
878222bb542SMatt Jacob 		return (1);
879222bb542SMatt Jacob 	}
880d720e6d5SJustin T. Gibbs 	isp->isp_result = base + ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN);
881222bb542SMatt Jacob 	im.error = 0;
882d720e6d5SJustin T. Gibbs 	bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_result,
883222bb542SMatt Jacob 	    ISP_QUEUE_SIZE(RESULT_QUEUE_LEN), isp_map_result, &im, 0);
884222bb542SMatt Jacob 	if (im.error) {
885222bb542SMatt Jacob 		printf("%s: error %d loading dma map for DMA result queue\n",
886222bb542SMatt Jacob 		    isp->isp_name, im.error);
887a95ae193SMatt Jacob 		free(isp->isp_xflist, M_DEVBUF);
888a95ae193SMatt Jacob 		free(pci->dmaps, M_DEVBUF);
889a95ae193SMatt Jacob 		isp->isp_rquest = NULL;
890222bb542SMatt Jacob 		return (1);
891222bb542SMatt Jacob 	}
892d720e6d5SJustin T. Gibbs 
893a95ae193SMatt Jacob 	for (i = 0; i < isp->isp_maxcmds; i++) {
894d720e6d5SJustin T. Gibbs 		error = bus_dmamap_create(pci->parent_dmat, 0, &pci->dmaps[i]);
895d720e6d5SJustin T. Gibbs 		if (error) {
896a95ae193SMatt Jacob 			printf("%s: error %d creating per-cmd DMA maps\n",
897d720e6d5SJustin T. Gibbs 			    isp->isp_name, error);
898a95ae193SMatt Jacob 			free(isp->isp_xflist, M_DEVBUF);
899a95ae193SMatt Jacob 			free(pci->dmaps, M_DEVBUF);
900a95ae193SMatt Jacob 			isp->isp_rquest = NULL;
901d720e6d5SJustin T. Gibbs 			return (1);
902d720e6d5SJustin T. Gibbs 		}
903d720e6d5SJustin T. Gibbs 	}
904a95ae193SMatt Jacob 
905222bb542SMatt Jacob 	if (IS_FC(isp)) {
90692c49d78SMatt Jacob 		fcparam *fcp = (fcparam *) isp->isp_param;
90792c49d78SMatt Jacob 		fcp->isp_scratch = base +
90892c49d78SMatt Jacob 			ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN) +
90992c49d78SMatt Jacob 			ISP_QUEUE_SIZE(RESULT_QUEUE_LEN);
910222bb542SMatt Jacob 		im.error = 0;
91192c49d78SMatt Jacob 		bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap,
912222bb542SMatt Jacob 		    fcp->isp_scratch, ISP2100_SCRLEN, isp_map_fcscrt, &im, 0);
913222bb542SMatt Jacob 		if (im.error) {
914222bb542SMatt Jacob 			printf("%s: error %d loading FC scratch area\n",
915222bb542SMatt Jacob 			    isp->isp_name, im.error);
916a95ae193SMatt Jacob 			free(isp->isp_xflist, M_DEVBUF);
917a95ae193SMatt Jacob 			free(pci->dmaps, M_DEVBUF);
918a95ae193SMatt Jacob 			isp->isp_rquest = NULL;
919222bb542SMatt Jacob 			return (1);
920222bb542SMatt Jacob 		}
92192c49d78SMatt Jacob 	}
922d720e6d5SJustin T. Gibbs 	return (0);
923d720e6d5SJustin T. Gibbs }
924d720e6d5SJustin T. Gibbs 
925d720e6d5SJustin T. Gibbs static void dma2 __P((void *, bus_dma_segment_t *, int, int));
926d720e6d5SJustin T. Gibbs typedef struct {
927d720e6d5SJustin T. Gibbs 	struct ispsoftc *isp;
928d720e6d5SJustin T. Gibbs 	ISP_SCSI_XFER_T *ccb;
929d720e6d5SJustin T. Gibbs 	ispreq_t *rq;
930d720e6d5SJustin T. Gibbs 	u_int8_t *iptrp;
931d720e6d5SJustin T. Gibbs 	u_int8_t optr;
932d720e6d5SJustin T. Gibbs 	u_int error;
933d720e6d5SJustin T. Gibbs } mush_t;
934d720e6d5SJustin T. Gibbs 
9354873663cSMatt Jacob #define	MUSHERR_NOQENTRIES	-2
9364873663cSMatt Jacob 
937d720e6d5SJustin T. Gibbs static void
93817e318c6SMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
939d720e6d5SJustin T. Gibbs {
940d720e6d5SJustin T. Gibbs 	mush_t *mp;
941d720e6d5SJustin T. Gibbs 	ISP_SCSI_XFER_T *ccb;
942d720e6d5SJustin T. Gibbs 	struct ispsoftc *isp;
943d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci;
944d720e6d5SJustin T. Gibbs 	bus_dmamap_t *dp;
945d720e6d5SJustin T. Gibbs 	bus_dma_segment_t *eseg;
946d720e6d5SJustin T. Gibbs 	ispreq_t *rq;
947d720e6d5SJustin T. Gibbs 	u_int8_t *iptrp;
948d720e6d5SJustin T. Gibbs 	u_int8_t optr;
949d720e6d5SJustin T. Gibbs 	ispcontreq_t *crq;
950d720e6d5SJustin T. Gibbs 	int drq, seglim, datalen;
951d720e6d5SJustin T. Gibbs 
952d720e6d5SJustin T. Gibbs 	mp = (mush_t *) arg;
953d720e6d5SJustin T. Gibbs 	if (error) {
954d720e6d5SJustin T. Gibbs 		mp->error = error;
955d720e6d5SJustin T. Gibbs 		return;
956d720e6d5SJustin T. Gibbs 	}
957d720e6d5SJustin T. Gibbs 
958d720e6d5SJustin T. Gibbs 	isp = mp->isp;
959d720e6d5SJustin T. Gibbs 	if (nseg < 1) {
960d720e6d5SJustin T. Gibbs 		printf("%s: zero or negative segment count\n", isp->isp_name);
961d720e6d5SJustin T. Gibbs 		mp->error = EFAULT;
962d720e6d5SJustin T. Gibbs 		return;
963d720e6d5SJustin T. Gibbs 	}
964d720e6d5SJustin T. Gibbs 	ccb = mp->ccb;
965d720e6d5SJustin T. Gibbs 	rq = mp->rq;
966d720e6d5SJustin T. Gibbs 	iptrp = mp->iptrp;
967d720e6d5SJustin T. Gibbs 	optr = mp->optr;
968d720e6d5SJustin T. Gibbs 	pci = (struct isp_pcisoftc *)isp;
969d720e6d5SJustin T. Gibbs 	dp = &pci->dmaps[rq->req_handle - 1];
970a95ae193SMatt Jacob 
971d720e6d5SJustin T. Gibbs 	if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
972d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
973d720e6d5SJustin T. Gibbs 		drq = REQFLAG_DATA_IN;
974d720e6d5SJustin T. Gibbs 	} else {
975d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
976d720e6d5SJustin T. Gibbs 		drq = REQFLAG_DATA_OUT;
977d720e6d5SJustin T. Gibbs 	}
978d720e6d5SJustin T. Gibbs 
979d720e6d5SJustin T. Gibbs 	datalen = XS_XFRLEN(ccb);
980222bb542SMatt Jacob 	if (IS_FC(isp)) {
981d720e6d5SJustin T. Gibbs 		seglim = ISP_RQDSEG_T2;
982d720e6d5SJustin T. Gibbs 		((ispreqt2_t *)rq)->req_totalcnt = datalen;
983d720e6d5SJustin T. Gibbs 		((ispreqt2_t *)rq)->req_flags |= drq;
984d720e6d5SJustin T. Gibbs 	} else {
985d720e6d5SJustin T. Gibbs 		seglim = ISP_RQDSEG;
986d720e6d5SJustin T. Gibbs 		rq->req_flags |= drq;
987d720e6d5SJustin T. Gibbs 	}
988d720e6d5SJustin T. Gibbs 
989d720e6d5SJustin T. Gibbs 	eseg = dm_segs + nseg;
990d720e6d5SJustin T. Gibbs 
991d720e6d5SJustin T. Gibbs 	while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) {
992222bb542SMatt Jacob 		if (IS_FC(isp)) {
993d720e6d5SJustin T. Gibbs 			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
994d720e6d5SJustin T. Gibbs 			rq2->req_dataseg[rq2->req_seg_count].ds_base =
995d720e6d5SJustin T. Gibbs 			    dm_segs->ds_addr;
996d720e6d5SJustin T. Gibbs 			rq2->req_dataseg[rq2->req_seg_count].ds_count =
997d720e6d5SJustin T. Gibbs 			    dm_segs->ds_len;
998d720e6d5SJustin T. Gibbs 		} else {
999d720e6d5SJustin T. Gibbs 			rq->req_dataseg[rq->req_seg_count].ds_base =
1000d720e6d5SJustin T. Gibbs 				dm_segs->ds_addr;
1001d720e6d5SJustin T. Gibbs 			rq->req_dataseg[rq->req_seg_count].ds_count =
1002d720e6d5SJustin T. Gibbs 				dm_segs->ds_len;
1003d720e6d5SJustin T. Gibbs 		}
1004d720e6d5SJustin T. Gibbs 		datalen -= dm_segs->ds_len;
1005d720e6d5SJustin T. Gibbs #if	0
1006222bb542SMatt Jacob 		if (IS_FC(isp)) {
1007d720e6d5SJustin T. Gibbs 			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
1008d720e6d5SJustin T. Gibbs 			printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n",
1009d720e6d5SJustin T. Gibbs 			    isp->isp_name, rq->req_seg_count,
1010d720e6d5SJustin T. Gibbs 			    rq2->req_dataseg[rq2->req_seg_count].ds_count,
1011d720e6d5SJustin T. Gibbs 			    rq2->req_dataseg[rq2->req_seg_count].ds_base);
1012d720e6d5SJustin T. Gibbs 		} else {
1013d720e6d5SJustin T. Gibbs 			printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n",
1014d720e6d5SJustin T. Gibbs 			    isp->isp_name, rq->req_seg_count,
1015d720e6d5SJustin T. Gibbs 			    rq->req_dataseg[rq->req_seg_count].ds_count,
1016d720e6d5SJustin T. Gibbs 			    rq->req_dataseg[rq->req_seg_count].ds_base);
1017d720e6d5SJustin T. Gibbs 		}
1018d720e6d5SJustin T. Gibbs #endif
1019d720e6d5SJustin T. Gibbs 		rq->req_seg_count++;
1020d720e6d5SJustin T. Gibbs 		dm_segs++;
1021d720e6d5SJustin T. Gibbs 	}
1022d720e6d5SJustin T. Gibbs 
1023d720e6d5SJustin T. Gibbs 	while (datalen > 0 && dm_segs != eseg) {
1024d720e6d5SJustin T. Gibbs 		crq = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, *iptrp);
10254873663cSMatt Jacob 		*iptrp = ISP_NXT_QENTRY(*iptrp, RQUEST_QUEUE_LEN);
1026d720e6d5SJustin T. Gibbs 		if (*iptrp == optr) {
10274873663cSMatt Jacob #if	0
10284873663cSMatt Jacob 			printf("%s: Request Queue Overflow++\n", isp->isp_name);
10294873663cSMatt Jacob #endif
10304873663cSMatt Jacob 			mp->error = MUSHERR_NOQENTRIES;
1031d720e6d5SJustin T. Gibbs 			return;
1032d720e6d5SJustin T. Gibbs 		}
1033d720e6d5SJustin T. Gibbs 		rq->req_header.rqs_entry_count++;
1034d720e6d5SJustin T. Gibbs 		bzero((void *)crq, sizeof (*crq));
1035d720e6d5SJustin T. Gibbs 		crq->req_header.rqs_entry_count = 1;
1036d720e6d5SJustin T. Gibbs 		crq->req_header.rqs_entry_type = RQSTYPE_DATASEG;
1037d720e6d5SJustin T. Gibbs 
1038d720e6d5SJustin T. Gibbs 		seglim = 0;
1039d720e6d5SJustin T. Gibbs 		while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) {
1040d720e6d5SJustin T. Gibbs 			crq->req_dataseg[seglim].ds_base =
1041d720e6d5SJustin T. Gibbs 			    dm_segs->ds_addr;
1042d720e6d5SJustin T. Gibbs 			crq->req_dataseg[seglim].ds_count =
1043d720e6d5SJustin T. Gibbs 			    dm_segs->ds_len;
1044d720e6d5SJustin T. Gibbs #if	0
1045d720e6d5SJustin T. Gibbs 			printf("%s: seg%d[%d] cnt 0x%x paddr 0x%08x\n",
1046d720e6d5SJustin T. Gibbs 			    isp->isp_name, rq->req_header.rqs_entry_count-1,
1047d720e6d5SJustin T. Gibbs 			    seglim, crq->req_dataseg[seglim].ds_count,
1048d720e6d5SJustin T. Gibbs 			    crq->req_dataseg[seglim].ds_base);
1049d720e6d5SJustin T. Gibbs #endif
1050d720e6d5SJustin T. Gibbs 			rq->req_seg_count++;
1051d720e6d5SJustin T. Gibbs 			dm_segs++;
1052d720e6d5SJustin T. Gibbs 			seglim++;
1053d720e6d5SJustin T. Gibbs 			datalen -= dm_segs->ds_len;
1054d720e6d5SJustin T. Gibbs 		}
1055d720e6d5SJustin T. Gibbs 	}
1056d720e6d5SJustin T. Gibbs }
1057d720e6d5SJustin T. Gibbs 
1058d720e6d5SJustin T. Gibbs static int
105917e318c6SMatt Jacob isp_pci_dmasetup(struct ispsoftc *isp, ISP_SCSI_XFER_T *ccb, ispreq_t *rq,
106017e318c6SMatt Jacob 	u_int8_t *iptrp, u_int8_t optr)
1061d720e6d5SJustin T. Gibbs {
1062d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
1063d720e6d5SJustin T. Gibbs 	struct ccb_hdr *ccb_h;
1064d720e6d5SJustin T. Gibbs 	struct ccb_scsiio *csio;
10650a5f7e8bSMatt Jacob 	bus_dmamap_t *dp = NULL;
1066d720e6d5SJustin T. Gibbs 	mush_t mush, *mp;
1067d720e6d5SJustin T. Gibbs 
1068d720e6d5SJustin T. Gibbs 	csio = (struct ccb_scsiio *) ccb;
1069d720e6d5SJustin T. Gibbs 	ccb_h = &csio->ccb_h;
1070d720e6d5SJustin T. Gibbs 
1071d720e6d5SJustin T. Gibbs 	if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_NONE) {
1072d720e6d5SJustin T. Gibbs 		rq->req_seg_count = 1;
10734873663cSMatt Jacob 		return (CMD_QUEUED);
1074d720e6d5SJustin T. Gibbs 	}
1075d720e6d5SJustin T. Gibbs 
1076d720e6d5SJustin T. Gibbs 	/*
1077d720e6d5SJustin T. Gibbs 	 * Do a virtual grapevine step to collect info for
10784873663cSMatt Jacob 	 * the callback dma allocation that we have to use...
1079d720e6d5SJustin T. Gibbs 	 */
1080d720e6d5SJustin T. Gibbs 	mp = &mush;
1081d720e6d5SJustin T. Gibbs 	mp->isp = isp;
1082d720e6d5SJustin T. Gibbs 	mp->ccb = ccb;
1083d720e6d5SJustin T. Gibbs 	mp->rq = rq;
1084d720e6d5SJustin T. Gibbs 	mp->iptrp = iptrp;
1085d720e6d5SJustin T. Gibbs 	mp->optr = optr;
1086d720e6d5SJustin T. Gibbs 	mp->error = 0;
1087d720e6d5SJustin T. Gibbs 
1088d720e6d5SJustin T. Gibbs 	if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) {
1089d720e6d5SJustin T. Gibbs 		if ((ccb_h->flags & CAM_DATA_PHYS) == 0) {
10904873663cSMatt Jacob 			int error, s;
10910a5f7e8bSMatt Jacob 			dp = &pci->dmaps[rq->req_handle - 1];
1092d720e6d5SJustin T. Gibbs 			s = splsoftvm();
1093d720e6d5SJustin T. Gibbs 			error = bus_dmamap_load(pci->parent_dmat, *dp,
1094d720e6d5SJustin T. Gibbs 			    csio->data_ptr, csio->dxfer_len, dma2, mp, 0);
1095d720e6d5SJustin T. Gibbs 			if (error == EINPROGRESS) {
1096d720e6d5SJustin T. Gibbs 				bus_dmamap_unload(pci->parent_dmat, *dp);
1097d720e6d5SJustin T. Gibbs 				mp->error = EINVAL;
10984873663cSMatt Jacob 				printf("%s: deferred dma allocation not "
10994873663cSMatt Jacob 				    "supported\n", isp->isp_name);
1100d720e6d5SJustin T. Gibbs 			} else if (error && mp->error == 0) {
11010a5f7e8bSMatt Jacob #ifdef	DIAGNOSTIC
11020a5f7e8bSMatt Jacob 				printf("%s: error %d in dma mapping code\n",
11030a5f7e8bSMatt Jacob 				    isp->isp_name, error);
11040a5f7e8bSMatt Jacob #endif
1105d720e6d5SJustin T. Gibbs 				mp->error = error;
1106d720e6d5SJustin T. Gibbs 			}
11074873663cSMatt Jacob 			splx(s);
1108d720e6d5SJustin T. Gibbs 		} else {
1109d720e6d5SJustin T. Gibbs 			/* Pointer to physical buffer */
1110d720e6d5SJustin T. Gibbs 			struct bus_dma_segment seg;
1111d720e6d5SJustin T. Gibbs 			seg.ds_addr = (bus_addr_t)csio->data_ptr;
1112d720e6d5SJustin T. Gibbs 			seg.ds_len = csio->dxfer_len;
1113d720e6d5SJustin T. Gibbs 			dma2(mp, &seg, 1, 0);
1114d720e6d5SJustin T. Gibbs 		}
1115d720e6d5SJustin T. Gibbs 	} else {
1116d720e6d5SJustin T. Gibbs 		struct bus_dma_segment *segs;
1117d720e6d5SJustin T. Gibbs 
1118d720e6d5SJustin T. Gibbs 		if ((ccb_h->flags & CAM_DATA_PHYS) != 0) {
1119d720e6d5SJustin T. Gibbs 			printf("%s: Physical segment pointers unsupported",
1120d720e6d5SJustin T. Gibbs 				isp->isp_name);
1121d720e6d5SJustin T. Gibbs 			mp->error = EINVAL;
1122d720e6d5SJustin T. Gibbs 		} else if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0) {
1123d720e6d5SJustin T. Gibbs 			printf("%s: Virtual segment addresses unsupported",
1124d720e6d5SJustin T. Gibbs 				isp->isp_name);
1125d720e6d5SJustin T. Gibbs 			mp->error = EINVAL;
1126d720e6d5SJustin T. Gibbs 		} else {
1127d720e6d5SJustin T. Gibbs 			/* Just use the segments provided */
1128d720e6d5SJustin T. Gibbs 			segs = (struct bus_dma_segment *) csio->data_ptr;
1129d720e6d5SJustin T. Gibbs 			dma2(mp, segs, csio->sglist_cnt, 0);
1130d720e6d5SJustin T. Gibbs 		}
1131d720e6d5SJustin T. Gibbs 	}
1132d720e6d5SJustin T. Gibbs 	if (mp->error) {
11334873663cSMatt Jacob 		int retval = CMD_COMPLETE;
11344873663cSMatt Jacob 		if (mp->error == MUSHERR_NOQENTRIES) {
11354873663cSMatt Jacob 			retval = CMD_EAGAIN;
11364873663cSMatt Jacob 		} else if (mp->error == EFBIG) {
11370a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_REQ_TOO_BIG);
1138d720e6d5SJustin T. Gibbs 		} else if (mp->error == EINVAL) {
11390a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_REQ_INVALID);
1140d720e6d5SJustin T. Gibbs 		} else {
11410a5f7e8bSMatt Jacob 			XS_SETERR(csio, CAM_UNREC_HBA_ERROR);
1142d720e6d5SJustin T. Gibbs 		}
11434873663cSMatt Jacob 		return (retval);
11444873663cSMatt Jacob 	} else {
11450a5f7e8bSMatt Jacob 		/*
11460a5f7e8bSMatt Jacob 		 * Check to see if we weren't cancelled while sleeping on
11470a5f7e8bSMatt Jacob 		 * getting DMA resources...
11480a5f7e8bSMatt Jacob 		 */
11490a5f7e8bSMatt Jacob 		if ((ccb_h->status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
11500a5f7e8bSMatt Jacob 			if (dp) {
11510a5f7e8bSMatt Jacob 				bus_dmamap_unload(pci->parent_dmat, *dp);
11520a5f7e8bSMatt Jacob 			}
11530a5f7e8bSMatt Jacob 			return (CMD_COMPLETE);
11540a5f7e8bSMatt Jacob 		}
11554873663cSMatt Jacob 		return (CMD_QUEUED);
1156d720e6d5SJustin T. Gibbs 	}
1157d720e6d5SJustin T. Gibbs }
1158d720e6d5SJustin T. Gibbs 
1159d720e6d5SJustin T. Gibbs static void
1160a95ae193SMatt Jacob isp_pci_dmateardown(struct ispsoftc *isp, ISP_SCSI_XFER_T *xs, u_int32_t handle)
1161d720e6d5SJustin T. Gibbs {
1162d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
1163a95ae193SMatt Jacob 	bus_dmamap_t *dp = &pci->dmaps[handle - 1];
1164a95ae193SMatt Jacob 	KASSERT((handle > 0 && handle <= isp->isp_maxcmds),
1165a95ae193SMatt Jacob 	    ("bad handle in isp_pci_dmateardonw"));
1166a95ae193SMatt Jacob 	if ((xs->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1167d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTREAD);
1168d720e6d5SJustin T. Gibbs 	} else {
1169d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTWRITE);
1170d720e6d5SJustin T. Gibbs 	}
1171d720e6d5SJustin T. Gibbs 	bus_dmamap_unload(pci->parent_dmat, *dp);
1172d720e6d5SJustin T. Gibbs }
1173d720e6d5SJustin T. Gibbs 
117465adb54cSMatt Jacob 
117565adb54cSMatt Jacob static void
117617e318c6SMatt Jacob isp_pci_reset1(struct ispsoftc *isp)
117765adb54cSMatt Jacob {
117865adb54cSMatt Jacob 	/* Make sure the BIOS is disabled */
117965adb54cSMatt Jacob 	isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS);
118065adb54cSMatt Jacob }
118165adb54cSMatt Jacob 
118265adb54cSMatt Jacob static void
118317e318c6SMatt Jacob isp_pci_dumpregs(struct ispsoftc *isp)
118465adb54cSMatt Jacob {
118565adb54cSMatt Jacob 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
11869bffbcd4SBruce Evans 	printf("%s: PCI Status Command/Status=%lx\n", pci->pci_isp.isp_name,
1187d951bbcaSMatt Jacob 	    pci_conf_read(pci->pci_id, PCIR_COMMAND));
118865adb54cSMatt Jacob }
1189