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