isp_pci.c revision 50477
1116742Ssam/* $FreeBSD: head/sys/dev/isp/isp_pci.c 50477 1999-08-28 01:08:13Z peter $ */
2116904Ssam/*
3186904Ssam * PCI specific probe and attach routines for Qlogic ISP SCSI adapters.
4116742Ssam * FreeBSD Version.
5116742Ssam *
6116742Ssam *---------------------------------------
7116742Ssam * Copyright (c) 1997, 1998, 1999 by Matthew Jacob
8116742Ssam * NASA/Ames Research Center
9116742Ssam * All rights reserved.
10116742Ssam *---------------------------------------
11116742Ssam *
12116742Ssam * Redistribution and use in source and binary forms, with or without
13116742Ssam * modification, are permitted provided that the following conditions
14116742Ssam * are met:
15116904Ssam * 1. Redistributions of source code must retain the above copyright
16116904Ssam *    notice immediately at the beginning of the file, without modification,
17116904Ssam *    this list of conditions, and the following disclaimer.
18116904Ssam * 2. Redistributions in binary form must reproduce the above copyright
19116904Ssam *    notice, this list of conditions and the following disclaimer in the
20116904Ssam *    documentation and/or other materials provided with the distribution.
21116904Ssam * 3. The name of the author may not be used to endorse or promote products
22116904Ssam *    derived from this software without specific prior written permission.
23116904Ssam *
24116904Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25116904Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26116742Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27116742Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
28116742Ssam * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29116742Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30116742Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31116742Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32116742Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33116742Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34138568Ssam * SUCH DAMAGE.
35138568Ssam */
36138568Ssam#include <dev/isp/isp_freebsd.h>
37116742Ssam#include <dev/isp/asm_pci.h>
38138568Ssam#include <sys/malloc.h>
39161146Ssam#include <vm/vm.h>
40138568Ssam#include <vm/pmap.h>
41138568Ssam#include <vm/vm_extern.h>
42170530Ssam
43170530Ssam
44170530Ssam#include <pci/pcireg.h>
45170530Ssam#include <pci/pcivar.h>
46170530Ssam
47170530Ssam#include <machine/bus_memio.h>
48170530Ssam#include <machine/bus_pio.h>
49170530Ssam#include <machine/bus.h>
50138568Ssam#include <machine/md_var.h>
51170530Ssam
52170530Ssam
53170530Ssamstatic u_int16_t isp_pci_rd_reg __P((struct ispsoftc *, int));
54170530Ssamstatic void isp_pci_wr_reg __P((struct ispsoftc *, int, u_int16_t));
55170530Ssam#ifndef ISP_DISABLE_1080_SUPPORT
56170530Ssamstatic u_int16_t isp_pci_rd_reg_1080 __P((struct ispsoftc *, int));
57170530Ssamstatic void isp_pci_wr_reg_1080 __P((struct ispsoftc *, int, u_int16_t));
58170530Ssam#endif
59170530Ssamstatic int isp_pci_mbxdma __P((struct ispsoftc *));
60170530Ssamstatic int isp_pci_dmasetup __P((struct ispsoftc *, ISP_SCSI_XFER_T *,
61170530Ssam	ispreq_t *, u_int8_t *, u_int8_t));
62170530Ssamstatic void
63173273Ssamisp_pci_dmateardown __P((struct ispsoftc *, ISP_SCSI_XFER_T *, u_int32_t));
64138568Ssam
65170530Ssamstatic void isp_pci_reset1 __P((struct ispsoftc *));
66170530Ssamstatic void isp_pci_dumpregs __P((struct ispsoftc *));
67193239Ssam
68170530Ssam#ifndef ISP_DISABLE_1020_SUPPORT
69170530Ssamstatic struct ispmdvec mdvec = {
70170530Ssam	isp_pci_rd_reg,
71170530Ssam	isp_pci_wr_reg,
72138568Ssam	isp_pci_mbxdma,
73170530Ssam	isp_pci_dmasetup,
74170530Ssam	isp_pci_dmateardown,
75138568Ssam	NULL,
76170530Ssam	isp_pci_reset1,
77138568Ssam	isp_pci_dumpregs,
78138568Ssam	ISP_RISC_CODE,
79170530Ssam	ISP_CODE_LENGTH,
80170530Ssam	ISP_CODE_ORG,
81170530Ssam	ISP_CODE_VERSION,
82170530Ssam	BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64,
83170530Ssam	0
84170530Ssam};
85170530Ssam#endif
86170530Ssam
87193239Ssam#ifndef ISP_DISABLE_1080_SUPPORT
88138568Ssamstatic struct ispmdvec mdvec_1080 = {
89138568Ssam	isp_pci_rd_reg_1080,
90138568Ssam	isp_pci_wr_reg_1080,
91138568Ssam	isp_pci_mbxdma,
92138568Ssam	isp_pci_dmasetup,
93121180Ssam	isp_pci_dmateardown,
94170530Ssam	NULL,
95170530Ssam	isp_pci_reset1,
96170530Ssam	isp_pci_dumpregs,
97170530Ssam	ISP1080_RISC_CODE,
98170530Ssam	ISP1080_CODE_LENGTH,
99170530Ssam	ISP1080_CODE_ORG,
100170530Ssam	ISP1080_CODE_VERSION,
101170530Ssam	BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64,
102170530Ssam	0
103170530Ssam};
104170530Ssam#endif
105170530Ssam
106193239Ssam#ifndef ISP_DISABLE_2100_SUPPORT
107170530Ssamstatic struct ispmdvec mdvec_2100 = {
108170530Ssam	isp_pci_rd_reg,
109170530Ssam	isp_pci_wr_reg,
110170530Ssam	isp_pci_mbxdma,
111170530Ssam	isp_pci_dmasetup,
112170530Ssam	isp_pci_dmateardown,
113170530Ssam	NULL,
114170530Ssam	isp_pci_reset1,
115170530Ssam	isp_pci_dumpregs,
116170530Ssam	ISP2100_RISC_CODE,
117170530Ssam	ISP2100_CODE_LENGTH,
118170530Ssam	ISP2100_CODE_ORG,
119170530Ssam	ISP2100_CODE_VERSION,
120170530Ssam	0,			/* Irrelevant to the 2100 */
121170530Ssam	0
122170530Ssam};
123170530Ssam#endif
124170530Ssam
125170530Ssam#ifndef	ISP_DISABLE_2200_SUPPORT
126170530Ssamstatic struct ispmdvec mdvec_2200 = {
127170530Ssam	isp_pci_rd_reg,
128170530Ssam	isp_pci_wr_reg,
129170530Ssam	isp_pci_mbxdma,
130170530Ssam	isp_pci_dmasetup,
131170530Ssam	isp_pci_dmateardown,
132170530Ssam	NULL,
133170530Ssam	isp_pci_reset1,
134170530Ssam	isp_pci_dumpregs,
135170530Ssam	ISP2200_RISC_CODE,
136170530Ssam	ISP2200_CODE_LENGTH,
137170530Ssam	ISP2100_CODE_ORG,
138170530Ssam	ISP2200_CODE_VERSION,
139170530Ssam	0,
140170530Ssam	0
141170530Ssam};
142170530Ssam#endif
143170530Ssam
144170530Ssam#ifndef	SCSI_ISP_PREFER_MEM_MAP
145170530Ssam#define	SCSI_ISP_PREFER_MEM_MAP	0
146170530Ssam#endif
147170530Ssam
148170530Ssam#ifndef	PCIM_CMD_INVEN
149170530Ssam#define	PCIM_CMD_INVEN			0x10
150170530Ssam#endif
151170530Ssam#ifndef	PCIM_CMD_BUSMASTEREN
152170530Ssam#define	PCIM_CMD_BUSMASTEREN		0x0004
153170530Ssam#endif
154170530Ssam#ifndef	PCIM_CMD_PERRESPEN
155170530Ssam#define	PCIM_CMD_PERRESPEN		0x0040
156170530Ssam#endif
157170530Ssam#ifndef	PCIM_CMD_SEREN
158170530Ssam#define	PCIM_CMD_SEREN			0x0100
159170530Ssam#endif
160170530Ssam
161170530Ssam#ifndef	PCIR_COMMAND
162170530Ssam#define	PCIR_COMMAND			0x04
163170530Ssam#endif
164170530Ssam
165170530Ssam#ifndef	PCIR_CACHELNSZ
166170530Ssam#define	PCIR_CACHELNSZ			0x0c
167170530Ssam#endif
168170530Ssam
169170530Ssam#ifndef	PCIR_LATTIMER
170170530Ssam#define	PCIR_LATTIMER			0x0d
171170530Ssam#endif
172170530Ssam
173170530Ssam#ifndef	PCIR_ROMADDR
174170530Ssam#define	PCIR_ROMADDR			0x30
175170530Ssam#endif
176170530Ssam
177170530Ssam#ifndef	PCI_VENDOR_QLOGIC
178170530Ssam#define	PCI_VENDOR_QLOGIC	0x1077
179170530Ssam#endif
180170530Ssam
181170530Ssam#ifndef	PCI_PRODUCT_QLOGIC_ISP1020
182170530Ssam#define	PCI_PRODUCT_QLOGIC_ISP1020	0x1020
183170530Ssam#endif
184170530Ssam
185170530Ssam#ifndef	PCI_PRODUCT_QLOGIC_ISP1080
186170530Ssam#define	PCI_PRODUCT_QLOGIC_ISP1080	0x1080
187170530Ssam#endif
188170530Ssam
189170530Ssam#ifndef	PCI_PRODUCT_QLOGIC_ISP1240
190170530Ssam#define	PCI_PRODUCT_QLOGIC_ISP1240	0x1240
191170530Ssam#endif
192173273Ssam
193170530Ssam#ifndef	PCI_PRODUCT_QLOGIC_ISP2100
194170530Ssam#define	PCI_PRODUCT_QLOGIC_ISP2100	0x2100
195170530Ssam#endif
196170530Ssam
197173273Ssam#ifndef	PCI_PRODUCT_QLOGIC_ISP2200
198173273Ssam#define	PCI_PRODUCT_QLOGIC_ISP2200	0x2200
199173273Ssam#endif
200173273Ssam
201178354Ssam#define	PCI_QLOGIC_ISP	((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC)
202178354Ssam
203173273Ssam#define	PCI_QLOGIC_ISP1080	\
204173273Ssam	((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC)
205173273Ssam
206173273Ssam#define	PCI_QLOGIC_ISP1240	\
207173273Ssam	((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC)
208173273Ssam
209173273Ssam#define	PCI_QLOGIC_ISP2100	\
210173273Ssam	((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC)
211173273Ssam
212182829Ssam#define	PCI_QLOGIC_ISP2200	\
213173273Ssam	((PCI_PRODUCT_QLOGIC_ISP2200 << 16) | PCI_VENDOR_QLOGIC)
214173273Ssam
215173273Ssam#define	IO_MAP_REG	0x10
216178354Ssam#define	MEM_MAP_REG	0x14
217178354Ssam
218178354Ssam#define	PCI_DFLT_LTNCY	0x40
219178354Ssam#define	PCI_DFLT_LNSZ	0x10
220178354Ssam
221186904Ssamstatic const char *isp_pci_probe __P((pcici_t tag, pcidi_t type));
222190579Ssamstatic void isp_pci_attach __P((pcici_t config_d, int unit));
223193239Ssam
224193239Ssam/* This distinguishing define is not right, but it does work */
225193239Ssam#ifdef __alpha__
226195618Srpaulo#define IO_SPACE_MAPPING	ALPHA_BUS_SPACE_IO
227195618Srpaulo#define MEM_SPACE_MAPPING	ALPHA_BUS_SPACE_MEM
228195618Srpaulo#else
229195618Srpaulo#define IO_SPACE_MAPPING	I386_BUS_SPACE_IO
230195618Srpaulo#define MEM_SPACE_MAPPING	I386_BUS_SPACE_MEM
231195618Srpaulo#endif
232195618Srpaulo
233195618Srpaulostruct isp_pcisoftc {
234195618Srpaulo	struct ispsoftc			pci_isp;
235195618Srpaulo        pcici_t				pci_id;
236195618Srpaulo	bus_space_tag_t			pci_st;
237195618Srpaulo	bus_space_handle_t		pci_sh;
238195784Srpaulo	int16_t				pci_poff[_NREG_BLKS];
239195784Srpaulo	bus_dma_tag_t			parent_dmat;
240195784Srpaulo	bus_dma_tag_t			cntrol_dmat;
241195784Srpaulo	bus_dmamap_t			cntrol_dmap;
242195757Ssam	bus_dmamap_t			dmaps[MAXISPREQUEST];
243195908Srpaulo};
244232244Sadrian
245234018Sadrianstatic u_long ispunit;
246234018Sadrian
247234018Sadrianstatic struct pci_device isp_pci_driver = {
248234018Sadrian	"isp",
249234018Sadrian	isp_pci_probe,
250121180Ssam	isp_pci_attach,
251121180Ssam	&ispunit,
252138568Ssam	NULL
253138568Ssam};
254138568SsamCOMPAT_PCI_DRIVER (isp_pci, isp_pci_driver);
255138568Ssam
256138568Ssam
257138568Ssamstatic const char *
258138568Ssamisp_pci_probe(pcici_t tag, pcidi_t type)
259138568Ssam{
260138568Ssam	static int oneshot = 1;
261138568Ssam	char *x;
262138568Ssam
263138568Ssam        switch (type) {
264138568Ssam#ifndef	ISP_DISABLE_1020_SUPPORT
265138568Ssam	case PCI_QLOGIC_ISP:
266138568Ssam		x = "Qlogic ISP 1020/1040 PCI SCSI Adapter";
267173273Ssam		break;
268138568Ssam#endif
269138568Ssam#ifndef	ISP_DISABLE_1080_SUPPORT
270170530Ssam	case PCI_QLOGIC_ISP1080:
271170530Ssam		x = "Qlogic ISP 1080 PCI SCSI Adapter";
272170530Ssam		break;
273170530Ssam	case PCI_QLOGIC_ISP1240:
274170530Ssam		x = "Qlogic ISP 1240 PCI SCSI Adapter";
275138568Ssam		break;
276138568Ssam#endif
277170530Ssam#ifndef	ISP_DISABLE_2100_SUPPORT
278170530Ssam	case PCI_QLOGIC_ISP2100:
279170530Ssam		x = "Qlogic ISP 2100 PCI FC-AL Adapter";
280170530Ssam		break;
281138568Ssam#endif
282138568Ssam#ifndef	ISP_DISABLE_2200_SUPPORT
283138568Ssam	case PCI_QLOGIC_ISP2200:
284138568Ssam		x = "Qlogic ISP 2200 PCI FC-AL Adapter";
285138568Ssam		break;
286138568Ssam#endif
287138568Ssam	default:
288170530Ssam		return (NULL);
289170530Ssam	}
290138568Ssam	if (oneshot) {
291138568Ssam		oneshot = 0;
292138568Ssam		printf("%s Version %d.%d, Core Version %d.%d\n", PVS,
293138568Ssam		    ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR,
294138568Ssam		    ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR);
295138568Ssam	}
296138568Ssam	return (x);
297138568Ssam}
298138568Ssam
299170530Ssamstatic void
300138568Ssamisp_pci_attach(pcici_t cfid, int unit)
301138568Ssam{
302138568Ssam	int mapped, prefer_mem_map, bitmap;
303138568Ssam	pci_port_t io_port;
304138568Ssam	u_int32_t data, linesz, psize, basetype;
305178354Ssam	struct isp_pcisoftc *pcs;
306170530Ssam	struct ispsoftc *isp;
307170530Ssam	vm_offset_t vaddr, paddr;
308170530Ssam	struct ispmdvec *mdvp;
309170530Ssam	bus_size_t lim;
310138568Ssam	ISP_LOCKVAL_DECL;
311138568Ssam
312138568Ssam	pcs = malloc(sizeof (struct isp_pcisoftc), M_DEVBUF, M_NOWAIT);
313138568Ssam	if (pcs == NULL) {
314138568Ssam		printf("isp%d: cannot allocate softc\n", unit);
315138568Ssam		return;
316138568Ssam	}
317138568Ssam	bzero(pcs, sizeof (struct isp_pcisoftc));
318138568Ssam
319138568Ssam	/*
320138568Ssam	 * Figure out if we're supposed to skip this one.
321149028Ssam	 */
322149028Ssam	if (getenv_int("isp_disable", &bitmap)) {
323178354Ssam		if (bitmap & (1 << unit)) {
324138568Ssam			printf("isp%d: not configuring\n", unit);
325138568Ssam			return;
326149028Ssam		}
327170530Ssam	}
328195561Ssam
329149028Ssam	/*
330138568Ssam	 * Figure out which we should try first - memory mapping or i/o mapping?
331195618Srpaulo	 */
332195618Srpaulo#if	SCSI_ISP_PREFER_MEM_MAP == 1
333195618Srpaulo	prefer_mem_map = 1;
334195618Srpaulo#else
335195618Srpaulo	prefer_mem_map = 0;
336195618Srpaulo#endif
337195618Srpaulo	bitmap = 0;
338195618Srpaulo	if (getenv_int("isp_mem_map", &bitmap)) {
339195618Srpaulo		if (bitmap & (1 << unit))
340195784Srpaulo			prefer_mem_map = 1;
341203556Srpaulo	}
342234894Smonthadar	bitmap = 0;
343234894Smonthadar	if (getenv_int("isp_io_map", &bitmap)) {
344234894Smonthadar		if (bitmap & (1 << unit))
345246501Smonthadar			prefer_mem_map = 0;
346203422Srpaulo	}
347203422Srpaulo
348203422Srpaulo	vaddr = paddr = NULL;
349195908Srpaulo	mapped = 0;
350195784Srpaulo	linesz = PCI_DFLT_LNSZ;
351195784Srpaulo	/*
352195784Srpaulo	 * Note that pci_conf_read is a 32 bit word aligned function.
353195784Srpaulo	 */
354195784Srpaulo	data = pci_conf_read(cfid, PCIR_COMMAND);
355195618Srpaulo	if (prefer_mem_map) {
356195618Srpaulo		if (data & PCI_COMMAND_MEM_ENABLE) {
357195618Srpaulo			if (pci_map_mem(cfid, MEM_MAP_REG, &vaddr, &paddr)) {
358195618Srpaulo				pcs->pci_st = MEM_SPACE_MAPPING;
359195618Srpaulo				pcs->pci_sh = vaddr;
360195618Srpaulo				mapped++;
361195618Srpaulo			}
362195618Srpaulo		}
363195618Srpaulo		if (mapped == 0 && (data & PCI_COMMAND_IO_ENABLE)) {
364195618Srpaulo			if (pci_map_port(cfid, PCI_MAP_REG_START, &io_port)) {
365195618Srpaulo				pcs->pci_st = IO_SPACE_MAPPING;
366195618Srpaulo				pcs->pci_sh = io_port;
367187801Ssam				mapped++;
368187801Ssam			}
369187801Ssam		}
370187801Ssam	} else {
371138568Ssam		if (data & PCI_COMMAND_IO_ENABLE) {
372138568Ssam			if (pci_map_port(cfid, PCI_MAP_REG_START, &io_port)) {
373187801Ssam				pcs->pci_st = IO_SPACE_MAPPING;
374138568Ssam				pcs->pci_sh = io_port;
375138568Ssam				mapped++;
376138568Ssam			}
377138568Ssam		}
378138568Ssam		if (mapped == 0 && (data & PCI_COMMAND_MEM_ENABLE)) {
379138568Ssam			if (pci_map_mem(cfid, MEM_MAP_REG, &vaddr, &paddr)) {
380138568Ssam				pcs->pci_st = MEM_SPACE_MAPPING;
381187801Ssam				pcs->pci_sh = vaddr;
382138568Ssam				mapped++;
383187801Ssam			}
384187801Ssam		}
385187801Ssam	}
386187801Ssam	if (mapped == 0) {
387187801Ssam		printf("isp%d: unable to map any ports!\n", unit);
388138568Ssam		free(pcs, M_DEVBUF);
389138568Ssam		return;
390138568Ssam	}
391138568Ssam	if (bootverbose)
392170530Ssam		printf("isp%d: using %s space register mapping\n", unit,
393170530Ssam		    pcs->pci_st == IO_SPACE_MAPPING? "I/O" : "Memory");
394170530Ssam
395138568Ssam	data = pci_conf_read(cfid, PCI_ID_REG);
396170530Ssam	pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF;
397170530Ssam	pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF;
398170530Ssam	pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF;
399170530Ssam	pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF;
400170530Ssam	pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF;
401138568Ssam	/*
402138568Ssam 	 * GCC!
403138568Ssam	 */
404138568Ssam	mdvp = &mdvec;
405138568Ssam	basetype = ISP_HA_SCSI_UNKNOWN;
406138568Ssam	psize = sizeof (sdparam);
407138568Ssam	lim = BUS_SPACE_MAXSIZE_32BIT;
408170530Ssam#ifndef	ISP_DISABLE_1020_SUPPORT
409170530Ssam	if (data == PCI_QLOGIC_ISP) {
410138568Ssam		mdvp = &mdvec;
411138568Ssam		basetype = ISP_HA_SCSI_UNKNOWN;
412138568Ssam		psize = sizeof (sdparam);
413138568Ssam		lim = BUS_SPACE_MAXSIZE_24BIT;
414138568Ssam	}
415138568Ssam#endif
416138568Ssam#ifndef	ISP_DISABLE_1080_SUPPORT
417138568Ssam	if (data == PCI_QLOGIC_ISP1080) {
418138568Ssam		mdvp = &mdvec_1080;
419178354Ssam		basetype = ISP_HA_SCSI_1080;
420170530Ssam		psize = sizeof (sdparam);
421170530Ssam		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
422170530Ssam		    ISP1080_DMA_REGS_OFF;
423173272Ssam	}
424194136Ssam	if (data == PCI_QLOGIC_ISP1240) {
425170530Ssam		mdvp = &mdvec_1080;
426161146Ssam		basetype = ISP_HA_SCSI_12X0;
427170530Ssam		psize = 2 * sizeof (sdparam);
428170530Ssam		pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
429170530Ssam		    ISP1080_DMA_REGS_OFF;
430170530Ssam	}
431170530Ssam#endif
432138568Ssam#ifndef	ISP_DISABLE_2100_SUPPORT
433170530Ssam	if (data == PCI_QLOGIC_ISP2100) {
434178354Ssam		mdvp = &mdvec_2100;
435170530Ssam		basetype = ISP_HA_FC_2100;
436170530Ssam		psize = sizeof (fcparam);
437170530Ssam		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
438172225Ssam		    PCI_MBOX_REGS2100_OFF;
439172225Ssam		data = pci_conf_read(cfid, PCI_CLASS_REG);
440172225Ssam		if ((data & 0xff) < 3) {
441170530Ssam			/*
442178354Ssam			 * XXX: Need to get the actual revision
443194136Ssam			 * XXX: number of the 2100 FB. At any rate,
444178354Ssam			 * XXX: lower cache line size for early revision
445178354Ssam			 * XXX; boards.
446195618Srpaulo			 */
447195618Srpaulo			linesz = 1;
448195618Srpaulo		}
449195618Srpaulo	}
450138568Ssam#endif
451138568Ssam#ifndef	ISP_DISABLE_2200_SUPPORT
452138568Ssam	if (data == PCI_QLOGIC_ISP2200) {
453138568Ssam		mdvp = &mdvec_2200;
454138568Ssam		basetype = ISP_HA_FC_2200;
455138568Ssam		psize = sizeof (fcparam);
456138568Ssam		pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
457138568Ssam		    PCI_MBOX_REGS2100_OFF;
458138568Ssam	}
459138568Ssam#endif
460138568Ssam	isp = &pcs->pci_isp;
461170530Ssam	isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT);
462170530Ssam	if (isp->isp_param == NULL) {
463138568Ssam		printf("isp%d: cannot allocate parameter data\n", unit);
464138568Ssam		return;
465138568Ssam	}
466138568Ssam	bzero(isp->isp_param, psize);
467138568Ssam	isp->isp_mdvec = mdvp;
468138568Ssam	isp->isp_type = basetype;
469138568Ssam	(void) snprintf(isp->isp_name, sizeof (isp->isp_name), "isp%d", unit);
470138568Ssam	isp->isp_osinfo.unit = unit;
471170530Ssam
472170530Ssam	ISP_LOCK(isp);
473138568Ssam
474138568Ssam	/*
475138568Ssam	 * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER
476178354Ssam	 * are set.
477178354Ssam	 */
478178354Ssam	data = pci_cfgread(cfid, PCIR_COMMAND, 2);
479178354Ssam	data |=	PCIM_CMD_SEREN		|
480178354Ssam		PCIM_CMD_PERRESPEN	|
481178354Ssam		PCIM_CMD_BUSMASTEREN	|
482138568Ssam		PCIM_CMD_INVEN;
483138568Ssam	pci_cfgwrite(cfid, PCIR_COMMAND, 2, data);
484138568Ssam
485138568Ssam	/*
486138568Ssam	 * Make sure the Cache Line Size register is set sensibly.
487178354Ssam	 */
488178354Ssam	data = pci_cfgread(cfid, PCIR_CACHELNSZ, 1);
489178354Ssam	if (data != linesz) {
490178354Ssam		data = PCI_DFLT_LNSZ;
491178354Ssam		printf("%s: set PCI line size to %d\n", isp->isp_name, data);
492178354Ssam		pci_cfgwrite(cfid, PCIR_CACHELNSZ, data, 1);
493178354Ssam	}
494178354Ssam
495178354Ssam	/*
496178354Ssam	 * Make sure the Latency Timer is sane.
497178354Ssam	 */
498178354Ssam	data = pci_cfgread(cfid, PCIR_LATTIMER, 1);
499178354Ssam	if (data < PCI_DFLT_LTNCY) {
500178354Ssam		data = PCI_DFLT_LTNCY;
501178354Ssam		printf("%s: set PCI latency to %d\n", isp->isp_name, data);
502178354Ssam		pci_cfgwrite(cfid, PCIR_LATTIMER, data, 1);
503178354Ssam	}
504178354Ssam
505178354Ssam	/*
506178354Ssam	 * Make sure we've disabled the ROM.
507178354Ssam	 */
508178354Ssam	data = pci_cfgread(cfid, PCIR_ROMADDR, 4);
509178354Ssam	data &= ~1;
510178354Ssam	pci_cfgwrite(cfid, PCIR_ROMADDR, data, 4);
511178354Ssam	ISP_UNLOCK(isp);
512178354Ssam
513178354Ssam	if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
514178354Ssam	    BUS_SPACE_MAXADDR, NULL, NULL, lim + 1,
515178354Ssam	    255, lim, 0, &pcs->parent_dmat) != 0) {
516178354Ssam		printf("%s: could not create master dma tag\n", isp->isp_name);
517178354Ssam		free(pcs, M_DEVBUF);
518178354Ssam		return;
519178354Ssam	}
520178354Ssam	if (pci_map_int(cfid, (void (*)(void *))isp_intr,
521178354Ssam	    (void *)isp, &IMASK) == 0) {
522178354Ssam		printf("%s: could not map interrupt\n", isp->isp_name);
523178354Ssam		free(pcs, M_DEVBUF);
524178354Ssam		return;
525178354Ssam	}
526178354Ssam
527178354Ssam	pcs->pci_id = cfid;
528178354Ssam#ifdef	SCSI_ISP_NO_FWLOAD_MASK
529178354Ssam	if (SCSI_ISP_NO_FWLOAD_MASK && (SCSI_ISP_NO_FWLOAD_MASK & (1 << unit)))
530178354Ssam		isp->isp_confopts |= ISP_CFG_NORELOAD;
531178354Ssam#endif
532178354Ssam	if (getenv_int("isp_no_fwload", &bitmap)) {
533178354Ssam		if (bitmap & (1 << unit))
534178354Ssam			isp->isp_confopts |= ISP_CFG_NORELOAD;
535178354Ssam	}
536178354Ssam	if (getenv_int("isp_fwload", &bitmap)) {
537178354Ssam		if (bitmap & (1 << unit))
538178354Ssam			isp->isp_confopts &= ~ISP_CFG_NORELOAD;
539178354Ssam	}
540178354Ssam
541187801Ssam#ifdef	SCSI_ISP_NO_NVRAM_MASK
542187801Ssam	if (SCSI_ISP_NO_NVRAM_MASK && (SCSI_ISP_NO_NVRAM_MASK & (1 << unit))) {
543187801Ssam		printf("%s: ignoring NVRAM\n", isp->isp_name);
544187801Ssam		isp->isp_confopts |= ISP_CFG_NONVRAM;
545187801Ssam	}
546178354Ssam#endif
547178354Ssam	if (getenv_int("isp_no_nvram", &bitmap)) {
548178354Ssam		if (bitmap & (1 << unit))
549178354Ssam			isp->isp_confopts |= ISP_CFG_NONVRAM;
550178354Ssam	}
551178354Ssam	if (getenv_int("isp_nvram", &bitmap)) {
552178354Ssam		if (bitmap & (1 << unit))
553178354Ssam			isp->isp_confopts &= ~ISP_CFG_NONVRAM;
554178354Ssam	}
555178354Ssam
556178354Ssam#ifdef	SCSI_ISP_FCDUPLEX
557178354Ssam	if (IS_FC(isp)) {
558187801Ssam		if (SCSI_ISP_FCDUPLEX && (SCSI_ISP_FCDUPLEX & (1 << unit))) {
559187801Ssam			isp->isp_confopts |= ISP_CFG_FULL_DUPLEX;
560187801Ssam		}
561187801Ssam	}
562187801Ssam#endif
563178354Ssam	if (getenv_int("isp_fcduplex", &bitmap)) {
564178354Ssam		if (bitmap & (1 << unit))
565178354Ssam			isp->isp_confopts |= ISP_CFG_FULL_DUPLEX;
566178354Ssam	}
567178354Ssam	if (getenv_int("isp_no_fcduplex", &bitmap)) {
568178354Ssam		if (bitmap & (1 << unit))
569178354Ssam			isp->isp_confopts &= ~ISP_CFG_FULL_DUPLEX;
570178354Ssam	}
571178354Ssam
572178354Ssam	if (getenv_int("isp_seed", &isp->isp_osinfo.seed)) {
573178354Ssam		isp->isp_osinfo.seed <<= 8;
574178354Ssam		isp->isp_osinfo.seed += (unit + 1);
575178354Ssam	} else {
576178354Ssam		/*
577178354Ssam		 * poor man's attempt at pseudo randomness.
578116742Ssam		 */
579116742Ssam		long i = (intptr_t) isp;
580116742Ssam
581116742Ssam		i >>= 5;
582116742Ssam		i &= 0x7;
583116742Ssam
584116742Ssam		/*
585170530Ssam		 * This isn't very random, but it's the best we can do for
586116742Ssam		 * the real edge case of cards that don't have WWNs.
587223145Skevlo		 */
588116742Ssam		isp->isp_osinfo.seed += ((int) cfid->bus) << 16;
589116742Ssam		isp->isp_osinfo.seed += ((int) cfid->slot) << 8;
590116742Ssam		isp->isp_osinfo.seed += ((int) cfid->func);
591116742Ssam		while (version[i])
592170530Ssam			isp->isp_osinfo.seed += (int) version[i++];
593116742Ssam		isp->isp_osinfo.seed <<= 8;
594116742Ssam		isp->isp_osinfo.seed += (unit + 1);
595116742Ssam	}
596116742Ssam
597116742Ssam	ISP_LOCK(isp);
598116742Ssam	isp_reset(isp);
599116742Ssam	if (isp->isp_state != ISP_RESETSTATE) {
600116742Ssam		(void) pci_unmap_int(cfid);
601116742Ssam		ISP_UNLOCK(isp);
602116742Ssam		free(pcs, M_DEVBUF);
603116742Ssam		return;
604116742Ssam	}
605116742Ssam	isp_init(isp);
606116742Ssam	if (isp->isp_state != ISP_INITSTATE) {
607116742Ssam		/* If we're a Fibre Channel Card, we allow deferred attach */
608116742Ssam		if (IS_SCSI(isp)) {
609116742Ssam			isp_uninit(isp);
610116742Ssam			(void) pci_unmap_int(cfid); /* Does nothing */
611116742Ssam			ISP_UNLOCK(isp);
612116742Ssam			free(pcs, M_DEVBUF);
613116742Ssam			return;
614116742Ssam		}
615120480Ssam	}
616127648Ssam	isp_attach(isp);
617127648Ssam	if (isp->isp_state != ISP_RUNSTATE) {
618127648Ssam		/* If we're a Fibre Channel Card, we allow deferred attach */
619127648Ssam		if (IS_SCSI(isp)) {
620138568Ssam			isp_uninit(isp);
621138568Ssam			(void) pci_unmap_int(cfid); /* Does nothing */
622138568Ssam			ISP_UNLOCK(isp);
623138568Ssam			free(pcs, M_DEVBUF);
624138568Ssam			return;
625138568Ssam		}
626138568Ssam	}
627138568Ssam	ISP_UNLOCK(isp);
628178354Ssam#ifdef __alpha__
629178354Ssam	/*
630154541Ssam	 * THIS SHOULD NOT HAVE TO BE HERE
631138568Ssam	 */
632138568Ssam	alpha_register_pci_scsi(cfid->bus, cfid->slot, isp->isp_sim);
633138568Ssam#endif
634138568Ssam}
635138568Ssam
636138568Ssamstatic u_int16_t
637178354Ssamisp_pci_rd_reg(isp, regoff)
638178354Ssam	struct ispsoftc *isp;
639138568Ssam	int regoff;
640138568Ssam{
641138568Ssam	u_int16_t rv;
642138568Ssam	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
643138568Ssam	int offset, oldconf = 0;
644138568Ssam
645161146Ssam	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
646138568Ssam		/*
647138568Ssam		 * We will assume that someone has paused the RISC processor.
648138568Ssam		 */
649138568Ssam		oldconf = isp_pci_rd_reg(isp, BIU_CONF1);
650138568Ssam		isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP);
651138568Ssam	}
652138568Ssam	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
653138568Ssam	offset += (regoff & 0xff);
654138568Ssam	rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset);
655138568Ssam	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
656147794Ssam		isp_pci_wr_reg(isp, BIU_CONF1, oldconf);
657170530Ssam	}
658170530Ssam	return (rv);
659170530Ssam}
660170530Ssam
661170530Ssamstatic void
662170530Ssamisp_pci_wr_reg(isp, regoff, val)
663178354Ssam	struct ispsoftc *isp;
664148292Ssam	int regoff;
665153421Ssam	u_int16_t val;
666154541Ssam{
667160686Ssam	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
668161146Ssam	int offset, oldconf = 0;
669170530Ssam
670170530Ssam	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
671170530Ssam		/*
672170530Ssam		 * We will assume that someone has paused the RISC processor.
673170530Ssam		 */
674170530Ssam		oldconf = isp_pci_rd_reg(isp, BIU_CONF1);
675170530Ssam		isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP);
676170530Ssam	}
677170530Ssam	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
678170530Ssam	offset += (regoff & 0xff);
679178354Ssam	bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val);
680170530Ssam	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
681178354Ssam		isp_pci_wr_reg(isp, BIU_CONF1, oldconf);
682172062Ssam	}
683178354Ssam}
684178354Ssam
685178354Ssam#ifndef	ISP_DISABLE_1080_SUPPORT
686178354Ssamstatic u_int16_t
687178354Ssamisp_pci_rd_reg_1080(isp, regoff)
688178354Ssam	struct ispsoftc *isp;
689178354Ssam	int regoff;
690173273Ssam{
691178354Ssam	u_int16_t rv;
692178354Ssam	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
693173273Ssam	int offset, oc = 0;
694178354Ssam
695178354Ssam	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
696178354Ssam		/*
697178354Ssam		 * We will assume that someone has paused the RISC processor.
698183255Ssam		 */
699183256Ssam		oc = isp_pci_rd_reg(isp, BIU_CONF1);
700193548Ssam		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_SXP);
701193548Ssam	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
702116742Ssam		oc = isp_pci_rd_reg(isp, BIU_CONF1);
703195618Srpaulo		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA);
704195618Srpaulo	}
705195618Srpaulo	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
706195618Srpaulo	offset += (regoff & 0xff);
707195618Srpaulo	rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset);
708195618Srpaulo	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
709195618Srpaulo	    ((regoff & _BLK_REG_MASK) == DMA_BLOCK)) {
710195618Srpaulo		isp_pci_wr_reg(isp, BIU_CONF1, oc);
711195618Srpaulo	}
712195618Srpaulo	return (rv);
713195618Srpaulo}
714234892Smonthadar
715195618Srpaulostatic void
716195618Srpauloisp_pci_wr_reg_1080(isp, regoff, val)
717195618Srpaulo	struct ispsoftc *isp;
718195618Srpaulo	int regoff;
719195618Srpaulo	u_int16_t val;
720186904Ssam{
721186904Ssam	struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
722186904Ssam	int offset, oc = 0;
723186904Ssam
724186904Ssam	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
725227331Sadrian		/*
726227331Sadrian		 * We will assume that someone has paused the RISC processor.
727227331Sadrian		 */
728227331Sadrian		oc = isp_pci_rd_reg(isp, BIU_CONF1);
729227331Sadrian		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_SXP);
730138568Ssam	} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
731178354Ssam		oc = isp_pci_rd_reg(isp, BIU_CONF1);
732178354Ssam		isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA);
733178354Ssam	}
734178354Ssam	offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
735178354Ssam	offset += (regoff & 0xff);
736178354Ssam	bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val);
737178354Ssam	if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
738178354Ssam	    ((regoff & _BLK_REG_MASK) == DMA_BLOCK)) {
739178354Ssam		isp_pci_wr_reg(isp, BIU_CONF1, oc);
740178354Ssam	}
741178354Ssam}
742178354Ssam#endif
743178354Ssam
744178354Ssam
745178354Ssamstatic void isp_map_rquest __P((void *, bus_dma_segment_t *, int, int));
746178354Ssamstatic void isp_map_result __P((void *, bus_dma_segment_t *, int, int));
747178354Ssamstatic void isp_map_fcscrt __P((void *, bus_dma_segment_t *, int, int));
748178354Ssam
749178354Ssamstruct imush {
750178354Ssam	struct ispsoftc *isp;
751178354Ssam	int error;
752178354Ssam};
753178354Ssam
754178354Ssamstatic void
755178354Ssamisp_map_rquest(void *arg, bus_dma_segment_t *segs, int nseg, int error)
756178354Ssam{
757178354Ssam	struct imush *imushp = (struct imush *) arg;
758178354Ssam	if (error) {
759178354Ssam		imushp->error = error;
760178354Ssam	} else {
761178354Ssam		imushp->isp->isp_rquest_dma = segs->ds_addr;
762178354Ssam	}
763178354Ssam}
764178354Ssam
765178354Ssamstatic void
766178354Ssamisp_map_result(void *arg, bus_dma_segment_t *segs, int nseg, int error)
767178354Ssam{
768178354Ssam	struct imush *imushp = (struct imush *) arg;
769178354Ssam	if (error) {
770178354Ssam		imushp->error = error;
771178354Ssam	} else {
772178354Ssam		imushp->isp->isp_result_dma = segs->ds_addr;
773178354Ssam	}
774178354Ssam}
775178354Ssam
776178354Ssamstatic void
777178354Ssamisp_map_fcscrt(void *arg, bus_dma_segment_t *segs, int nseg, int error)
778178354Ssam{
779178354Ssam	struct imush *imushp = (struct imush *) arg;
780178354Ssam	if (error) {
781178354Ssam		imushp->error = error;
782178354Ssam	} else {
783178354Ssam		fcparam *fcp = imushp->isp->isp_param;
784178354Ssam		fcp->isp_scdma = segs->ds_addr;
785178354Ssam	}
786178354Ssam}
787178354Ssam
788178354Ssamstatic int
789178354Ssamisp_pci_mbxdma(struct ispsoftc *isp)
790138568Ssam{
791154541Ssam	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
792154541Ssam	caddr_t base;
793154541Ssam	u_int32_t len;
794154541Ssam	int i, error;
795154541Ssam	bus_size_t lim;
796138568Ssam	struct imush im;
797138568Ssam
798178354Ssam
799178354Ssam	if (IS_FC(isp) || IS_1080(isp) || IS_12X0(isp))
800170530Ssam		lim = BUS_SPACE_MAXADDR + 1;
801170530Ssam	else
802170530Ssam		lim = BUS_SPACE_MAXADDR_24BIT + 1;
803154541Ssam
804154541Ssam	/*
805199076Srpaulo	 * Allocate and map the request, result queues, plus FC scratch area.
806170530Ssam	 */
807170530Ssam	len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN);
808170530Ssam	len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN);
809170530Ssam	if (IS_FC(isp)) {
810170530Ssam		len += ISP2100_SCRLEN;
811170530Ssam	}
812195618Srpaulo	if (bus_dma_tag_create(pci->parent_dmat, PAGE_SIZE, lim,
813195618Srpaulo	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, len, 1,
814195618Srpaulo	    BUS_SPACE_MAXSIZE_32BIT, 0, &pci->cntrol_dmat) != 0) {
815138568Ssam		printf("%s: cannot create a dma tag for control spaces\n",
816121180Ssam		    isp->isp_name);
817178354Ssam		return (1);
818178354Ssam	}
819178354Ssam	if (bus_dmamem_alloc(pci->cntrol_dmat, (void **)&base,
820178354Ssam	    BUS_DMA_NOWAIT, &pci->cntrol_dmap) != 0) {
821178354Ssam		printf("%s: cannot allocate %d bytes of CCB memory\n",
822178354Ssam		    isp->isp_name, len);
823178354Ssam		return (1);
824178354Ssam	}
825178354Ssam
826178354Ssam	isp->isp_rquest = base;
827178354Ssam	im.isp = isp;
828178354Ssam	im.error = 0;
829178354Ssam	bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_rquest,
830178354Ssam	    ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN), isp_map_rquest, &im, 0);
831178354Ssam	if (im.error) {
832178354Ssam		printf("%s: error %d loading dma map for DMA request queue\n",
833178354Ssam		    isp->isp_name, im.error);
834178354Ssam		return (1);
835178354Ssam	}
836178354Ssam	isp->isp_result = base + ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN);
837178354Ssam	im.error = 0;
838178354Ssam	bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_result,
839178354Ssam	    ISP_QUEUE_SIZE(RESULT_QUEUE_LEN), isp_map_result, &im, 0);
840178354Ssam	if (im.error) {
841178354Ssam		printf("%s: error %d loading dma map for DMA result queue\n",
842178354Ssam		    isp->isp_name, im.error);
843178354Ssam		return (1);
844178354Ssam	}
845178354Ssam
846178354Ssam	/*
847170530Ssam	 * Use this opportunity to initialize/create data DMA maps.
848170530Ssam	 */
849178354Ssam	for (i = 0; i < MAXISPREQUEST; i++) {
850178354Ssam		error = bus_dmamap_create(pci->parent_dmat, 0, &pci->dmaps[i]);
851178354Ssam		if (error) {
852178354Ssam			printf("%s: error %d creating mailbox DMA maps\n",
853170530Ssam			    isp->isp_name, error);
854178354Ssam			return (1);
855178354Ssam		}
856178354Ssam	}
857178354Ssam	if (IS_FC(isp)) {
858186904Ssam		fcparam *fcp = (fcparam *) isp->isp_param;
859116742Ssam		fcp->isp_scratch = base +
860116742Ssam			ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN) +
861116742Ssam			ISP_QUEUE_SIZE(RESULT_QUEUE_LEN);
862		im.error = 0;
863		bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap,
864		    fcp->isp_scratch, ISP2100_SCRLEN, isp_map_fcscrt, &im, 0);
865		if (im.error) {
866			printf("%s: error %d loading FC scratch area\n",
867			    isp->isp_name, im.error);
868			return (1);
869		}
870	}
871	return (0);
872}
873
874static void dma2 __P((void *, bus_dma_segment_t *, int, int));
875typedef struct {
876	struct ispsoftc *isp;
877	ISP_SCSI_XFER_T *ccb;
878	ispreq_t *rq;
879	u_int8_t *iptrp;
880	u_int8_t optr;
881	u_int error;
882} mush_t;
883
884#define	MUSHERR_NOQENTRIES	-2
885
886static void
887dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
888{
889	mush_t *mp;
890	ISP_SCSI_XFER_T *ccb;
891	struct ispsoftc *isp;
892	struct isp_pcisoftc *pci;
893	bus_dmamap_t *dp;
894	bus_dma_segment_t *eseg;
895	ispreq_t *rq;
896	u_int8_t *iptrp;
897	u_int8_t optr;
898	ispcontreq_t *crq;
899	int drq, seglim, datalen;
900
901	mp = (mush_t *) arg;
902	if (error) {
903		mp->error = error;
904		return;
905	}
906
907	isp = mp->isp;
908	if (nseg < 1) {
909		printf("%s: zero or negative segment count\n", isp->isp_name);
910		mp->error = EFAULT;
911		return;
912	}
913	ccb = mp->ccb;
914	rq = mp->rq;
915	iptrp = mp->iptrp;
916	optr = mp->optr;
917
918	pci = (struct isp_pcisoftc *)isp;
919	dp = &pci->dmaps[rq->req_handle - 1];
920	if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
921		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD);
922		drq = REQFLAG_DATA_IN;
923	} else {
924		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
925		drq = REQFLAG_DATA_OUT;
926	}
927
928	datalen = XS_XFRLEN(ccb);
929	if (IS_FC(isp)) {
930		seglim = ISP_RQDSEG_T2;
931		((ispreqt2_t *)rq)->req_totalcnt = datalen;
932		((ispreqt2_t *)rq)->req_flags |= drq;
933	} else {
934		seglim = ISP_RQDSEG;
935		rq->req_flags |= drq;
936	}
937
938	eseg = dm_segs + nseg;
939
940	while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) {
941		if (IS_FC(isp)) {
942			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
943			rq2->req_dataseg[rq2->req_seg_count].ds_base =
944			    dm_segs->ds_addr;
945			rq2->req_dataseg[rq2->req_seg_count].ds_count =
946			    dm_segs->ds_len;
947		} else {
948			rq->req_dataseg[rq->req_seg_count].ds_base =
949				dm_segs->ds_addr;
950			rq->req_dataseg[rq->req_seg_count].ds_count =
951				dm_segs->ds_len;
952		}
953		datalen -= dm_segs->ds_len;
954#if	0
955		if (IS_FC(isp)) {
956			ispreqt2_t *rq2 = (ispreqt2_t *)rq;
957			printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n",
958			    isp->isp_name, rq->req_seg_count,
959			    rq2->req_dataseg[rq2->req_seg_count].ds_count,
960			    rq2->req_dataseg[rq2->req_seg_count].ds_base);
961		} else {
962			printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n",
963			    isp->isp_name, rq->req_seg_count,
964			    rq->req_dataseg[rq->req_seg_count].ds_count,
965			    rq->req_dataseg[rq->req_seg_count].ds_base);
966		}
967#endif
968		rq->req_seg_count++;
969		dm_segs++;
970	}
971
972	while (datalen > 0 && dm_segs != eseg) {
973		crq = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, *iptrp);
974		*iptrp = ISP_NXT_QENTRY(*iptrp, RQUEST_QUEUE_LEN);
975		if (*iptrp == optr) {
976#if	0
977			printf("%s: Request Queue Overflow++\n", isp->isp_name);
978#endif
979			mp->error = MUSHERR_NOQENTRIES;
980			return;
981		}
982		rq->req_header.rqs_entry_count++;
983		bzero((void *)crq, sizeof (*crq));
984		crq->req_header.rqs_entry_count = 1;
985		crq->req_header.rqs_entry_type = RQSTYPE_DATASEG;
986
987		seglim = 0;
988		while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) {
989			crq->req_dataseg[seglim].ds_base =
990			    dm_segs->ds_addr;
991			crq->req_dataseg[seglim].ds_count =
992			    dm_segs->ds_len;
993#if	0
994			printf("%s: seg%d[%d] cnt 0x%x paddr 0x%08x\n",
995			    isp->isp_name, rq->req_header.rqs_entry_count-1,
996			    seglim, crq->req_dataseg[seglim].ds_count,
997			    crq->req_dataseg[seglim].ds_base);
998#endif
999			rq->req_seg_count++;
1000			dm_segs++;
1001			seglim++;
1002			datalen -= dm_segs->ds_len;
1003		}
1004	}
1005}
1006
1007static int
1008isp_pci_dmasetup(struct ispsoftc *isp, ISP_SCSI_XFER_T *ccb, ispreq_t *rq,
1009	u_int8_t *iptrp, u_int8_t optr)
1010{
1011	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
1012	struct ccb_hdr *ccb_h;
1013	struct ccb_scsiio *csio;
1014	bus_dmamap_t *dp = NULL;
1015	mush_t mush, *mp;
1016
1017	csio = (struct ccb_scsiio *) ccb;
1018	ccb_h = &csio->ccb_h;
1019
1020	if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_NONE) {
1021		rq->req_seg_count = 1;
1022		return (CMD_QUEUED);
1023	}
1024
1025	/*
1026	 * Do a virtual grapevine step to collect info for
1027	 * the callback dma allocation that we have to use...
1028	 */
1029	mp = &mush;
1030	mp->isp = isp;
1031	mp->ccb = ccb;
1032	mp->rq = rq;
1033	mp->iptrp = iptrp;
1034	mp->optr = optr;
1035	mp->error = 0;
1036
1037	if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) {
1038		if ((ccb_h->flags & CAM_DATA_PHYS) == 0) {
1039			int error, s;
1040
1041			dp = &pci->dmaps[rq->req_handle - 1];
1042			s = splsoftvm();
1043			error = bus_dmamap_load(pci->parent_dmat, *dp,
1044			    csio->data_ptr, csio->dxfer_len, dma2, mp, 0);
1045			if (error == EINPROGRESS) {
1046				bus_dmamap_unload(pci->parent_dmat, *dp);
1047				mp->error = EINVAL;
1048				printf("%s: deferred dma allocation not "
1049				    "supported\n", isp->isp_name);
1050			} else if (error && mp->error == 0) {
1051#ifdef	DIAGNOSTIC
1052				printf("%s: error %d in dma mapping code\n",
1053				    isp->isp_name, error);
1054#endif
1055				mp->error = error;
1056			}
1057			splx(s);
1058		} else {
1059			/* Pointer to physical buffer */
1060			struct bus_dma_segment seg;
1061			seg.ds_addr = (bus_addr_t)csio->data_ptr;
1062			seg.ds_len = csio->dxfer_len;
1063			dma2(mp, &seg, 1, 0);
1064		}
1065	} else {
1066		struct bus_dma_segment *segs;
1067
1068		if ((ccb_h->flags & CAM_DATA_PHYS) != 0) {
1069			printf("%s: Physical segment pointers unsupported",
1070				isp->isp_name);
1071			mp->error = EINVAL;
1072		} else if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0) {
1073			printf("%s: Virtual segment addresses unsupported",
1074				isp->isp_name);
1075			mp->error = EINVAL;
1076		} else {
1077			/* Just use the segments provided */
1078			segs = (struct bus_dma_segment *) csio->data_ptr;
1079			dma2(mp, segs, csio->sglist_cnt, 0);
1080		}
1081	}
1082	if (mp->error) {
1083		int retval = CMD_COMPLETE;
1084		if (mp->error == MUSHERR_NOQENTRIES) {
1085			retval = CMD_EAGAIN;
1086		} else if (mp->error == EFBIG) {
1087			XS_SETERR(csio, CAM_REQ_TOO_BIG);
1088		} else if (mp->error == EINVAL) {
1089			XS_SETERR(csio, CAM_REQ_INVALID);
1090		} else {
1091			XS_SETERR(csio, CAM_UNREC_HBA_ERROR);
1092		}
1093		return (retval);
1094	} else {
1095		/*
1096		 * Check to see if we weren't cancelled while sleeping on
1097		 * getting DMA resources...
1098		 */
1099		if ((ccb_h->status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
1100			if (dp) {
1101				bus_dmamap_unload(pci->parent_dmat, *dp);
1102			}
1103			return (CMD_COMPLETE);
1104		}
1105		return (CMD_QUEUED);
1106	}
1107}
1108
1109static void
1110isp_pci_dmateardown(struct ispsoftc *isp, ISP_SCSI_XFER_T *ccb,
1111	u_int32_t handle)
1112{
1113	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
1114	bus_dmamap_t *dp = &pci->dmaps[handle];
1115
1116	if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1117		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTREAD);
1118	} else {
1119		bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTWRITE);
1120	}
1121	bus_dmamap_unload(pci->parent_dmat, *dp);
1122}
1123
1124
1125static void
1126isp_pci_reset1(struct ispsoftc *isp)
1127{
1128	/* Make sure the BIOS is disabled */
1129	isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS);
1130}
1131
1132static void
1133isp_pci_dumpregs(struct ispsoftc *isp)
1134{
1135	struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp;
1136	printf("%s: PCI Status Command/Status=%lx\n", pci->pci_isp.isp_name,
1137	    pci_conf_read(pci->pci_id, PCIR_COMMAND));
1138}
1139