xref: /freebsd/sys/dev/isp/isp_pci.c (revision 96b3554e5c90242d0c5eea10fc394975d03303a8)
196b3554eSPeter Wemm /* $Id: isp_pci.c,v 1.19 1999/04/11 02:47:31 eivind Exp $ */
2ab6d0040SMatt Jacob /* release_4_3_99 */
365adb54cSMatt Jacob /*
465adb54cSMatt Jacob  * PCI specific probe and attach routines for Qlogic ISP SCSI adapters.
565adb54cSMatt Jacob  * FreeBSD Version.
665adb54cSMatt Jacob  *
765adb54cSMatt Jacob  *---------------------------------------
865adb54cSMatt Jacob  * Copyright (c) 1997, 1998 by Matthew Jacob
965adb54cSMatt Jacob  * NASA/Ames Research Center
1065adb54cSMatt Jacob  * All rights reserved.
1165adb54cSMatt Jacob  *---------------------------------------
1265adb54cSMatt Jacob  *
1365adb54cSMatt Jacob  * Redistribution and use in source and binary forms, with or without
1465adb54cSMatt Jacob  * modification, are permitted provided that the following conditions
1565adb54cSMatt Jacob  * are met:
1665adb54cSMatt Jacob  * 1. Redistributions of source code must retain the above copyright
1765adb54cSMatt Jacob  *    notice immediately at the beginning of the file, without modification,
1865adb54cSMatt Jacob  *    this list of conditions, and the following disclaimer.
1965adb54cSMatt Jacob  * 2. Redistributions in binary form must reproduce the above copyright
2065adb54cSMatt Jacob  *    notice, this list of conditions and the following disclaimer in the
2165adb54cSMatt Jacob  *    documentation and/or other materials provided with the distribution.
2265adb54cSMatt Jacob  * 3. The name of the author may not be used to endorse or promote products
2365adb54cSMatt Jacob  *    derived from this software without specific prior written permission.
2465adb54cSMatt Jacob  *
2565adb54cSMatt Jacob  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2665adb54cSMatt Jacob  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2765adb54cSMatt Jacob  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2865adb54cSMatt Jacob  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2965adb54cSMatt Jacob  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3065adb54cSMatt Jacob  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3165adb54cSMatt Jacob  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3265adb54cSMatt Jacob  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3365adb54cSMatt Jacob  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3465adb54cSMatt Jacob  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3565adb54cSMatt Jacob  * SUCH DAMAGE.
3665adb54cSMatt Jacob  */
3765adb54cSMatt Jacob #include <dev/isp/isp_freebsd.h>
3865adb54cSMatt Jacob #include <dev/isp/asm_pci.h>
39d720e6d5SJustin T. Gibbs #include <sys/malloc.h>
40d720e6d5SJustin T. Gibbs #include <vm/vm.h>
41d720e6d5SJustin T. Gibbs #include <vm/pmap.h>
42d720e6d5SJustin T. Gibbs #include <vm/vm_extern.h>
43d720e6d5SJustin T. Gibbs 
4465adb54cSMatt Jacob 
4565adb54cSMatt Jacob #include <pci/pcireg.h>
4665adb54cSMatt Jacob #include <pci/pcivar.h>
4765adb54cSMatt Jacob 
483dd37e43SMatt Jacob #if	__FreeBSD_version >= 300004
49d720e6d5SJustin T. Gibbs #include <machine/bus_memio.h>
50d720e6d5SJustin T. Gibbs #include <machine/bus_pio.h>
51d720e6d5SJustin T. Gibbs #include <machine/bus.h>
52d720e6d5SJustin T. Gibbs #endif
53d720e6d5SJustin T. Gibbs 
54d59bd469SMatt Jacob #include "opt_isp.h"
55d59bd469SMatt Jacob 
5665adb54cSMatt Jacob static u_int16_t isp_pci_rd_reg __P((struct ispsoftc *, int));
5765adb54cSMatt Jacob static void isp_pci_wr_reg __P((struct ispsoftc *, int, u_int16_t));
58d59bd469SMatt Jacob #ifndef ISP_DISABLE_1080_SUPPORT
59d59bd469SMatt Jacob static u_int16_t isp_pci_rd_reg_1080 __P((struct ispsoftc *, int));
60d59bd469SMatt Jacob static void isp_pci_wr_reg_1080 __P((struct ispsoftc *, int, u_int16_t));
61d59bd469SMatt Jacob #endif
6265adb54cSMatt Jacob static int isp_pci_mbxdma __P((struct ispsoftc *));
6365adb54cSMatt Jacob static int isp_pci_dmasetup __P((struct ispsoftc *, ISP_SCSI_XFER_T *,
6465adb54cSMatt Jacob 	ispreq_t *, u_int8_t *, u_int8_t));
653dd37e43SMatt Jacob #if	__FreeBSD_version >= 300004
66d720e6d5SJustin T. Gibbs static void
67d720e6d5SJustin T. Gibbs isp_pci_dmateardown __P((struct ispsoftc *, ISP_SCSI_XFER_T *, u_int32_t));
68ab6d0040SMatt Jacob #define	PROBETYPE	const char *
69d720e6d5SJustin T. Gibbs #else
70ab6d0040SMatt Jacob typedef u_int16_t pci_port_t;
71d720e6d5SJustin T. Gibbs #define	isp_pci_dmateardown	NULL
72ab6d0040SMatt Jacob #define	PROBETYPE	char *
73d720e6d5SJustin T. Gibbs #endif
7465adb54cSMatt Jacob 
7565adb54cSMatt Jacob static void isp_pci_reset1 __P((struct ispsoftc *));
7665adb54cSMatt Jacob static void isp_pci_dumpregs __P((struct ispsoftc *));
7765adb54cSMatt Jacob 
78d59bd469SMatt Jacob #ifndef ISP_DISABLE_1020_SUPPORT
7965adb54cSMatt Jacob static struct ispmdvec mdvec = {
8065adb54cSMatt Jacob 	isp_pci_rd_reg,
8165adb54cSMatt Jacob 	isp_pci_wr_reg,
8265adb54cSMatt Jacob 	isp_pci_mbxdma,
8365adb54cSMatt Jacob 	isp_pci_dmasetup,
84d720e6d5SJustin T. Gibbs 	isp_pci_dmateardown,
8565adb54cSMatt Jacob 	NULL,
8665adb54cSMatt Jacob 	isp_pci_reset1,
8765adb54cSMatt Jacob 	isp_pci_dumpregs,
8865adb54cSMatt Jacob 	ISP_RISC_CODE,
8965adb54cSMatt Jacob 	ISP_CODE_LENGTH,
9065adb54cSMatt Jacob 	ISP_CODE_ORG,
9165adb54cSMatt Jacob 	ISP_CODE_VERSION,
92285e230dSMatt Jacob 	BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64,
93d720e6d5SJustin T. Gibbs 	0
9465adb54cSMatt Jacob };
95d59bd469SMatt Jacob #endif
9665adb54cSMatt Jacob 
97d59bd469SMatt Jacob #ifndef ISP_DISABLE_1080_SUPPORT
98d59bd469SMatt Jacob static struct ispmdvec mdvec_1080 = {
99d59bd469SMatt Jacob 	isp_pci_rd_reg_1080,
100d59bd469SMatt Jacob 	isp_pci_wr_reg_1080,
101d59bd469SMatt Jacob 	isp_pci_mbxdma,
102d59bd469SMatt Jacob 	isp_pci_dmasetup,
103d59bd469SMatt Jacob 	isp_pci_dmateardown,
104d59bd469SMatt Jacob 	NULL,
105d59bd469SMatt Jacob 	isp_pci_reset1,
106d59bd469SMatt Jacob 	isp_pci_dumpregs,
10792c49d78SMatt Jacob 	ISP1080_RISC_CODE,
10892c49d78SMatt Jacob 	ISP1080_CODE_LENGTH,
10992c49d78SMatt Jacob 	ISP1080_CODE_ORG,
11092c49d78SMatt Jacob 	ISP1080_CODE_VERSION,
111d59bd469SMatt Jacob 	BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64,
112d59bd469SMatt Jacob 	0
113d59bd469SMatt Jacob };
114d59bd469SMatt Jacob #endif
115d59bd469SMatt Jacob 
116d59bd469SMatt Jacob #ifndef ISP_DISABLE_2100_SUPPORT
11765adb54cSMatt Jacob static struct ispmdvec mdvec_2100 = {
11865adb54cSMatt Jacob 	isp_pci_rd_reg,
11965adb54cSMatt Jacob 	isp_pci_wr_reg,
12065adb54cSMatt Jacob 	isp_pci_mbxdma,
12165adb54cSMatt Jacob 	isp_pci_dmasetup,
122d720e6d5SJustin T. Gibbs 	isp_pci_dmateardown,
12365adb54cSMatt Jacob 	NULL,
12465adb54cSMatt Jacob 	isp_pci_reset1,
12565adb54cSMatt Jacob 	isp_pci_dumpregs,
12665adb54cSMatt Jacob 	ISP2100_RISC_CODE,
12765adb54cSMatt Jacob 	ISP2100_CODE_LENGTH,
12865adb54cSMatt Jacob 	ISP2100_CODE_ORG,
12965adb54cSMatt Jacob 	ISP2100_CODE_VERSION,
130285e230dSMatt Jacob 	0,			/* Irrelevant to the 2100 */
131d720e6d5SJustin T. Gibbs 	0
13265adb54cSMatt Jacob };
133d59bd469SMatt Jacob #endif
13465adb54cSMatt Jacob 
135d951bbcaSMatt Jacob #ifndef	SCSI_ISP_PREFER_MEM_MAP
136d951bbcaSMatt Jacob #ifdef	__alpha__
137d951bbcaSMatt Jacob #define	SCSI_ISP_PREFER_MEM_MAP	0
138d951bbcaSMatt Jacob #else
139d951bbcaSMatt Jacob #define	SCSI_ISP_PREFER_MEM_MAP	1
140d951bbcaSMatt Jacob #endif
141d951bbcaSMatt Jacob #endif
142d951bbcaSMatt Jacob 
14365adb54cSMatt Jacob #ifndef	PCIM_CMD_INVEN
14465adb54cSMatt Jacob #define	PCIM_CMD_INVEN			0x10
14565adb54cSMatt Jacob #endif
14665adb54cSMatt Jacob #ifndef	PCIM_CMD_BUSMASTEREN
14765adb54cSMatt Jacob #define	PCIM_CMD_BUSMASTEREN		0x0004
14865adb54cSMatt Jacob #endif
149d951bbcaSMatt Jacob #ifndef	PCIM_CMD_PERRESPEN
150d951bbcaSMatt Jacob #define	PCIM_CMD_PERRESPEN		0x0040
151d951bbcaSMatt Jacob #endif
152d951bbcaSMatt Jacob #ifndef	PCIM_CMD_SEREN
153d951bbcaSMatt Jacob #define	PCIM_CMD_SEREN			0x0100
154d951bbcaSMatt Jacob #endif
155d951bbcaSMatt Jacob 
156d951bbcaSMatt Jacob #ifndef	PCIR_COMMAND
157d951bbcaSMatt Jacob #define	PCIR_COMMAND			0x04
158d951bbcaSMatt Jacob #endif
159d951bbcaSMatt Jacob 
160d951bbcaSMatt Jacob #ifndef	PCIR_CACHELNSZ
161d951bbcaSMatt Jacob #define	PCIR_CACHELNSZ			0x0c
162d951bbcaSMatt Jacob #endif
163d951bbcaSMatt Jacob 
164d951bbcaSMatt Jacob #ifndef	PCIR_LATTIMER
165d951bbcaSMatt Jacob #define	PCIR_LATTIMER			0x0d
166d951bbcaSMatt Jacob #endif
167d951bbcaSMatt Jacob 
168ab6d0040SMatt Jacob #ifndef	PCIR_ROMADDR
169ab6d0040SMatt Jacob #define	PCIR_ROMADDR			0x30
170ab6d0040SMatt Jacob #endif
171ab6d0040SMatt Jacob 
17265adb54cSMatt Jacob #ifndef	PCI_VENDOR_QLOGIC
17365adb54cSMatt Jacob #define	PCI_VENDOR_QLOGIC	0x1077
17465adb54cSMatt Jacob #endif
17565adb54cSMatt Jacob 
17665adb54cSMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1020
17765adb54cSMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1020	0x1020
17865adb54cSMatt Jacob #endif
17965adb54cSMatt Jacob 
180d59bd469SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1080
181d59bd469SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1080	0x1080
182d59bd469SMatt Jacob #endif
183d59bd469SMatt Jacob 
184d59bd469SMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP1240
185d59bd469SMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP1240	0x1240
186d59bd469SMatt Jacob #endif
18765adb54cSMatt Jacob 
18865adb54cSMatt Jacob #ifndef	PCI_PRODUCT_QLOGIC_ISP2100
18965adb54cSMatt Jacob #define	PCI_PRODUCT_QLOGIC_ISP2100	0x2100
19065adb54cSMatt Jacob #endif
19165adb54cSMatt Jacob 
192d59bd469SMatt Jacob #define	PCI_QLOGIC_ISP	((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC)
193d59bd469SMatt Jacob 
194d59bd469SMatt Jacob #define	PCI_QLOGIC_ISP1080	\
195d59bd469SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC)
196d59bd469SMatt Jacob 
197d59bd469SMatt Jacob #define	PCI_QLOGIC_ISP1240	\
198d59bd469SMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC)
199d59bd469SMatt Jacob 
20065adb54cSMatt Jacob #define	PCI_QLOGIC_ISP2100	\
20165adb54cSMatt Jacob 	((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC)
20265adb54cSMatt Jacob 
20365adb54cSMatt Jacob #define	IO_MAP_REG	0x10
20465adb54cSMatt Jacob #define	MEM_MAP_REG	0x14
20565adb54cSMatt Jacob 
206d951bbcaSMatt Jacob #define	PCI_DFLT_LTNCY	0x40
207d951bbcaSMatt Jacob #define	PCI_DFLT_LNSZ	0x10
20865adb54cSMatt Jacob 
209ab6d0040SMatt Jacob static PROBETYPE isp_pci_probe __P((pcici_t tag, pcidi_t type));
21065adb54cSMatt Jacob static void isp_pci_attach __P((pcici_t config_d, int unit));
21165adb54cSMatt Jacob 
212d720e6d5SJustin T. Gibbs /* This distinguishing define is not right, but it does work */
21365adb54cSMatt Jacob 
2143dd37e43SMatt Jacob #if	__FreeBSD_version < 300004
215a185f9b1SMatt Jacob #define	IO_SPACE_MAPPING	0
216a185f9b1SMatt Jacob #define	MEM_SPACE_MAPPING	1
21765adb54cSMatt Jacob typedef int bus_space_tag_t;
21865adb54cSMatt Jacob typedef u_long bus_space_handle_t;
219ab6d0040SMatt Jacob typedef unsigned int            __uintptr_t;
220ab6d0040SMatt Jacob typedef __uintptr_t     uintptr_t;
221a185f9b1SMatt Jacob #ifdef __alpha__
22265adb54cSMatt Jacob #define	bus_space_read_2(st, sh, offset)	\
223d951bbcaSMatt Jacob 	alpha_mb(),
224a185f9b1SMatt Jacob 	(st == IO_SPACE_MAPPING)? \
225a185f9b1SMatt Jacob 		inw((pci_port_t)sh + offset) : readw((pci_port_t)sh + offset)
22665adb54cSMatt Jacob #define	bus_space_write_2(st, sh, offset, val)	\
227d951bbcaSMatt Jacob 	((st == IO_SPACE_MAPPING)? outw((pci_port_t)sh + offset, val) : \
228d951bbcaSMatt Jacob                 writew((pci_port_t)sh + offset, val)), alpha_mb()
229a185f9b1SMatt Jacob #else
230a185f9b1SMatt Jacob #define	bus_space_read_2(st, sh, offset)	\
231a185f9b1SMatt Jacob 	(st == IO_SPACE_MAPPING)? \
232a185f9b1SMatt Jacob 		inw((pci_port_t)sh + offset) : *((u_int16_t *)(uintptr_t)sh)
233a185f9b1SMatt Jacob #define	bus_space_write_2(st, sh, offset, val)	\
234a185f9b1SMatt Jacob 	if (st == IO_SPACE_MAPPING) outw((pci_port_t)sh + offset, val); else \
235b97fc948SBruce Evans 		*((u_int16_t *)(uintptr_t)sh) = val
236d720e6d5SJustin T. Gibbs #endif
237a185f9b1SMatt Jacob #else
238a185f9b1SMatt Jacob #ifdef __alpha__
239a185f9b1SMatt Jacob #define IO_SPACE_MAPPING	ALPHA_BUS_SPACE_IO
240a185f9b1SMatt Jacob #define MEM_SPACE_MAPPING	ALPHA_BUS_SPACE_MEM
241a185f9b1SMatt Jacob #else
242a185f9b1SMatt Jacob #define IO_SPACE_MAPPING	I386_BUS_SPACE_IO
243a185f9b1SMatt Jacob #define MEM_SPACE_MAPPING	I386_BUS_SPACE_MEM
244a185f9b1SMatt Jacob #endif
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];
2533dd37e43SMatt Jacob #if	__FreeBSD_version >= 300004
254d720e6d5SJustin T. Gibbs 	bus_dma_tag_t			parent_dmat;
255d720e6d5SJustin T. Gibbs 	bus_dma_tag_t			cntrol_dmat;
256d720e6d5SJustin T. Gibbs 	bus_dmamap_t			cntrol_dmap;
257d720e6d5SJustin T. Gibbs 	bus_dmamap_t			dmaps[MAXISPREQUEST];
258d720e6d5SJustin T. Gibbs #endif
25965adb54cSMatt Jacob 	union {
26065adb54cSMatt Jacob 		sdparam	_x;
26192c49d78SMatt Jacob 		fcparam _y;
26265adb54cSMatt Jacob 	} _z;
26365adb54cSMatt Jacob };
26465adb54cSMatt Jacob 
265d720e6d5SJustin T. Gibbs static u_long ispunit;
26665adb54cSMatt Jacob 
26766235db5SEivind Eklund static struct pci_device isp_pci_driver = {
26865adb54cSMatt Jacob 	"isp",
26965adb54cSMatt Jacob 	isp_pci_probe,
27065adb54cSMatt Jacob 	isp_pci_attach,
271d720e6d5SJustin T. Gibbs 	&ispunit,
27265adb54cSMatt Jacob 	NULL
27365adb54cSMatt Jacob };
27496b3554eSPeter Wemm #ifdef COMPAT_PCI_DRIVER
27596b3554eSPeter Wemm COMPAT_PCI_DRIVER (isp_pci, isp_pci_driver);
27696b3554eSPeter Wemm #else
27765adb54cSMatt Jacob DATA_SET (pcidevice_set, isp_pci_driver);
27896b3554eSPeter Wemm #endif /* COMPAT_PCI_DRIVER */
27965adb54cSMatt Jacob 
28065adb54cSMatt Jacob 
281ab6d0040SMatt Jacob static PROBETYPE
28217e318c6SMatt Jacob isp_pci_probe(pcici_t tag, pcidi_t type)
28365adb54cSMatt Jacob {
28465adb54cSMatt Jacob 	static int oneshot = 1;
28565adb54cSMatt Jacob 	char *x;
28665adb54cSMatt Jacob 
28765adb54cSMatt Jacob         switch (type) {
288d59bd469SMatt Jacob #ifndef	ISP_DISABLE_1020_SUPPORT
28965adb54cSMatt Jacob 	case PCI_QLOGIC_ISP:
290d59bd469SMatt Jacob 		x = "Qlogic ISP 1020/1040 PCI SCSI Adapter";
29165adb54cSMatt Jacob 		break;
292d59bd469SMatt Jacob #endif
293d59bd469SMatt Jacob #ifndef	ISP_DISABLE_1080_SUPPORT
294d59bd469SMatt Jacob 	case PCI_QLOGIC_ISP1080:
295d59bd469SMatt Jacob #if	0
296d59bd469SMatt Jacob 	case PCI_QLOGIC_ISP1240:	/* 1240 not ready yet */
29792c49d78SMatt Jacob #endif
298d59bd469SMatt Jacob 		x = "Qlogic ISP 1080/1240 PCI SCSI Adapter";
299d59bd469SMatt Jacob 		break;
300d59bd469SMatt Jacob #endif
301d59bd469SMatt Jacob #ifndef	ISP_DISABLE_2100_SUPPORT
30265adb54cSMatt Jacob 	case PCI_QLOGIC_ISP2100:
30365adb54cSMatt Jacob 		x = "Qlogic ISP 2100 PCI FC-AL Adapter";
30465adb54cSMatt Jacob 		break;
305d59bd469SMatt Jacob #endif
30665adb54cSMatt Jacob 	default:
30765adb54cSMatt Jacob 		return (NULL);
30865adb54cSMatt Jacob 	}
30965adb54cSMatt Jacob 	if (oneshot) {
31065adb54cSMatt Jacob 		oneshot = 0;
311d720e6d5SJustin T. Gibbs 		printf("%s Version %d.%d, Core Version %d.%d\n", PVS,
312d720e6d5SJustin T. Gibbs 		    ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR,
313d720e6d5SJustin T. Gibbs 		    ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR);
31465adb54cSMatt Jacob 	}
31565adb54cSMatt Jacob 	return (x);
31665adb54cSMatt Jacob }
31765adb54cSMatt Jacob 
31865adb54cSMatt Jacob 
31965adb54cSMatt Jacob static void
32017e318c6SMatt Jacob isp_pci_attach(pcici_t config_id, int unit)
32165adb54cSMatt Jacob {
32265adb54cSMatt Jacob 	int mapped;
323a185f9b1SMatt Jacob 	pci_port_t io_port;
324ab6d0040SMatt Jacob 	u_int32_t data, linesz;
32565adb54cSMatt Jacob 	struct isp_pcisoftc *pcs;
32665adb54cSMatt Jacob 	struct ispsoftc *isp;
32765adb54cSMatt Jacob 	vm_offset_t vaddr, paddr;
32865adb54cSMatt Jacob 	ISP_LOCKVAL_DECL;
32965adb54cSMatt Jacob 
33065adb54cSMatt Jacob 
33165adb54cSMatt Jacob 	pcs = malloc(sizeof (struct isp_pcisoftc), M_DEVBUF, M_NOWAIT);
33265adb54cSMatt Jacob 	if (pcs == NULL) {
3339bffbcd4SBruce Evans 		printf("isp%d: cannot allocate softc\n", unit);
33465adb54cSMatt Jacob 		return;
33565adb54cSMatt Jacob 	}
33665adb54cSMatt Jacob 	bzero(pcs, sizeof (struct isp_pcisoftc));
33765adb54cSMatt Jacob 
33865adb54cSMatt Jacob 	vaddr = paddr = NULL;
33965adb54cSMatt Jacob 	mapped = 0;
340ab6d0040SMatt Jacob 	linesz = PCI_DFLT_LNSZ;
341d951bbcaSMatt Jacob 	/*
342d951bbcaSMatt Jacob 	 * Note that pci_conf_read is a 32 bit word aligned function.
343d951bbcaSMatt Jacob 	 */
344d951bbcaSMatt Jacob 	data = pci_conf_read(config_id, PCIR_COMMAND);
345d951bbcaSMatt Jacob #if	SCSI_ISP_PREFER_MEM_MAP == 1
346a185f9b1SMatt Jacob 	if (mapped == 0 && (data & PCI_COMMAND_MEM_ENABLE)) {
347a185f9b1SMatt Jacob 		if (pci_map_mem(config_id, MEM_MAP_REG, &vaddr, &paddr)) {
348a185f9b1SMatt Jacob 			pcs->pci_st = MEM_SPACE_MAPPING;
349a185f9b1SMatt Jacob 			pcs->pci_sh = vaddr;
35065adb54cSMatt Jacob 			mapped++;
35165adb54cSMatt Jacob 		}
35265adb54cSMatt Jacob 	}
353a185f9b1SMatt Jacob 	if (mapped == 0 && (data & PCI_COMMAND_IO_ENABLE)) {
354a185f9b1SMatt Jacob 		if (pci_map_port(config_id, PCI_MAP_REG_START, &io_port)) {
355a185f9b1SMatt Jacob 			pcs->pci_st = IO_SPACE_MAPPING;
356a185f9b1SMatt Jacob 			pcs->pci_sh = io_port;
35765adb54cSMatt Jacob 			mapped++;
35865adb54cSMatt Jacob 		}
35965adb54cSMatt Jacob 	}
360d951bbcaSMatt Jacob #else
361d951bbcaSMatt Jacob 	if (mapped == 0 && (data & PCI_COMMAND_IO_ENABLE)) {
362d951bbcaSMatt Jacob 		if (pci_map_port(config_id, PCI_MAP_REG_START, &io_port)) {
363d951bbcaSMatt Jacob 			pcs->pci_st = IO_SPACE_MAPPING;
364d951bbcaSMatt Jacob 			pcs->pci_sh = io_port;
365d951bbcaSMatt Jacob 			mapped++;
366d951bbcaSMatt Jacob 		}
367d951bbcaSMatt Jacob 	}
368d951bbcaSMatt Jacob 	if (mapped == 0 && (data & PCI_COMMAND_MEM_ENABLE)) {
369d951bbcaSMatt Jacob 		if (pci_map_mem(config_id, MEM_MAP_REG, &vaddr, &paddr)) {
370d951bbcaSMatt Jacob 			pcs->pci_st = MEM_SPACE_MAPPING;
371d951bbcaSMatt Jacob 			pcs->pci_sh = vaddr;
372d951bbcaSMatt Jacob 			mapped++;
373d951bbcaSMatt Jacob 		}
374d951bbcaSMatt Jacob 	}
375d951bbcaSMatt Jacob #endif
37665adb54cSMatt Jacob 	if (mapped == 0) {
3779bffbcd4SBruce Evans 		printf("isp%d: unable to map any ports!\n", unit);
37865adb54cSMatt Jacob 		free(pcs, M_DEVBUF);
37965adb54cSMatt Jacob 		return;
38065adb54cSMatt Jacob 	}
38165adb54cSMatt Jacob 	printf("isp%d: using %s space register mapping\n", unit,
382a185f9b1SMatt Jacob 	    pcs->pci_st == IO_SPACE_MAPPING? "I/O" : "Memory");
38365adb54cSMatt Jacob 
38465adb54cSMatt Jacob 	isp = &pcs->pci_isp;
3852fa86a2bSMatt Jacob #if	__FreeBSD_version >= 300006
3862127f260SArchie Cobbs 	(void) snprintf(isp->isp_name, sizeof (isp->isp_name), "isp%d", unit);
3872fa86a2bSMatt Jacob #else
3882fa86a2bSMatt Jacob 	(void) sprintf(isp->isp_name, "isp%d", unit);
3892fa86a2bSMatt Jacob #endif
39065adb54cSMatt Jacob 	isp->isp_osinfo.unit = unit;
39165adb54cSMatt Jacob 
39265adb54cSMatt Jacob 	data = pci_conf_read(config_id, PCI_ID_REG);
393d59bd469SMatt Jacob 	pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF;
394d59bd469SMatt Jacob 	pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF;
395d59bd469SMatt Jacob 	pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF;
396d59bd469SMatt Jacob 	pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF;
397d59bd469SMatt Jacob 	pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF;
398d59bd469SMatt Jacob #ifndef	ISP_DISABLE_1020_SUPPORT
39965adb54cSMatt Jacob 	if (data == PCI_QLOGIC_ISP) {
40065adb54cSMatt Jacob 		isp->isp_mdvec = &mdvec;
40165adb54cSMatt Jacob 		isp->isp_type = ISP_HA_SCSI_UNKNOWN;
40265adb54cSMatt Jacob 		isp->isp_param = &pcs->_z._x;
403d59bd469SMatt Jacob 	}
404d59bd469SMatt Jacob #endif
405d59bd469SMatt Jacob #ifndef	ISP_DISABLE_1080_SUPPORT
406d59bd469SMatt Jacob 	if (data == PCI_QLOGIC_ISP1080 || data == PCI_QLOGIC_ISP1240) {
407d59bd469SMatt Jacob 		isp->isp_mdvec = &mdvec_1080;
408d59bd469SMatt Jacob 		isp->isp_type = ISP_HA_SCSI_1080;
409d59bd469SMatt Jacob 		isp->isp_param = &pcs->_z._x;
410d59bd469SMatt Jacob 		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
411d59bd469SMatt Jacob 		    ISP1080_DMA_REGS_OFF;
412d59bd469SMatt Jacob 	}
413d59bd469SMatt Jacob #endif
414d59bd469SMatt Jacob #ifndef	ISP_DISABLE_2100_SUPPORT
415d59bd469SMatt Jacob 	if (data == PCI_QLOGIC_ISP2100) {
41665adb54cSMatt Jacob 		isp->isp_mdvec = &mdvec_2100;
41765adb54cSMatt Jacob 		isp->isp_type = ISP_HA_FC_2100;
41892c49d78SMatt Jacob 		isp->isp_param = &pcs->_z._y;
419d59bd469SMatt Jacob 		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
420d59bd469SMatt Jacob 		    PCI_MBOX_REGS2100_OFF;
421ab6d0040SMatt Jacob 
422ab6d0040SMatt Jacob 		data = pci_conf_read(config_id, PCI_CLASS_REG);
423ab6d0040SMatt Jacob 		if ((data & 0xff) < 3) {
424ab6d0040SMatt Jacob 			/*
425ab6d0040SMatt Jacob 			 * XXX: Need to get the actual revision
426ab6d0040SMatt Jacob 			 * XXX: number of the 2100 FB. At any rate,
427ab6d0040SMatt Jacob 			 * XXX: lower cache line size for early revision
428ab6d0040SMatt Jacob 			 * XXX; boards.
429ab6d0040SMatt Jacob 			 */
430ab6d0040SMatt Jacob 			linesz = 1;
431ab6d0040SMatt Jacob 		}
43265adb54cSMatt Jacob 	}
433d59bd469SMatt Jacob #endif
43465adb54cSMatt Jacob 
4353dd37e43SMatt Jacob #if	__FreeBSD_version >= 300004
436d951bbcaSMatt Jacob 	ISP_LOCK(isp);
437ab6d0040SMatt Jacob 
438d951bbcaSMatt Jacob 	/*
439d951bbcaSMatt Jacob 	 * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER
440d951bbcaSMatt Jacob 	 * are set.
441d951bbcaSMatt Jacob 	 */
442d951bbcaSMatt Jacob 	data = pci_cfgread(config_id, PCIR_COMMAND, 2);
443d951bbcaSMatt Jacob 	data |=	PCIM_CMD_SEREN		|
444d951bbcaSMatt Jacob 		PCIM_CMD_PERRESPEN	|
445d951bbcaSMatt Jacob 		PCIM_CMD_BUSMASTEREN	|
446d951bbcaSMatt Jacob 		PCIM_CMD_INVEN;
447d951bbcaSMatt Jacob 	pci_cfgwrite(config_id, PCIR_COMMAND, 2, data);
448ab6d0040SMatt Jacob 
449d951bbcaSMatt Jacob 	/*
450d951bbcaSMatt Jacob 	 * Make sure the CACHE Line Size register is set sensibly.
451d951bbcaSMatt Jacob 	 */
452d951bbcaSMatt Jacob 	data = pci_cfgread(config_id, PCIR_CACHELNSZ, 1);
453ab6d0040SMatt Jacob 	if (data != linesz) {
454d951bbcaSMatt Jacob 		data = PCI_DFLT_LNSZ;
455d951bbcaSMatt Jacob 		printf("%s: set PCI line size to %d\n", isp->isp_name, data);
456d951bbcaSMatt Jacob 		pci_cfgwrite(config_id, PCIR_CACHELNSZ, data, 1);
457d951bbcaSMatt Jacob 	}
458ab6d0040SMatt Jacob 
459d951bbcaSMatt Jacob 	/*
460d951bbcaSMatt Jacob 	 * Make sure the Latency Timer is sane.
461d951bbcaSMatt Jacob 	 */
462d951bbcaSMatt Jacob 	data = pci_cfgread(config_id, PCIR_LATTIMER, 1);
463d951bbcaSMatt Jacob 	if (data < PCI_DFLT_LTNCY) {
464d951bbcaSMatt Jacob 		data = PCI_DFLT_LTNCY;
465d951bbcaSMatt Jacob 		printf("%s: set PCI latency to %d\n", isp->isp_name, data);
466d951bbcaSMatt Jacob 		pci_cfgwrite(config_id, PCIR_LATTIMER, data, 1);
467d951bbcaSMatt Jacob 	}
468ab6d0040SMatt Jacob 
469ab6d0040SMatt Jacob 	/*
470ab6d0040SMatt Jacob 	 * Make sure we've disabled the ROM.
471ab6d0040SMatt Jacob 	 */
472ab6d0040SMatt Jacob 	data = pci_cfgread(config_id, PCIR_ROMADDR, 4);
473ab6d0040SMatt Jacob 	data &= ~1;
474ab6d0040SMatt Jacob 	pci_cfgwrite(config_id, PCIR_ROMADDR, data, 4);
475ab6d0040SMatt Jacob 
476d951bbcaSMatt Jacob 	ISP_UNLOCK(isp);
477d951bbcaSMatt Jacob 
478d720e6d5SJustin T. Gibbs 	if (bus_dma_tag_create(NULL, 0, 0, BUS_SPACE_MAXADDR_32BIT,
479d720e6d5SJustin T. Gibbs 	    BUS_SPACE_MAXADDR, NULL, NULL, 1<<24,
480d720e6d5SJustin T. Gibbs 	    255, 1<<24, 0, &pcs->parent_dmat) != 0) {
481d720e6d5SJustin T. Gibbs 		printf("%s: could not create master dma tag\n", isp->isp_name);
482d720e6d5SJustin T. Gibbs 		free(pcs, M_DEVBUF);
483d720e6d5SJustin T. Gibbs 		return;
484d720e6d5SJustin T. Gibbs 	}
485ab6d0040SMatt Jacob #else
486ab6d0040SMatt Jacob 	ISP_LOCK(isp);
487ab6d0040SMatt Jacob 	data = pci_conf_read(config_id, PCIR_COMMAND);
488ab6d0040SMatt Jacob 	data |=	PCIM_CMD_SEREN		|
489ab6d0040SMatt Jacob 		PCIM_CMD_PERRESPEN	|
490ab6d0040SMatt Jacob 		PCIM_CMD_BUSMASTEREN	|
491ab6d0040SMatt Jacob 		PCIM_CMD_INVEN;
492ab6d0040SMatt Jacob 	pci_conf_write(config_id, PCIR_COMMAND, data);
493ab6d0040SMatt Jacob 	data = pci_conf_read(config_id, PCIR_CACHELNSZ);
494ab6d0040SMatt Jacob 	if ((data & ~0xffff) != ((PCI_DFLT_LTNCY << 8) | linesz)) {
495ab6d0040SMatt Jacob 		data &= ~0xffff;
496ab6d0040SMatt Jacob 		data |= (PCI_DFLT_LTNCY << 8) | linesz;
497ab6d0040SMatt Jacob 		pci_conf_write(config_id, PCIR_CACHELNSZ, data);
498ab6d0040SMatt Jacob 		printf("%s: set PCI line size to %d\n", isp->isp_name, linesz);
499ab6d0040SMatt Jacob 		printf("%s: set PCI latency to %d\n", isp->isp_name,
500ab6d0040SMatt Jacob 		    PCI_DFLT_LTNCY);
501ab6d0040SMatt Jacob 	}
502d951bbcaSMatt Jacob 
503ab6d0040SMatt Jacob 	/*
504ab6d0040SMatt Jacob 	 * Make sure we've disabled the ROM.
505ab6d0040SMatt Jacob 	 */
506ab6d0040SMatt Jacob 	data = pci_conf_read(config_id, PCIR_ROMADDR);
507ab6d0040SMatt Jacob 	data &= ~1;
508ab6d0040SMatt Jacob 	pci_conf_write(config_id, PCIR_ROMADDR, data);
509ab6d0040SMatt Jacob 	ISP_UNLOCK(isp);
510d720e6d5SJustin T. Gibbs #endif
51165adb54cSMatt Jacob 	if (pci_map_int(config_id, (void (*)(void *))isp_intr,
51265adb54cSMatt Jacob 	    (void *)isp, &IMASK) == 0) {
5139bffbcd4SBruce Evans 		printf("%s: could not map interrupt\n", isp->isp_name);
51465adb54cSMatt Jacob 		free(pcs, M_DEVBUF);
51565adb54cSMatt Jacob 		return;
51665adb54cSMatt Jacob 	}
51765adb54cSMatt Jacob 
51865adb54cSMatt Jacob 	pcs->pci_id = config_id;
519d951bbcaSMatt Jacob #ifdef	SCSI_ISP_NO_FWLOAD_MASK
520d951bbcaSMatt Jacob 	if (SCSI_ISP_NO_FWLOAD_MASK && (SCSI_ISP_NO_FWLOAD_MASK & (1 << unit)))
521d951bbcaSMatt Jacob 		isp->isp_confopts |= ISP_CFG_NORELOAD;
522d951bbcaSMatt Jacob #endif
523d951bbcaSMatt Jacob #ifdef	SCSI_ISP_NO_NVRAM_MASK
524ab6d0040SMatt Jacob 	if (SCSI_ISP_NO_NVRAM_MASK && (SCSI_ISP_NO_NVRAM_MASK & (1 << unit))) {
525ab6d0040SMatt Jacob 		printf("%s: ignoring NVRAM\n", isp->isp_name);
526d951bbcaSMatt Jacob 		isp->isp_confopts |= ISP_CFG_NONVRAM;
527ab6d0040SMatt Jacob 	}
528d951bbcaSMatt Jacob #endif
529d720e6d5SJustin T. Gibbs 	ISP_LOCK(isp);
53065adb54cSMatt Jacob 	isp_reset(isp);
53165adb54cSMatt Jacob 	if (isp->isp_state != ISP_RESETSTATE) {
532d720e6d5SJustin T. Gibbs 		ISP_UNLOCK(isp);
53365adb54cSMatt Jacob 		free(pcs, M_DEVBUF);
53465adb54cSMatt Jacob 		return;
53565adb54cSMatt Jacob 	}
53665adb54cSMatt Jacob 	isp_init(isp);
53765adb54cSMatt Jacob 	if (isp->isp_state != ISP_INITSTATE) {
538d59bd469SMatt Jacob 		/* If we're a Fibre Channel Card, we allow deferred attach */
539d59bd469SMatt Jacob 		if (isp->isp_type & ISP_HA_SCSI) {
54065adb54cSMatt Jacob 			isp_uninit(isp);
54165adb54cSMatt Jacob 			free(pcs, M_DEVBUF);
542d59bd469SMatt Jacob 		}
54365adb54cSMatt Jacob 	}
54465adb54cSMatt Jacob 	isp_attach(isp);
54565adb54cSMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE) {
546d59bd469SMatt Jacob 		/* If we're a Fibre Channel Card, we allow deferred attach */
54792c49d78SMatt Jacob 		if (IS_SCSI(isp)) {
54865adb54cSMatt Jacob 			isp_uninit(isp);
54965adb54cSMatt Jacob 			free(pcs, M_DEVBUF);
55065adb54cSMatt Jacob 		}
551d59bd469SMatt Jacob 	}
552d720e6d5SJustin T. Gibbs 	ISP_UNLOCK(isp);
553e37c0455SDoug Rabson #ifdef __alpha__
554d951bbcaSMatt Jacob 	/*
555d951bbcaSMatt Jacob 	 * THIS SHOULD NOT HAVE TO BE HERE
556d951bbcaSMatt Jacob 	 */
557e37c0455SDoug Rabson 	alpha_register_pci_scsi(config_id->bus, config_id->slot, isp->isp_sim);
558e37c0455SDoug Rabson #endif
55965adb54cSMatt Jacob }
56065adb54cSMatt Jacob 
56165adb54cSMatt Jacob static u_int16_t
562d59bd469SMatt Jacob isp_pci_rd_reg(isp, regoff)
563d59bd469SMatt Jacob 	struct ispsoftc *isp;
564d59bd469SMatt Jacob 	int regoff;
56565adb54cSMatt Jacob {
56665adb54cSMatt Jacob 	u_int16_t rv;
56765adb54cSMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
568d59bd469SMatt Jacob 	int offset, oldconf = 0;
56965adb54cSMatt Jacob 
570d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
57165adb54cSMatt Jacob 		/*
57265adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
57365adb54cSMatt Jacob 		 */
574d59bd469SMatt Jacob 		oldconf = isp_pci_rd_reg(isp, BIU_CONF1);
575d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP);
57665adb54cSMatt Jacob 	}
577d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
578d59bd469SMatt Jacob 	offset += (regoff & 0xff);
57965adb54cSMatt Jacob 	rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset);
580d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
581d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf);
58265adb54cSMatt Jacob 	}
58365adb54cSMatt Jacob 	return (rv);
58465adb54cSMatt Jacob }
58565adb54cSMatt Jacob 
58665adb54cSMatt Jacob static void
587d59bd469SMatt Jacob isp_pci_wr_reg(isp, regoff, val)
588d59bd469SMatt Jacob 	struct ispsoftc *isp;
589d59bd469SMatt Jacob 	int regoff;
590d59bd469SMatt Jacob 	u_int16_t val;
59165adb54cSMatt Jacob {
59265adb54cSMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
593d59bd469SMatt Jacob 	int offset, oldconf = 0;
594d59bd469SMatt Jacob 
595d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
59665adb54cSMatt Jacob 		/*
59765adb54cSMatt Jacob 		 * We will assume that someone has paused the RISC processor.
59865adb54cSMatt Jacob 		 */
599d59bd469SMatt Jacob 		oldconf = isp_pci_rd_reg(isp, BIU_CONF1);
600d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP);
60165adb54cSMatt Jacob 	}
602d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
603d59bd469SMatt Jacob 	offset += (regoff & 0xff);
60465adb54cSMatt Jacob 	bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val);
605d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
606d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oldconf);
60765adb54cSMatt Jacob 	}
60865adb54cSMatt Jacob }
60965adb54cSMatt Jacob 
610d59bd469SMatt Jacob #ifndef	ISP_DISABLE_1080_SUPPORT
611d59bd469SMatt Jacob static u_int16_t
612d59bd469SMatt Jacob isp_pci_rd_reg_1080(isp, regoff)
613d59bd469SMatt Jacob 	struct ispsoftc *isp;
614d59bd469SMatt Jacob 	int regoff;
615d59bd469SMatt Jacob {
616d59bd469SMatt Jacob 	u_int16_t rv;
617d59bd469SMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
618d59bd469SMatt Jacob 	int offset, oc = 0;
619d59bd469SMatt Jacob 
620d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
621d59bd469SMatt Jacob 		/*
622d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
623d59bd469SMatt Jacob 		 */
624d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
625d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_SXP);
626d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
627d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
628d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA);
629d59bd469SMatt Jacob 	}
630d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
631d59bd469SMatt Jacob 	offset += (regoff & 0xff);
632d59bd469SMatt Jacob 	rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset);
633d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
634d59bd469SMatt Jacob 	    ((regoff & _BLK_REG_MASK) == DMA_BLOCK)) {
635d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc);
636d59bd469SMatt Jacob 	}
637d59bd469SMatt Jacob 	return (rv);
638d59bd469SMatt Jacob }
639d59bd469SMatt Jacob 
640d59bd469SMatt Jacob static void
641d59bd469SMatt Jacob isp_pci_wr_reg_1080(isp, regoff, val)
642d59bd469SMatt Jacob 	struct ispsoftc *isp;
643d59bd469SMatt Jacob 	int regoff;
644d59bd469SMatt Jacob 	u_int16_t val;
645d59bd469SMatt Jacob {
646d59bd469SMatt Jacob 	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
647d59bd469SMatt Jacob 	int offset, oc = 0;
648d59bd469SMatt Jacob 
649d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
650d59bd469SMatt Jacob 		/*
651d59bd469SMatt Jacob 		 * We will assume that someone has paused the RISC processor.
652d59bd469SMatt Jacob 		 */
653d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
654d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_SXP);
655d59bd469SMatt Jacob 	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
656d59bd469SMatt Jacob 		oc = isp_pci_rd_reg(isp, BIU_CONF1);
657d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA);
658d59bd469SMatt Jacob 	}
659d59bd469SMatt Jacob 	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
660d59bd469SMatt Jacob 	offset += (regoff & 0xff);
661d59bd469SMatt Jacob 	bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val);
662d59bd469SMatt Jacob 	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
663d59bd469SMatt Jacob 	    ((regoff & _BLK_REG_MASK) == DMA_BLOCK)) {
664d59bd469SMatt Jacob 		isp_pci_wr_reg(isp, BIU_CONF1, oc);
665d59bd469SMatt Jacob 	}
666d59bd469SMatt Jacob }
667d59bd469SMatt Jacob #endif
668d59bd469SMatt Jacob 
669d59bd469SMatt Jacob 
6703dd37e43SMatt Jacob #if	__FreeBSD_version >= 300004
671d720e6d5SJustin T. Gibbs static void isp_map_rquest __P((void *, bus_dma_segment_t *, int, int));
672d720e6d5SJustin T. Gibbs static void isp_map_result __P((void *, bus_dma_segment_t *, int, int));
673d720e6d5SJustin T. Gibbs static void isp_map_fcscrt __P((void *, bus_dma_segment_t *, int, int));
674d720e6d5SJustin T. Gibbs 
675d720e6d5SJustin T. Gibbs static void
67617e318c6SMatt Jacob isp_map_rquest(void *arg, bus_dma_segment_t *segs, int nseg, int error)
677d720e6d5SJustin T. Gibbs {
678d720e6d5SJustin T. Gibbs 	struct ispsoftc *isp = (struct ispsoftc *) arg;
679d720e6d5SJustin T. Gibbs 	isp->isp_rquest_dma = segs->ds_addr;
680d720e6d5SJustin T. Gibbs }
681d720e6d5SJustin T. Gibbs 
682d720e6d5SJustin T. Gibbs static void
68317e318c6SMatt Jacob isp_map_result(void *arg, bus_dma_segment_t *segs, int nseg, int error)
684d720e6d5SJustin T. Gibbs {
685d720e6d5SJustin T. Gibbs 	struct ispsoftc *isp = (struct ispsoftc *) arg;
686d720e6d5SJustin T. Gibbs 	isp->isp_result_dma = segs->ds_addr;
687d720e6d5SJustin T. Gibbs }
688d720e6d5SJustin T. Gibbs 
689d720e6d5SJustin T. Gibbs static void
69017e318c6SMatt Jacob isp_map_fcscrt(void *arg, bus_dma_segment_t *segs, int nseg, int error)
691d720e6d5SJustin T. Gibbs {
692d720e6d5SJustin T. Gibbs 	struct ispsoftc *isp = (struct ispsoftc *) arg;
693d720e6d5SJustin T. Gibbs 	fcparam *fcp = isp->isp_param;
694d720e6d5SJustin T. Gibbs 	fcp->isp_scdma = segs->ds_addr;
695d720e6d5SJustin T. Gibbs }
696d720e6d5SJustin T. Gibbs 
697d720e6d5SJustin T. Gibbs static int
69817e318c6SMatt Jacob isp_pci_mbxdma(struct ispsoftc *isp)
699d720e6d5SJustin T. Gibbs {
700d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
701d720e6d5SJustin T. Gibbs 	caddr_t base;
702d720e6d5SJustin T. Gibbs 	u_int32_t len;
703d720e6d5SJustin T. Gibbs 	int i, error;
704d720e6d5SJustin T. Gibbs 
705d720e6d5SJustin T. Gibbs 	/*
706d720e6d5SJustin T. Gibbs 	 * Allocate and map the request, result queues, plus FC scratch area.
707d720e6d5SJustin T. Gibbs 	 */
708d720e6d5SJustin T. Gibbs 	len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN);
709d720e6d5SJustin T. Gibbs 	len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN);
710d720e6d5SJustin T. Gibbs 	if (isp->isp_type & ISP_HA_FC) {
711d720e6d5SJustin T. Gibbs 		len += ISP2100_SCRLEN;
712d720e6d5SJustin T. Gibbs 	}
713d720e6d5SJustin T. Gibbs 	if (bus_dma_tag_create(pci->parent_dmat, 0, 0, BUS_SPACE_MAXADDR,
714d720e6d5SJustin T. Gibbs 	    BUS_SPACE_MAXADDR, NULL, NULL, len, 1, BUS_SPACE_MAXSIZE_32BIT,
715d720e6d5SJustin T. Gibbs 	    0, &pci->cntrol_dmat) != 0) {
716d720e6d5SJustin T. Gibbs 		printf("%s: cannot create a dma tag for control spaces\n",
717d720e6d5SJustin T. Gibbs 		    isp->isp_name);
718d720e6d5SJustin T. Gibbs 		return (1);
719d720e6d5SJustin T. Gibbs 	}
720d720e6d5SJustin T. Gibbs 	if (bus_dmamem_alloc(pci->cntrol_dmat, (void **)&base,
721d720e6d5SJustin T. Gibbs 	    BUS_DMA_NOWAIT, &pci->cntrol_dmap) != 0) {
7224873663cSMatt Jacob 		printf("%s: cannot allocate %d bytes of CCB memory\n",
7234873663cSMatt Jacob 		    isp->isp_name, len);
724d720e6d5SJustin T. Gibbs 		return (1);
725d720e6d5SJustin T. Gibbs 	}
726d720e6d5SJustin T. Gibbs 
727d720e6d5SJustin T. Gibbs 	isp->isp_rquest = base;
728d720e6d5SJustin T. Gibbs 	bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_rquest,
729d720e6d5SJustin T. Gibbs 	    ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN), isp_map_rquest, pci, 0);
730d720e6d5SJustin T. Gibbs 
731d720e6d5SJustin T. Gibbs 	isp->isp_result = base + ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN);
732d720e6d5SJustin T. Gibbs 	bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_result,
733d720e6d5SJustin T. Gibbs 	    ISP_QUEUE_SIZE(RESULT_QUEUE_LEN), isp_map_result, pci, 0);
734d720e6d5SJustin T. Gibbs 
735d720e6d5SJustin T. Gibbs 	/*
736d720e6d5SJustin T. Gibbs 	 * Use this opportunity to initialize/create data DMA maps.
737d720e6d5SJustin T. Gibbs 	 */
738d720e6d5SJustin T. Gibbs 	for (i = 0; i < MAXISPREQUEST; i++) {
739d720e6d5SJustin T. Gibbs 		error = bus_dmamap_create(pci->parent_dmat, 0, &pci->dmaps[i]);
740d720e6d5SJustin T. Gibbs 		if (error) {
7414873663cSMatt Jacob 			printf("%s: error %d creating mailbox DMA maps\n",
742d720e6d5SJustin T. Gibbs 			    isp->isp_name, error);
743d720e6d5SJustin T. Gibbs 			return (1);
744d720e6d5SJustin T. Gibbs 		}
745d720e6d5SJustin T. Gibbs 	}
74692c49d78SMatt Jacob 
74792c49d78SMatt Jacob 	if (isp->isp_type & ISP_HA_FC) {
74892c49d78SMatt Jacob 		fcparam *fcp = (fcparam *) isp->isp_param;
74992c49d78SMatt Jacob 		fcp->isp_scratch = base +
75092c49d78SMatt Jacob 			ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN) +
75192c49d78SMatt Jacob 			ISP_QUEUE_SIZE(RESULT_QUEUE_LEN);
75292c49d78SMatt Jacob 		bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap,
75392c49d78SMatt Jacob 		    fcp->isp_scratch, ISP2100_SCRLEN, isp_map_fcscrt, pci, 0);
75492c49d78SMatt Jacob 	}
755d720e6d5SJustin T. Gibbs 	return (0);
756d720e6d5SJustin T. Gibbs }
757d720e6d5SJustin T. Gibbs 
758d720e6d5SJustin T. Gibbs static void dma2 __P((void *, bus_dma_segment_t *, int, int));
759d720e6d5SJustin T. Gibbs typedef struct {
760d720e6d5SJustin T. Gibbs 	struct ispsoftc *isp;
761d720e6d5SJustin T. Gibbs 	ISP_SCSI_XFER_T *ccb;
762d720e6d5SJustin T. Gibbs 	ispreq_t *rq;
763d720e6d5SJustin T. Gibbs 	u_int8_t *iptrp;
764d720e6d5SJustin T. Gibbs 	u_int8_t optr;
765d720e6d5SJustin T. Gibbs 	u_int error;
766d720e6d5SJustin T. Gibbs } mush_t;
767d720e6d5SJustin T. Gibbs 
7684873663cSMatt Jacob #define	MUSHERR_NOQENTRIES	-2
7694873663cSMatt Jacob 
770d720e6d5SJustin T. Gibbs static void
77117e318c6SMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
772d720e6d5SJustin T. Gibbs {
773d720e6d5SJustin T. Gibbs 	mush_t *mp;
774d720e6d5SJustin T. Gibbs 	ISP_SCSI_XFER_T *ccb;
775d720e6d5SJustin T. Gibbs 	struct ispsoftc *isp;
776d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci;
777d720e6d5SJustin T. Gibbs 	bus_dmamap_t *dp;
778d720e6d5SJustin T. Gibbs 	bus_dma_segment_t *eseg;
779d720e6d5SJustin T. Gibbs 	ispreq_t *rq;
780d720e6d5SJustin T. Gibbs 	u_int8_t *iptrp;
781d720e6d5SJustin T. Gibbs 	u_int8_t optr;
782d720e6d5SJustin T. Gibbs 	ispcontreq_t *crq;
783d720e6d5SJustin T. Gibbs 	int drq, seglim, datalen;
784d720e6d5SJustin T. Gibbs 
785d720e6d5SJustin T. Gibbs 	mp = (mush_t *) arg;
786d720e6d5SJustin T. Gibbs 	if (error) {
787d720e6d5SJustin T. Gibbs 		mp->error = error;
788d720e6d5SJustin T. Gibbs 		return;
789d720e6d5SJustin T. Gibbs 	}
790d720e6d5SJustin T. Gibbs 
791d720e6d5SJustin T. Gibbs 	isp = mp->isp;
792d720e6d5SJustin T. Gibbs 	if (nseg < 1) {
793d720e6d5SJustin T. Gibbs 		printf("%s: zero or negative segment count\n", isp->isp_name);
794d720e6d5SJustin T. Gibbs 		mp->error = EFAULT;
795d720e6d5SJustin T. Gibbs 		return;
796d720e6d5SJustin T. Gibbs 	}
797d720e6d5SJustin T. Gibbs 	ccb = mp->ccb;
798d720e6d5SJustin T. Gibbs 	rq = mp->rq;
799d720e6d5SJustin T. Gibbs 	iptrp = mp->iptrp;
800d720e6d5SJustin T. Gibbs 	optr = mp->optr;
801d720e6d5SJustin T. Gibbs 
802d720e6d5SJustin T. Gibbs 	pci = (struct isp_pcisoftc *)isp;
803d720e6d5SJustin T. Gibbs 	dp = &pci->dmaps[rq->req_handle - 1];
804d720e6d5SJustin T. Gibbs 	if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
805d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
806d720e6d5SJustin T. Gibbs 		drq = REQFLAG_DATA_IN;
807d720e6d5SJustin T. Gibbs 	} else {
808d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
809d720e6d5SJustin T. Gibbs 		drq = REQFLAG_DATA_OUT;
810d720e6d5SJustin T. Gibbs 	}
811d720e6d5SJustin T. Gibbs 
812d720e6d5SJustin T. Gibbs 	datalen = XS_XFRLEN(ccb);
813d720e6d5SJustin T. Gibbs 	if (isp->isp_type & ISP_HA_FC) {
814d720e6d5SJustin T. Gibbs 		seglim = ISP_RQDSEG_T2;
815d720e6d5SJustin T. Gibbs 		((ispreqt2_t *)rq)->req_totalcnt = datalen;
816d720e6d5SJustin T. Gibbs 		((ispreqt2_t *)rq)->req_flags |= drq;
817d720e6d5SJustin T. Gibbs 	} else {
818d720e6d5SJustin T. Gibbs 		seglim = ISP_RQDSEG;
819d720e6d5SJustin T. Gibbs 		rq->req_flags |= drq;
820d720e6d5SJustin T. Gibbs 	}
821d720e6d5SJustin T. Gibbs 
822d720e6d5SJustin T. Gibbs 	eseg = dm_segs + nseg;
823d720e6d5SJustin T. Gibbs 
824d720e6d5SJustin T. Gibbs 	while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) {
825d720e6d5SJustin T. Gibbs 		if (isp->isp_type & ISP_HA_FC) {
826d720e6d5SJustin T. Gibbs 			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
827d720e6d5SJustin T. Gibbs 			rq2->req_dataseg[rq2->req_seg_count].ds_base =
828d720e6d5SJustin T. Gibbs 			    dm_segs->ds_addr;
829d720e6d5SJustin T. Gibbs 			rq2->req_dataseg[rq2->req_seg_count].ds_count =
830d720e6d5SJustin T. Gibbs 			    dm_segs->ds_len;
831d720e6d5SJustin T. Gibbs 		} else {
832d720e6d5SJustin T. Gibbs 			rq->req_dataseg[rq->req_seg_count].ds_base =
833d720e6d5SJustin T. Gibbs 				dm_segs->ds_addr;
834d720e6d5SJustin T. Gibbs 			rq->req_dataseg[rq->req_seg_count].ds_count =
835d720e6d5SJustin T. Gibbs 				dm_segs->ds_len;
836d720e6d5SJustin T. Gibbs 		}
837d720e6d5SJustin T. Gibbs 		datalen -= dm_segs->ds_len;
838d720e6d5SJustin T. Gibbs #if	0
839d720e6d5SJustin T. Gibbs 		if (isp->isp_type & ISP_HA_FC) {
840d720e6d5SJustin T. Gibbs 			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
841d720e6d5SJustin T. Gibbs 			printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n",
842d720e6d5SJustin T. Gibbs 			    isp->isp_name, rq->req_seg_count,
843d720e6d5SJustin T. Gibbs 			    rq2->req_dataseg[rq2->req_seg_count].ds_count,
844d720e6d5SJustin T. Gibbs 			    rq2->req_dataseg[rq2->req_seg_count].ds_base);
845d720e6d5SJustin T. Gibbs 		} else {
846d720e6d5SJustin T. Gibbs 			printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n",
847d720e6d5SJustin T. Gibbs 			    isp->isp_name, rq->req_seg_count,
848d720e6d5SJustin T. Gibbs 			    rq->req_dataseg[rq->req_seg_count].ds_count,
849d720e6d5SJustin T. Gibbs 			    rq->req_dataseg[rq->req_seg_count].ds_base);
850d720e6d5SJustin T. Gibbs 		}
851d720e6d5SJustin T. Gibbs #endif
852d720e6d5SJustin T. Gibbs 		rq->req_seg_count++;
853d720e6d5SJustin T. Gibbs 		dm_segs++;
854d720e6d5SJustin T. Gibbs 	}
855d720e6d5SJustin T. Gibbs 
856d720e6d5SJustin T. Gibbs 	while (datalen > 0 && dm_segs != eseg) {
857d720e6d5SJustin T. Gibbs 		crq = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, *iptrp);
8584873663cSMatt Jacob 		*iptrp = ISP_NXT_QENTRY(*iptrp, RQUEST_QUEUE_LEN);
859d720e6d5SJustin T. Gibbs 		if (*iptrp == optr) {
8604873663cSMatt Jacob #if	0
8614873663cSMatt Jacob 			printf("%s: Request Queue Overflow++\n", isp->isp_name);
8624873663cSMatt Jacob #endif
8634873663cSMatt Jacob 			mp->error = MUSHERR_NOQENTRIES;
864d720e6d5SJustin T. Gibbs 			return;
865d720e6d5SJustin T. Gibbs 		}
866d720e6d5SJustin T. Gibbs 		rq->req_header.rqs_entry_count++;
867d720e6d5SJustin T. Gibbs 		bzero((void *)crq, sizeof (*crq));
868d720e6d5SJustin T. Gibbs 		crq->req_header.rqs_entry_count = 1;
869d720e6d5SJustin T. Gibbs 		crq->req_header.rqs_entry_type = RQSTYPE_DATASEG;
870d720e6d5SJustin T. Gibbs 
871d720e6d5SJustin T. Gibbs 		seglim = 0;
872d720e6d5SJustin T. Gibbs 		while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) {
873d720e6d5SJustin T. Gibbs 			crq->req_dataseg[seglim].ds_base =
874d720e6d5SJustin T. Gibbs 			    dm_segs->ds_addr;
875d720e6d5SJustin T. Gibbs 			crq->req_dataseg[seglim].ds_count =
876d720e6d5SJustin T. Gibbs 			    dm_segs->ds_len;
877d720e6d5SJustin T. Gibbs #if	0
878d720e6d5SJustin T. Gibbs 			printf("%s: seg%d[%d] cnt 0x%x paddr 0x%08x\n",
879d720e6d5SJustin T. Gibbs 			    isp->isp_name, rq->req_header.rqs_entry_count-1,
880d720e6d5SJustin T. Gibbs 			    seglim, crq->req_dataseg[seglim].ds_count,
881d720e6d5SJustin T. Gibbs 			    crq->req_dataseg[seglim].ds_base);
882d720e6d5SJustin T. Gibbs #endif
883d720e6d5SJustin T. Gibbs 			rq->req_seg_count++;
884d720e6d5SJustin T. Gibbs 			dm_segs++;
885d720e6d5SJustin T. Gibbs 			seglim++;
886d720e6d5SJustin T. Gibbs 			datalen -= dm_segs->ds_len;
887d720e6d5SJustin T. Gibbs 		}
888d720e6d5SJustin T. Gibbs 	}
889d720e6d5SJustin T. Gibbs }
890d720e6d5SJustin T. Gibbs 
891d720e6d5SJustin T. Gibbs static int
89217e318c6SMatt Jacob isp_pci_dmasetup(struct ispsoftc *isp, ISP_SCSI_XFER_T *ccb, ispreq_t *rq,
89317e318c6SMatt Jacob 	u_int8_t *iptrp, u_int8_t optr)
894d720e6d5SJustin T. Gibbs {
895d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
896d720e6d5SJustin T. Gibbs 	struct ccb_hdr *ccb_h;
897d720e6d5SJustin T. Gibbs 	struct ccb_scsiio *csio;
898d720e6d5SJustin T. Gibbs 	bus_dmamap_t *dp;
899d720e6d5SJustin T. Gibbs 	mush_t mush, *mp;
900d720e6d5SJustin T. Gibbs 
901d720e6d5SJustin T. Gibbs 	csio = (struct ccb_scsiio *) ccb;
902d720e6d5SJustin T. Gibbs 	ccb_h = &csio->ccb_h;
903d720e6d5SJustin T. Gibbs 
904d720e6d5SJustin T. Gibbs 	if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_NONE) {
905d720e6d5SJustin T. Gibbs 		rq->req_seg_count = 1;
9064873663cSMatt Jacob 		return (CMD_QUEUED);
907d720e6d5SJustin T. Gibbs 	}
908d720e6d5SJustin T. Gibbs 	dp = &pci->dmaps[rq->req_handle - 1];
909d720e6d5SJustin T. Gibbs 
910d720e6d5SJustin T. Gibbs 	/*
911d720e6d5SJustin T. Gibbs 	 * Do a virtual grapevine step to collect info for
9124873663cSMatt Jacob 	 * the callback dma allocation that we have to use...
913d720e6d5SJustin T. Gibbs 	 */
914d720e6d5SJustin T. Gibbs 	mp = &mush;
915d720e6d5SJustin T. Gibbs 	mp->isp = isp;
916d720e6d5SJustin T. Gibbs 	mp->ccb = ccb;
917d720e6d5SJustin T. Gibbs 	mp->rq = rq;
918d720e6d5SJustin T. Gibbs 	mp->iptrp = iptrp;
919d720e6d5SJustin T. Gibbs 	mp->optr = optr;
920d720e6d5SJustin T. Gibbs 	mp->error = 0;
921d720e6d5SJustin T. Gibbs 
922d720e6d5SJustin T. Gibbs 	if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) {
923d720e6d5SJustin T. Gibbs 		if ((ccb_h->flags & CAM_DATA_PHYS) == 0) {
9244873663cSMatt Jacob 			int error, s;
9254873663cSMatt Jacob 
926d720e6d5SJustin T. Gibbs 			s = splsoftvm();
927d720e6d5SJustin T. Gibbs 			error = bus_dmamap_load(pci->parent_dmat, *dp,
928d720e6d5SJustin T. Gibbs 			    csio->data_ptr, csio->dxfer_len, dma2, mp, 0);
929d720e6d5SJustin T. Gibbs 			if (error == EINPROGRESS) {
930d720e6d5SJustin T. Gibbs 				bus_dmamap_unload(pci->parent_dmat, *dp);
931d720e6d5SJustin T. Gibbs 				mp->error = EINVAL;
9324873663cSMatt Jacob 				printf("%s: deferred dma allocation not "
9334873663cSMatt Jacob 				    "supported\n", isp->isp_name);
934d720e6d5SJustin T. Gibbs 			} else if (error && mp->error == 0) {
935d720e6d5SJustin T. Gibbs 				mp->error = error;
936d720e6d5SJustin T. Gibbs 			}
9374873663cSMatt Jacob 			splx(s);
938d720e6d5SJustin T. Gibbs 		} else {
939d720e6d5SJustin T. Gibbs 			/* Pointer to physical buffer */
940d720e6d5SJustin T. Gibbs 			struct bus_dma_segment seg;
941d720e6d5SJustin T. Gibbs 			seg.ds_addr = (bus_addr_t)csio->data_ptr;
942d720e6d5SJustin T. Gibbs 			seg.ds_len = csio->dxfer_len;
943d720e6d5SJustin T. Gibbs 			dma2(mp, &seg, 1, 0);
944d720e6d5SJustin T. Gibbs 		}
945d720e6d5SJustin T. Gibbs 	} else {
946d720e6d5SJustin T. Gibbs 		struct bus_dma_segment *segs;
947d720e6d5SJustin T. Gibbs 
948d720e6d5SJustin T. Gibbs 		if ((ccb_h->flags & CAM_DATA_PHYS) != 0) {
949d720e6d5SJustin T. Gibbs 			printf("%s: Physical segment pointers unsupported",
950d720e6d5SJustin T. Gibbs 				isp->isp_name);
951d720e6d5SJustin T. Gibbs 			mp->error = EINVAL;
952d720e6d5SJustin T. Gibbs 		} else if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0) {
953d720e6d5SJustin T. Gibbs 			printf("%s: Virtual segment addresses unsupported",
954d720e6d5SJustin T. Gibbs 				isp->isp_name);
955d720e6d5SJustin T. Gibbs 			mp->error = EINVAL;
956d720e6d5SJustin T. Gibbs 		} else {
957d720e6d5SJustin T. Gibbs 			/* Just use the segments provided */
958d720e6d5SJustin T. Gibbs 			segs = (struct bus_dma_segment *) csio->data_ptr;
959d720e6d5SJustin T. Gibbs 			dma2(mp, segs, csio->sglist_cnt, 0);
960d720e6d5SJustin T. Gibbs 		}
961d720e6d5SJustin T. Gibbs 	}
962d720e6d5SJustin T. Gibbs 	if (mp->error) {
9634873663cSMatt Jacob 		int retval = CMD_COMPLETE;
9644873663cSMatt Jacob 		if (mp->error == MUSHERR_NOQENTRIES) {
9654873663cSMatt Jacob 			retval = CMD_EAGAIN;
9664873663cSMatt Jacob 			ccb_h->status = CAM_UNREC_HBA_ERROR;
9674873663cSMatt Jacob 		} else if (mp->error == EFBIG) {
968d720e6d5SJustin T. Gibbs 			ccb_h->status = CAM_REQ_TOO_BIG;
969d720e6d5SJustin T. Gibbs 		} else if (mp->error == EINVAL) {
970d720e6d5SJustin T. Gibbs 			ccb_h->status = CAM_REQ_INVALID;
971d720e6d5SJustin T. Gibbs 		} else {
972d720e6d5SJustin T. Gibbs 			ccb_h->status = CAM_UNREC_HBA_ERROR;
973d720e6d5SJustin T. Gibbs 		}
9744873663cSMatt Jacob 		return (retval);
9754873663cSMatt Jacob 	} else {
9764873663cSMatt Jacob 		return (CMD_QUEUED);
977d720e6d5SJustin T. Gibbs 	}
978d720e6d5SJustin T. Gibbs }
979d720e6d5SJustin T. Gibbs 
980d720e6d5SJustin T. Gibbs static void
98117e318c6SMatt Jacob isp_pci_dmateardown(struct ispsoftc *isp, ISP_SCSI_XFER_T *ccb,
98217e318c6SMatt Jacob 	u_int32_t handle)
983d720e6d5SJustin T. Gibbs {
984d720e6d5SJustin T. Gibbs 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
985d720e6d5SJustin T. Gibbs 	bus_dmamap_t *dp = &pci->dmaps[handle];
986d720e6d5SJustin T. Gibbs 
987d720e6d5SJustin T. Gibbs 	if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
988d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTREAD);
989d720e6d5SJustin T. Gibbs 	} else {
990d720e6d5SJustin T. Gibbs 		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTWRITE);
991d720e6d5SJustin T. Gibbs 	}
992d720e6d5SJustin T. Gibbs 	bus_dmamap_unload(pci->parent_dmat, *dp);
993d720e6d5SJustin T. Gibbs }
994d720e6d5SJustin T. Gibbs 
9953dd37e43SMatt Jacob #else	/* __FreeBSD_version >= 300004 */
9963dd37e43SMatt Jacob 
997d720e6d5SJustin T. Gibbs 
99865adb54cSMatt Jacob static int
99917e318c6SMatt Jacob isp_pci_mbxdma(struct ispsoftc *isp)
100065adb54cSMatt Jacob {
100165adb54cSMatt Jacob 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
100265adb54cSMatt Jacob 	u_int32_t len;
100365adb54cSMatt Jacob 	int rseg;
100465adb54cSMatt Jacob 
100565adb54cSMatt Jacob 	/* XXXX CHECK FOR ALIGNMENT */
100665adb54cSMatt Jacob 	/*
100765adb54cSMatt Jacob 	 * Allocate and map the request queue.
100865adb54cSMatt Jacob 	 */
1009d720e6d5SJustin T. Gibbs 	len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN);
101065adb54cSMatt Jacob 	isp->isp_rquest = malloc(len, M_DEVBUF, M_NOWAIT);
101165adb54cSMatt Jacob 	if (isp->isp_rquest == NULL) {
101265adb54cSMatt Jacob 		printf("%s: cannot malloc request queue\n", isp->isp_name);
101365adb54cSMatt Jacob 		return (1);
101465adb54cSMatt Jacob 	}
101565adb54cSMatt Jacob 	isp->isp_rquest_dma = vtophys(isp->isp_rquest);
101665adb54cSMatt Jacob 
101765adb54cSMatt Jacob #if	0
101865adb54cSMatt Jacob 	printf("RQUEST=0x%x (0x%x)...", isp->isp_rquest, isp->isp_rquest_dma);
101965adb54cSMatt Jacob #endif
102065adb54cSMatt Jacob 
102165adb54cSMatt Jacob 	/*
102265adb54cSMatt Jacob 	 * Allocate and map the result queue.
102365adb54cSMatt Jacob 	 */
1024d720e6d5SJustin T. Gibbs 	len = ISP_QUEUE_SIZE(RESULT_QUEUE_LEN);
102565adb54cSMatt Jacob 	isp->isp_result = malloc(len, M_DEVBUF, M_NOWAIT);
102665adb54cSMatt Jacob 	if (isp->isp_result == NULL) {
102765adb54cSMatt Jacob 		free(isp->isp_rquest, M_DEVBUF);
102865adb54cSMatt Jacob 		printf("%s: cannot malloc result queue\n", isp->isp_name);
102965adb54cSMatt Jacob 		return (1);
103065adb54cSMatt Jacob 	}
103165adb54cSMatt Jacob 	isp->isp_result_dma = vtophys(isp->isp_result);
103265adb54cSMatt Jacob #if	0
103365adb54cSMatt Jacob 	printf("RESULT=0x%x (0x%x)\n", isp->isp_result, isp->isp_result_dma);
103465adb54cSMatt Jacob #endif
103565adb54cSMatt Jacob 	if (isp->isp_type & ISP_HA_FC) {
103665adb54cSMatt Jacob 		fcparam *fcp = isp->isp_param;
103765adb54cSMatt Jacob 		len = ISP2100_SCRLEN;
1038ab6d0040SMatt Jacob 		fcp->isp_scratch = (volatile caddr_t)
1039ab6d0040SMatt Jacob 		    malloc(ISP2100_SCRLEN, M_DEVBUF, M_NOWAIT);
1040ab6d0040SMatt Jacob 		if (fcp->isp_scratch == NULL) {
1041ab6d0040SMatt Jacob 			printf("%s: cannot alloc scratch\n", isp->isp_name);
1042ab6d0040SMatt Jacob 			return (1);
1043ab6d0040SMatt Jacob 		}
104465adb54cSMatt Jacob 		fcp->isp_scdma = vtophys(fcp->isp_scratch);
104565adb54cSMatt Jacob 	}
104665adb54cSMatt Jacob 	return (0);
104765adb54cSMatt Jacob }
104865adb54cSMatt Jacob 
104965adb54cSMatt Jacob static int
105017e318c6SMatt Jacob isp_pci_dmasetup(struct ispsoftc *isp, ISP_SCSI_XFER_T *xs,
105117e318c6SMatt Jacob 	ispreq_t *rq, u_int8_t *iptrp, u_int8_t optr)
105265adb54cSMatt Jacob {
105365adb54cSMatt Jacob 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
105465adb54cSMatt Jacob 	ispcontreq_t *crq;
105565adb54cSMatt Jacob 	vm_offset_t vaddr;
105665adb54cSMatt Jacob 	int drq, seglim;
105765adb54cSMatt Jacob 	u_int32_t paddr, nextpaddr, datalen, size, *ctrp;
105865adb54cSMatt Jacob 
105965adb54cSMatt Jacob 	if (xs->datalen == 0) {
106065adb54cSMatt Jacob 		rq->req_seg_count = 1;
10614873663cSMatt Jacob 		return (CMD_QUEUED);
106265adb54cSMatt Jacob 	}
106365adb54cSMatt Jacob 
106465adb54cSMatt Jacob 	if (xs->flags & SCSI_DATA_IN) {
106565adb54cSMatt Jacob 		drq = REQFLAG_DATA_IN;
106665adb54cSMatt Jacob 	} else {
106765adb54cSMatt Jacob 		drq = REQFLAG_DATA_OUT;
106865adb54cSMatt Jacob 	}
106965adb54cSMatt Jacob 
107065adb54cSMatt Jacob 	if (isp->isp_type & ISP_HA_FC) {
107165adb54cSMatt Jacob 		seglim = ISP_RQDSEG_T2;
1072d720e6d5SJustin T. Gibbs 		((ispreqt2_t *)rq)->req_totalcnt = XS_XFRLEN(xs);
107365adb54cSMatt Jacob 		((ispreqt2_t *)rq)->req_flags |= drq;
107465adb54cSMatt Jacob 	} else {
107565adb54cSMatt Jacob 		seglim = ISP_RQDSEG;
107665adb54cSMatt Jacob 		rq->req_flags |= drq;
107765adb54cSMatt Jacob 	}
107865adb54cSMatt Jacob 
1079d720e6d5SJustin T. Gibbs 	datalen = XS_XFRLEN(xs);
108065adb54cSMatt Jacob 	vaddr = (vm_offset_t) xs->data;
108165adb54cSMatt Jacob 	paddr = vtophys(vaddr);
108265adb54cSMatt Jacob 
108365adb54cSMatt Jacob 	while (datalen != 0 && rq->req_seg_count < seglim) {
108465adb54cSMatt Jacob 		if (isp->isp_type & ISP_HA_FC) {
108565adb54cSMatt Jacob 			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
108665adb54cSMatt Jacob 			rq2->req_dataseg[rq2->req_seg_count].ds_base = paddr;
108765adb54cSMatt Jacob 			ctrp = &rq2->req_dataseg[rq2->req_seg_count].ds_count;
108865adb54cSMatt Jacob 		} else {
108965adb54cSMatt Jacob 			rq->req_dataseg[rq->req_seg_count].ds_base = paddr;
109065adb54cSMatt Jacob 			ctrp = &rq->req_dataseg[rq->req_seg_count].ds_count;
109165adb54cSMatt Jacob 		}
109265adb54cSMatt Jacob 		nextpaddr = paddr;
109365adb54cSMatt Jacob 		*(ctrp) = 0;
109465adb54cSMatt Jacob 
109565adb54cSMatt Jacob 		while (datalen != 0 && paddr == nextpaddr) {
109665adb54cSMatt Jacob 			nextpaddr = (paddr & (~PAGE_MASK)) + PAGE_SIZE;
109765adb54cSMatt Jacob 			size = nextpaddr - paddr;
109865adb54cSMatt Jacob 			if (size > datalen)
109965adb54cSMatt Jacob 				size = datalen;
110065adb54cSMatt Jacob 			*(ctrp) += size;
110165adb54cSMatt Jacob 			vaddr += size;
110265adb54cSMatt Jacob 			datalen -= size;
110365adb54cSMatt Jacob 			if (datalen != 0)
110465adb54cSMatt Jacob 				paddr = vtophys(vaddr);
110565adb54cSMatt Jacob 
110665adb54cSMatt Jacob 		}
110765adb54cSMatt Jacob #if	0
110865adb54cSMatt Jacob 		if (isp->isp_type & ISP_HA_FC) {
110965adb54cSMatt Jacob 			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
111065adb54cSMatt Jacob 			printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n",
111165adb54cSMatt Jacob 			    isp->isp_name, rq->req_seg_count,
111265adb54cSMatt Jacob 			    rq2->req_dataseg[rq2->req_seg_count].ds_count,
111365adb54cSMatt Jacob 			    rq2->req_dataseg[rq2->req_seg_count].ds_base);
111465adb54cSMatt Jacob 		} else {
111565adb54cSMatt Jacob 			printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n",
111665adb54cSMatt Jacob 			    isp->isp_name, rq->req_seg_count,
111765adb54cSMatt Jacob 			    rq->req_dataseg[rq->req_seg_count].ds_count,
111865adb54cSMatt Jacob 			    rq->req_dataseg[rq->req_seg_count].ds_base);
111965adb54cSMatt Jacob 		}
112065adb54cSMatt Jacob #endif
112165adb54cSMatt Jacob 		rq->req_seg_count++;
112265adb54cSMatt Jacob 	}
112365adb54cSMatt Jacob 
112465adb54cSMatt Jacob 
112565adb54cSMatt Jacob 
112665adb54cSMatt Jacob 	if (datalen == 0)
11274873663cSMatt Jacob 		return (CMD_QUEUED);
112865adb54cSMatt Jacob 
112965adb54cSMatt Jacob 	paddr = vtophys(vaddr);
113065adb54cSMatt Jacob 	while (datalen > 0) {
113165adb54cSMatt Jacob 		crq = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, *iptrp);
11324873663cSMatt Jacob 		*iptrp = ISP_NXT_QENTRY(*iptrp, RQUEST_QUEUE_LEN);
113365adb54cSMatt Jacob 		if (*iptrp == optr) {
113465adb54cSMatt Jacob 			printf("%s: Request Queue Overflow\n", isp->isp_name);
1135d720e6d5SJustin T. Gibbs 			XS_SETERR(xs, HBA_BOTCH);
11364873663cSMatt Jacob 			return (CMD_EAGAIN);
113765adb54cSMatt Jacob 		}
113865adb54cSMatt Jacob 		rq->req_header.rqs_entry_count++;
113965adb54cSMatt Jacob 		bzero((void *)crq, sizeof (*crq));
114065adb54cSMatt Jacob 		crq->req_header.rqs_entry_count = 1;
114165adb54cSMatt Jacob 		crq->req_header.rqs_entry_type = RQSTYPE_DATASEG;
114265adb54cSMatt Jacob 
114365adb54cSMatt Jacob 		for (seglim = 0; datalen != 0 && seglim < ISP_CDSEG; seglim++) {
114465adb54cSMatt Jacob 			crq->req_dataseg[seglim].ds_base = paddr;
114565adb54cSMatt Jacob 			ctrp = &crq->req_dataseg[seglim].ds_count;
114665adb54cSMatt Jacob 			*(ctrp) = 0;
114765adb54cSMatt Jacob 			nextpaddr = paddr;
114865adb54cSMatt Jacob 			while (datalen != 0 && paddr == nextpaddr) {
114965adb54cSMatt Jacob 				nextpaddr = (paddr & (~PAGE_MASK)) + PAGE_SIZE;
115065adb54cSMatt Jacob 				size = nextpaddr - paddr;
115165adb54cSMatt Jacob 				if (size > datalen)
115265adb54cSMatt Jacob 					size = datalen;
115365adb54cSMatt Jacob 				*(ctrp) += size;
115465adb54cSMatt Jacob 				vaddr += size;
115565adb54cSMatt Jacob 				datalen -= size;
115665adb54cSMatt Jacob 				if (datalen != 0)
115765adb54cSMatt Jacob 					paddr = vtophys(vaddr);
115865adb54cSMatt Jacob 			}
115965adb54cSMatt Jacob #if	0
116065adb54cSMatt Jacob 			printf("%s: seg%d[%d] cnt 0x%x paddr 0x%08x\n",
116165adb54cSMatt Jacob 			    isp->isp_name, rq->req_header.rqs_entry_count-1,
116265adb54cSMatt Jacob 			    seglim, crq->req_dataseg[seglim].ds_count,
116365adb54cSMatt Jacob 			    crq->req_dataseg[seglim].ds_base);
116465adb54cSMatt Jacob #endif
116565adb54cSMatt Jacob 			rq->req_seg_count++;
116665adb54cSMatt Jacob 		}
116765adb54cSMatt Jacob 	}
116865adb54cSMatt Jacob 
11694873663cSMatt Jacob 	return (CMD_QUEUED);
117065adb54cSMatt Jacob }
1171d720e6d5SJustin T. Gibbs #endif
117265adb54cSMatt Jacob 
117365adb54cSMatt Jacob static void
117417e318c6SMatt Jacob isp_pci_reset1(struct ispsoftc *isp)
117565adb54cSMatt Jacob {
117665adb54cSMatt Jacob 	/* Make sure the BIOS is disabled */
117765adb54cSMatt Jacob 	isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS);
117865adb54cSMatt Jacob }
117965adb54cSMatt Jacob 
118065adb54cSMatt Jacob static void
118117e318c6SMatt Jacob isp_pci_dumpregs(struct ispsoftc *isp)
118265adb54cSMatt Jacob {
118365adb54cSMatt Jacob 	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
11849bffbcd4SBruce Evans 	printf("%s: PCI Status Command/Status=%lx\n", pci->pci_isp.isp_name,
1185d951bbcaSMatt Jacob 	    pci_conf_read(pci->pci_id, PCIR_COMMAND));
118665adb54cSMatt Jacob }
1187