1 /*	$OpenBSD: isp_sbus.c,v 1.6 2003/06/24 21:54:38 henric Exp $	*/
2 /* $NetBSD: isp_sbus.c,v 1.46 2001/09/26 20:53:14 eeh Exp $ */
3 
4 /*
5  * This driver, which is contained in NetBSD in the files:
6  *
7  *	sys/dev/ic/isp.c
8  *	sys/dev/ic/isp_inline.h
9  *	sys/dev/ic/isp_netbsd.c
10  *	sys/dev/ic/isp_netbsd.h
11  *	sys/dev/ic/isp_target.c
12  *	sys/dev/ic/isp_target.h
13  *	sys/dev/ic/isp_tpublic.h
14  *	sys/dev/ic/ispmbox.h
15  *	sys/dev/ic/ispreg.h
16  *	sys/dev/ic/ispvar.h
17  *	sys/microcode/isp/asm_sbus.h
18  *	sys/microcode/isp/asm_1040.h
19  *	sys/microcode/isp/asm_1080.h
20  *	sys/microcode/isp/asm_12160.h
21  *	sys/microcode/isp/asm_2100.h
22  *	sys/microcode/isp/asm_2200.h
23  *	sys/pci/isp_pci.c
24  *	sys/sbus/isp_sbus.c
25  *
26  * Is being actively maintained by Matthew Jacob (mjacob@netbsd.org).
27  * This driver also is shared source with FreeBSD, OpenBSD, Linux, Solaris,
28  * Linux versions. This tends to be an interesting maintenance problem.
29  *
30  * Please coordinate with Matthew Jacob on changes you wish to make here.
31  */
32 /*
33  * SBus specific probe and attach routines for Qlogic ISP SCSI adapters.
34  *
35  * Copyright (c) 1997, 2001 by Matthew Jacob
36  * NASA AMES Research Center
37  * All rights reserved.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice immediately at the beginning of the file, without modification,
44  *    this list of conditions, and the following disclaimer.
45  * 2. Redistributions in binary form must reproduce the above copyright
46  *    notice, this list of conditions and the following disclaimer in the
47  *    documentation and/or other materials provided with the distribution.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
53  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59  * SUCH DAMAGE.
60  *
61  */
62 
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/device.h>
66 #include <sys/kernel.h>
67 #include <sys/malloc.h>
68 #include <sys/queue.h>
69 
70 #include <machine/bus.h>
71 #include <machine/intr.h>
72 #include <machine/autoconf.h>
73 
74 #include <dev/ic/isp_openbsd.h>
75 #if	defined(ISP_COMPILE_FW) || defined(ISP_COMPILE_1000_FW)
76 #include <dev/microcode/isp/asm_sbus.h>
77 #endif
78 #include <dev/sbus/sbusvar.h>
79 #include <sys/reboot.h>
80 
81 static int isp_sbus_intr(void *);
82 static int
83 isp_sbus_rd_isr(struct ispsoftc *, u_int16_t *, u_int16_t *, u_int16_t *);
84 static u_int16_t isp_sbus_rd_reg(struct ispsoftc *, int);
85 static void isp_sbus_wr_reg (struct ispsoftc *, int, u_int16_t);
86 static int isp_sbus_mbxdma(struct ispsoftc *);
87 static int isp_sbus_dmasetup(struct ispsoftc *, XS_T *, ispreq_t *, u_int16_t *,
88     u_int16_t);
89 static void isp_sbus_dmateardown(struct ispsoftc *, XS_T *, u_int16_t);
90 
91 #ifndef	ISP_1000_RISC_CODE
92 #define	ISP_1000_RISC_CODE	NULL
93 #endif
94 
95 static struct ispmdvec mdvec = {
96 	isp_sbus_rd_isr,
97 	isp_sbus_rd_reg,
98 	isp_sbus_wr_reg,
99 	isp_sbus_mbxdma,
100 	isp_sbus_dmasetup,
101 	isp_sbus_dmateardown,
102 	NULL,
103 	NULL,
104 	NULL,
105 	(u_int16_t *) ISP_1000_RISC_CODE
106 };
107 
108 struct isp_sbussoftc {
109 	struct ispsoftc	sbus_isp;
110 	struct sbusdev	sbus_sd;
111 	sdparam		sbus_dev;
112 	bus_space_tag_t	sbus_bustag;
113 	bus_space_handle_t sbus_reg;
114 	int		sbus_node;
115 	int		sbus_pri;
116 	struct ispmdvec	sbus_mdvec;
117 	bus_dmamap_t	*sbus_dmamap;
118 	int16_t		sbus_poff[_NREG_BLKS];
119 };
120 
121 
122 static int isp_match(struct device *, void *, void *);
123 static void isp_sbus_attach(struct device *, struct device *, void *);
124 struct cfattach isp_sbus_ca = {
125 	sizeof (struct isp_sbussoftc), isp_match, isp_sbus_attach
126 };
127 
128 static int
isp_match(struct device * parent,void * vcf,void * aux)129 isp_match(struct device *parent, void *vcf, void *aux)
130 {
131 	struct cfdata *cf = vcf;
132 	int rv;
133 #ifdef DEBUG
134 	static int oneshot = 1;
135 #endif
136 	struct sbus_attach_args *sa = aux;
137 
138 	rv = (strcmp(cf->cf_driver->cd_name, sa->sa_name) == 0 ||
139 		strcmp("PTI,ptisp", sa->sa_name) == 0 ||
140 		strcmp("ptisp", sa->sa_name) == 0 ||
141 		strcmp("SUNW,isp", sa->sa_name) == 0 ||
142 		strcmp("QLGC,isp", sa->sa_name) == 0);
143 #ifdef DEBUG
144 	if (rv && oneshot) {
145 		oneshot = 0;
146 		printf("Qlogic ISP Driver, NetBSD (sbus) Platform Version "
147 		    "%d.%d Core Version %d.%d\n",
148 		    ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR,
149 		    ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR);
150 	}
151 #endif
152 	return (rv);
153 }
154 
155 
156 static void
isp_sbus_attach(struct device * parent,struct device * self,void * aux)157 isp_sbus_attach(struct device *parent, struct device *self, void *aux)
158 {
159 	int freq, ispburst, sbusburst;
160 	struct sbus_attach_args *sa = aux;
161 	struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) self;
162 	struct ispsoftc *isp = &sbc->sbus_isp;
163 
164 	printf(" for %s\n", sa->sa_name);
165 
166 	sbc->sbus_bustag = sa->sa_bustag;
167 	if (sa->sa_nintr != 0)
168 		sbc->sbus_pri = sa->sa_pri;
169 	sbc->sbus_mdvec = mdvec;
170 
171 	if (sa->sa_npromvaddrs != 0) {
172 		if (bus_space_map(sa->sa_bustag, sa->sa_promvaddrs[0],
173 		    sa->sa_size,
174 		    BUS_SPACE_MAP_PROMADDRESS | BUS_SPACE_MAP_LINEAR,
175 		    &sbc->sbus_reg) == 0) {
176 			printf("%s: cannot map registers\n", self->dv_xname);
177 			return;
178 		}
179 	} else {
180 		if (sbus_bus_map(sa->sa_bustag, sa->sa_slot, sa->sa_offset,
181 				 sa->sa_size, BUS_SPACE_MAP_LINEAR, 0,
182 				 &sbc->sbus_reg) != 0) {
183 			printf("%s: cannot map registers\n", self->dv_xname);
184 			return;
185 		}
186 	}
187 	sbc->sbus_node = sa->sa_node;
188 
189 	freq = getpropint(sa->sa_node, "clock-frequency", 0);
190 	if (freq) {
191 		/*
192 		 * Convert from HZ to MHz, rounding up.
193 		 */
194 		freq = (freq + 500000)/1000000;
195 #if	0
196 		printf("%s: %d MHz\n", self->dv_xname, freq);
197 #endif
198 	}
199 	sbc->sbus_mdvec.dv_clock = freq;
200 
201 	/*
202 	 * Now figure out what the proper burst sizes, etc., to use.
203 	 * Unfortunately, there is no ddi_dma_burstsizes here which
204 	 * walks up the tree finding the limiting burst size node (if
205 	 * any).
206 	 */
207 	sbusburst = ((struct sbus_softc *)parent)->sc_burst;
208 	if (sbusburst == 0)
209 		sbusburst = SBUS_BURST_32 - 1;
210 	ispburst = getpropint(sa->sa_node, "burst-sizes", -1);
211 	if (ispburst == -1) {
212 		ispburst = sbusburst;
213 	}
214 	ispburst &= sbusburst;
215 	ispburst &= ~(1 << 7);
216 	ispburst &= ~(1 << 6);
217 	sbc->sbus_mdvec.dv_conf1 =  0;
218 	if (ispburst & (1 << 5)) {
219 		sbc->sbus_mdvec.dv_conf1 = BIU_SBUS_CONF1_FIFO_32;
220 	} else if (ispburst & (1 << 4)) {
221 		sbc->sbus_mdvec.dv_conf1 = BIU_SBUS_CONF1_FIFO_16;
222 	} else if (ispburst & (1 << 3)) {
223 		sbc->sbus_mdvec.dv_conf1 =
224 		    BIU_SBUS_CONF1_BURST8 | BIU_SBUS_CONF1_FIFO_8;
225 	}
226 	if (sbc->sbus_mdvec.dv_conf1) {
227 		sbc->sbus_mdvec.dv_conf1 |= BIU_BURST_ENABLE;
228 	}
229 
230 	/*
231 	 * Some early versions of the PTI SBus adapter
232 	 * would fail in trying to download (via poking)
233 	 * FW. We give up on them.
234 	 */
235 	if (strcmp("PTI,ptisp", sa->sa_name) == 0 ||
236 	    strcmp("ptisp", sa->sa_name) == 0) {
237 		sbc->sbus_mdvec.dv_ispfw = NULL;
238 	}
239 
240 	isp->isp_mdvec = &sbc->sbus_mdvec;
241 	isp->isp_bustype = ISP_BT_SBUS;
242 	isp->isp_type = ISP_HA_SCSI_UNKNOWN;
243 	isp->isp_param = &sbc->sbus_dev;
244 	isp->isp_dmatag = sa->sa_dmatag;
245 	MEMZERO(isp->isp_param, sizeof (sdparam));
246 
247 	sbc->sbus_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF;
248 	sbc->sbus_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = SBUS_MBOX_REGS_OFF;
249 	sbc->sbus_poff[SXP_BLOCK >> _BLK_REG_SHFT] = SBUS_SXP_REGS_OFF;
250 	sbc->sbus_poff[RISC_BLOCK >> _BLK_REG_SHFT] = SBUS_RISC_REGS_OFF;
251 	sbc->sbus_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF;
252 
253 	/* Establish interrupt channel */
254 	bus_intr_establish(sbc->sbus_bustag, sbc->sbus_pri, IPL_BIO, 0,
255 	    isp_sbus_intr, sbc, self->dv_xname);
256 	sbus_establish(&sbc->sbus_sd, &sbc->sbus_isp.isp_osinfo._dev);
257 
258 	/*
259 	 * Set up logging levels.
260 	 */
261 #ifdef	ISP_LOGDEFAULT
262 	isp->isp_dblev = ISP_LOGDEFAULT;
263 #else
264 	isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR;
265 #ifdef	SCSIDEBUG
266 	isp->isp_dblev |= ISP_LOGDEBUG1|ISP_LOGDEBUG2;
267 #endif
268 #ifdef	DEBUG
269 	isp->isp_dblev |= ISP_LOGDEBUG0|ISP_LOGCONFIG|ISP_LOGINFO;
270 #endif
271 #endif
272 
273 	isp->isp_confopts = self->dv_cfdata->cf_flags;
274 	isp->isp_role = ISP_DEFAULT_ROLES;
275 
276 	/*
277 	 * There's no tool on sparc to set NVRAM for ISPs, so ignore it.
278 	 */
279 	isp->isp_confopts |= ISP_CFG_NONVRAM;
280 	ISP_LOCK(isp);
281 	isp->isp_osinfo.no_mbox_ints = 1;
282 	isp_reset(isp);
283 	if (isp->isp_state != ISP_RESETSTATE) {
284 		ISP_UNLOCK(isp);
285 		return;
286 	}
287 	ENABLE_INTS(isp);
288 	isp_init(isp);
289 	if (isp->isp_state != ISP_INITSTATE) {
290 		isp_uninit(isp);
291 		ISP_UNLOCK(isp);
292 		return;
293 	}
294 
295 	/*
296 	 * do generic attach.
297 	 */
298 	ISP_UNLOCK(isp);
299 	isp_attach(isp);
300 	if (isp->isp_state != ISP_RUNSTATE) {
301 		ISP_LOCK(isp);
302 		isp_uninit(isp);
303 		ISP_UNLOCK(isp);
304 	}
305 }
306 
307 static int
isp_sbus_intr(void * arg)308 isp_sbus_intr(void *arg)
309 {
310 	u_int16_t isr, sema, mbox;
311 	struct ispsoftc *isp = arg;
312 
313 	isp->isp_intcnt++;
314 	if (ISP_READ_ISR(isp, &isr, &sema, &mbox) == 0) {
315 		isp->isp_intbogus++;
316 		return (0);
317 	} else {
318 		isp->isp_osinfo.onintstack = 1;
319 		isp_intr(isp, isr, sema, mbox);
320 		isp->isp_osinfo.onintstack = 0;
321 		return (1);
322 	}
323 }
324 
325 #define	IspVirt2Off(a, x)	\
326 	(((struct isp_sbussoftc *)a)->sbus_poff[((x) & _BLK_REG_MASK) >> \
327 	_BLK_REG_SHFT] + ((x) & 0xff))
328 
329 #define	BXR2(sbc, off)		\
330 	bus_space_read_2(sbc->sbus_bustag, sbc->sbus_reg, off)
331 
332 static int
isp_sbus_rd_isr(struct ispsoftc * isp,u_int16_t * isrp,u_int16_t * semap,u_int16_t * mbp)333 isp_sbus_rd_isr(struct ispsoftc *isp, u_int16_t *isrp,
334     u_int16_t *semap, u_int16_t *mbp)
335 {
336 	struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
337 	u_int16_t isr, sema;
338 
339 	isr = BXR2(sbc, IspVirt2Off(isp, BIU_ISR));
340 	sema = BXR2(sbc, IspVirt2Off(isp, BIU_SEMA));
341 	isp_prt(isp, ISP_LOGDEBUG3, "ISR 0x%x SEMA 0x%x", isr, sema);
342 	isr &= INT_PENDING_MASK(isp);
343 	sema &= BIU_SEMA_LOCK;
344 	if (isr == 0 && sema == 0) {
345 		return (0);
346 	}
347 	*isrp = isr;
348 	if ((*semap = sema) != 0) {
349 		*mbp = BXR2(sbc, IspVirt2Off(isp, OUTMAILBOX0));
350 	}
351 	return (1);
352 }
353 
354 static u_int16_t
isp_sbus_rd_reg(struct ispsoftc * isp,int regoff)355 isp_sbus_rd_reg(struct ispsoftc *isp, int regoff)
356 {
357 	struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
358 	int offset = sbc->sbus_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
359 	offset += (regoff & 0xff);
360 	return (bus_space_read_2(sbc->sbus_bustag, sbc->sbus_reg, offset));
361 }
362 
363 static void
isp_sbus_wr_reg(struct ispsoftc * isp,int regoff,u_int16_t val)364 isp_sbus_wr_reg(struct ispsoftc *isp, int regoff, u_int16_t val)
365 {
366 	struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
367 	int offset = sbc->sbus_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
368 	offset += (regoff & 0xff);
369 	bus_space_write_2(sbc->sbus_bustag, sbc->sbus_reg, offset, val);
370 }
371 
372 static int
isp_sbus_mbxdma(struct ispsoftc * isp)373 isp_sbus_mbxdma(struct ispsoftc *isp)
374 {
375 	struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
376 	bus_dma_segment_t reqseg, rspseg;
377 	int reqrs, rsprs, i, progress;
378 	size_t n;
379 	bus_size_t len;
380 
381 	if (isp->isp_rquest_dma)
382 		return (0);
383 
384 	n = isp->isp_maxcmds * sizeof (XS_T *);
385 	isp->isp_xflist = (XS_T **) malloc(n, M_DEVBUF, M_WAITOK);
386 	if (isp->isp_xflist == NULL) {
387 		isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array");
388 		return (1);
389 	}
390 	MEMZERO(isp->isp_xflist, n);
391 	n = sizeof (bus_dmamap_t) * isp->isp_maxcmds;
392 	sbc->sbus_dmamap = (bus_dmamap_t *) malloc(n, M_DEVBUF, M_WAITOK);
393 	if (sbc->sbus_dmamap == NULL) {
394 		free(isp->isp_xflist, M_DEVBUF);
395 		isp->isp_xflist = NULL;
396 		isp_prt(isp, ISP_LOGERR, "cannot alloc dmamap array");
397 		return (1);
398 	}
399 	for (i = 0; i < isp->isp_maxcmds; i++) {
400 		/* Allocate a DMA handle */
401 		if (bus_dmamap_create(isp->isp_dmatag, MAXPHYS, 1, MAXPHYS, 0,
402 		    BUS_DMA_NOWAIT, &sbc->sbus_dmamap[i]) != 0) {
403 			isp_prt(isp, ISP_LOGERR, "cmd DMA maps create error");
404 			break;
405 		}
406 	}
407 	if (i < isp->isp_maxcmds) {
408 		while (--i >= 0) {
409 			bus_dmamap_destroy(isp->isp_dmatag,
410 			    sbc->sbus_dmamap[i]);
411 		}
412 		free(isp->isp_xflist, M_DEVBUF);
413 		free(sbc->sbus_dmamap, M_DEVBUF);
414 		isp->isp_xflist = NULL;
415 		sbc->sbus_dmamap = NULL;
416 		return (1);
417 	}
418 
419 	/*
420 	 * Allocate and map the request and response queues
421 	 */
422 	progress = 0;
423 	len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
424 	if (bus_dmamem_alloc(isp->isp_dmatag, len, 0, 0, &reqseg, 1, &reqrs,
425 	    BUS_DMA_NOWAIT)) {
426 		goto dmafail;
427 	}
428 	progress++;
429 	if (bus_dmamem_map(isp->isp_dmatag, &reqseg, reqrs, len,
430 	    (caddr_t *)&isp->isp_rquest, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
431 		goto dmafail;
432 	}
433 	progress++;
434 	if (bus_dmamap_create(isp->isp_dmatag, len, 1, len, 0, BUS_DMA_NOWAIT,
435 	    &isp->isp_rqdmap) != 0) {
436 		goto dmafail;
437 	}
438 	progress++;
439 	if (bus_dmamap_load(isp->isp_dmatag, isp->isp_rqdmap,
440 	    isp->isp_rquest, len, NULL, BUS_DMA_NOWAIT) != 0) {
441 		goto dmafail;
442 	}
443 	progress++;
444 	isp->isp_rquest_dma = isp->isp_rqdmap->dm_segs[0].ds_addr;
445 
446 	len = ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
447 	if (bus_dmamem_alloc(isp->isp_dmatag, len, 0, 0, &rspseg, 1, &rsprs,
448 	    BUS_DMA_NOWAIT)) {
449 		goto dmafail;
450 	}
451 	progress++;
452 	if (bus_dmamem_map(isp->isp_dmatag, &rspseg, rsprs, len,
453 	    (caddr_t *)&isp->isp_result, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
454 		goto dmafail;
455 	}
456 	progress++;
457 	if (bus_dmamap_create(isp->isp_dmatag, len, 1, len, 0, BUS_DMA_NOWAIT,
458 	    &isp->isp_rsdmap) != 0) {
459 		goto dmafail;
460 	}
461 	progress++;
462 	if (bus_dmamap_load(isp->isp_dmatag, isp->isp_rsdmap,
463 	    isp->isp_result, len, NULL, BUS_DMA_NOWAIT) != 0) {
464 		goto dmafail;
465 	}
466 	isp->isp_result_dma = isp->isp_rsdmap->dm_segs[0].ds_addr;
467 
468 	return (0);
469 
470 dmafail:
471 	isp_prt(isp, ISP_LOGERR, "Mailbox DMA Setup Failure");
472 
473 	if (progress >= 8) {
474 		bus_dmamap_unload(isp->isp_dmatag, isp->isp_rsdmap);
475 	}
476 	if (progress >= 7) {
477 		bus_dmamap_destroy(isp->isp_dmatag, isp->isp_rsdmap);
478 	}
479 	if (progress >= 6) {
480 		bus_dmamem_unmap(isp->isp_dmatag,
481 		    isp->isp_result, ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)));
482 	}
483 	if (progress >= 5) {
484 		bus_dmamem_free(isp->isp_dmatag, &rspseg, rsprs);
485 	}
486 
487 	if (progress >= 4) {
488 		bus_dmamap_unload(isp->isp_dmatag, isp->isp_rqdmap);
489 	}
490 	if (progress >= 3) {
491 		bus_dmamap_destroy(isp->isp_dmatag, isp->isp_rqdmap);
492 	}
493 	if (progress >= 2) {
494 		bus_dmamem_unmap(isp->isp_dmatag,
495 		    isp->isp_rquest, ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)));
496 	}
497 	if (progress >= 1) {
498 		bus_dmamem_free(isp->isp_dmatag, &reqseg, reqrs);
499 	}
500 
501 	for (i = 0; i < isp->isp_maxcmds; i++) {
502 		bus_dmamap_destroy(isp->isp_dmatag, sbc->sbus_dmamap[i]);
503 	}
504 	free(sbc->sbus_dmamap, M_DEVBUF);
505 	free(isp->isp_xflist, M_DEVBUF);
506 	isp->isp_xflist = NULL;
507 	sbc->sbus_dmamap = NULL;
508 	return (1);
509 }
510 
511 /*
512  * Map a DMA request.
513  * We're guaranteed that rq->req_handle is a value from 1 to isp->isp_maxcmds.
514  */
515 
516 static int
isp_sbus_dmasetup(struct ispsoftc * isp,XS_T * xs,ispreq_t * rq,u_int16_t * nxtip,u_int16_t optr)517 isp_sbus_dmasetup(struct ispsoftc *isp, XS_T *xs, ispreq_t *rq,
518     u_int16_t *nxtip, u_int16_t optr)
519 {
520 	struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
521 	bus_dmamap_t dmap;
522 	ispreq_t *qep;
523 	int cansleep = (xs->flags & SCSI_NOSLEEP) == 0;
524 	int in = (xs->flags & SCSI_DATA_IN) != 0;
525 
526 	qep = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx);
527 	if (xs->datalen == 0) {
528 		rq->req_seg_count = 1;
529 		goto mbxsync;
530 	}
531 
532 	dmap = sbc->sbus_dmamap[isp_handle_index(rq->req_handle)];
533 	if (dmap->dm_nsegs != 0) {
534 		panic("%s: dma map already allocated", isp->isp_name);
535 		/* NOTREACHED */
536 	}
537 	if (bus_dmamap_load(isp->isp_dmatag, dmap, xs->data, xs->datalen,
538 	    NULL, (cansleep ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT) |
539 	    BUS_DMA_STREAMING) != 0) {
540 		XS_SETERR(xs, HBA_BOTCH);
541 		return (CMD_COMPLETE);
542 	}
543 
544 	bus_dmamap_sync(isp->isp_dmatag, dmap, 0, xs->datalen,
545 	    in? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
546 
547 	if (in) {
548 		rq->req_flags |= REQFLAG_DATA_IN;
549 	} else {
550 		rq->req_flags |= REQFLAG_DATA_OUT;
551 	}
552 
553 	if (XS_CDBLEN(xs) > 12) {
554 		u_int16_t onxti;
555 		ispcontreq_t local, *crq = &local, *cqe;
556 
557 		onxti = *nxtip;
558 		cqe = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, onxti);
559 		*nxtip = ISP_NXT_QENTRY(onxti, RQUEST_QUEUE_LEN(isp));
560 		if (*nxtip == optr) {
561 			isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow++");
562 			bus_dmamap_unload(isp->isp_dmatag, dmap);
563 			XS_SETERR(xs, HBA_BOTCH);
564 			return (CMD_EAGAIN);
565 		}
566 		rq->req_seg_count = 2;
567 		MEMZERO((void *)crq, sizeof (*crq));
568 		crq->req_header.rqs_entry_count = 1;
569 		crq->req_header.rqs_entry_type = RQSTYPE_DATASEG;
570 		crq->req_dataseg[0].ds_count = xs->datalen;
571 		crq->req_dataseg[0].ds_base = dmap->dm_segs[0].ds_addr;
572 		isp_put_cont_req(isp, crq, cqe);
573 		MEMORYBARRIER(isp, SYNC_REQUEST, onxti, QENTRY_LEN);
574 	} else {
575 		rq->req_seg_count = 1;
576 		rq->req_dataseg[0].ds_count = xs->datalen;
577 		rq->req_dataseg[0].ds_base = dmap->dm_segs[0].ds_addr;
578 	}
579 
580 mbxsync:
581 	if (XS_CDBLEN(xs) > 12) {
582 		isp_put_extended_request(isp,
583 		    (ispextreq_t *)rq, (ispextreq_t *) qep);
584 	} else {
585 		isp_put_request(isp, rq, qep);
586 	}
587 	return (CMD_QUEUED);
588 }
589 
590 static void
isp_sbus_dmateardown(struct ispsoftc * isp,XS_T * xs,u_int16_t handle)591 isp_sbus_dmateardown(struct ispsoftc *isp, XS_T *xs, u_int16_t handle)
592 {
593 	struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
594 	bus_dmamap_t dmap;
595 
596 	dmap = sbc->sbus_dmamap[isp_handle_index(handle)];
597 
598 	if (dmap->dm_nsegs == 0) {
599 		panic("%s: dma map not already allocated", isp->isp_name);
600 		/* NOTREACHED */
601 	}
602 	bus_dmamap_sync(isp->isp_dmatag, dmap, 0,
603 	    xs->datalen, (xs->flags & SCSI_DATA_IN)?
604 	    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
605 	bus_dmamap_unload(isp->isp_dmatag, dmap);
606 }
607