]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/isp/isp_sbus.c
This commit was generated by cvs2svn to compensate for changes in r164146,
[FreeBSD/FreeBSD.git] / sys / dev / isp / isp_sbus.c
1 /*-
2  * Copyright (c) 1997-2006 by Matthew Jacob
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice immediately at the beginning of the file, without modification,
10  *    this list of conditions, and the following disclaimer.
11  * 2. The name of the author may not be used to endorse or promote products
12  *    derived from this software without specific prior written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 /*
27  * SBus specific probe and attach routines for Qlogic ISP SCSI adapters.
28  * FreeBSD Version.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #if __FreeBSD_version >= 700000
37 #include <sys/linker.h>
38 #include <sys/firmware.h>
39 #endif
40 #include <sys/bus.h>
41 #include <sys/kernel.h>
42 #include <sys/module.h>
43 #include <sys/resource.h>
44
45 #include <dev/ofw/ofw_bus.h>
46
47 #include <machine/bus.h>
48 #include <machine/resource.h>
49 #include <sys/rman.h>
50 #include <sparc64/sbus/sbusvar.h>
51
52 #include <dev/isp/isp_freebsd.h>
53
54 static uint32_t
55 isp_sbus_rd_reg(ispsoftc_t *, int);
56 static void
57 isp_sbus_wr_reg(ispsoftc_t *, int, uint32_t);
58 static int
59 isp_sbus_rd_isr(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *);
60 static int isp_sbus_mbxdma(ispsoftc_t *);
61 static int
62 isp_sbus_dmasetup(ispsoftc_t *, XS_T *, ispreq_t *, uint32_t *, uint32_t);
63 static void
64 isp_sbus_dmateardown(ispsoftc_t *, XS_T *, uint32_t);
65
66 static void isp_sbus_reset1(ispsoftc_t *);
67 static void isp_sbus_dumpregs(ispsoftc_t *, const char *);
68
69 static struct ispmdvec mdvec = {
70         isp_sbus_rd_isr,
71         isp_sbus_rd_reg,
72         isp_sbus_wr_reg,
73         isp_sbus_mbxdma,
74         isp_sbus_dmasetup,
75         isp_sbus_dmateardown,
76         NULL,
77         isp_sbus_reset1,
78         isp_sbus_dumpregs,
79         NULL,
80         BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64
81 };
82
83 static int isp_sbus_probe (device_t);
84 static int isp_sbus_attach (device_t);
85
86
87 struct isp_sbussoftc {
88         ispsoftc_t                      sbus_isp;
89         device_t                        sbus_dev;
90         struct resource *               sbus_reg;
91         bus_space_tag_t                 sbus_st;
92         bus_space_handle_t              sbus_sh;
93         void *                          ih;
94         int16_t                         sbus_poff[_NREG_BLKS];
95         bus_dma_tag_t                   dmat;
96         bus_dmamap_t                    *dmaps;
97         sdparam                         sbus_param;
98         struct ispmdvec                 sbus_mdvec;
99         struct resource *               sbus_ires;
100 };
101
102
103 static device_method_t isp_sbus_methods[] = {
104         /* Device interface */
105         DEVMETHOD(device_probe,         isp_sbus_probe),
106         DEVMETHOD(device_attach,        isp_sbus_attach),
107         { 0, 0 }
108 };
109 static void isp_sbus_intr(void *);
110
111 static driver_t isp_sbus_driver = {
112         "isp", isp_sbus_methods, sizeof (struct isp_sbussoftc)
113 };
114 static devclass_t isp_devclass;
115 DRIVER_MODULE(isp, sbus, isp_sbus_driver, isp_devclass, 0, 0);
116 #if __FreeBSD_version >= 700000
117 MODULE_DEPEND(isp, firmware, 1, 1, 1);
118 #else
119 extern ispfwfunc *isp_get_firmware_p;
120 #endif
121
122 static int
123 isp_sbus_probe(device_t dev)
124 {
125         int found = 0;
126         const char *name = ofw_bus_get_name(dev);
127         if (strcmp(name, "SUNW,isp") == 0 ||
128             strcmp(name, "QLGC,isp") == 0 ||
129             strcmp(name, "ptisp") == 0 ||
130             strcmp(name, "PTI,ptisp") == 0) {
131                 found++;
132         }
133         if (!found)
134                 return (ENXIO);
135         
136         if (isp_announced == 0 && bootverbose) {
137                 printf("Qlogic ISP Driver, FreeBSD Version %d.%d, "
138                     "Core Version %d.%d\n",
139                     ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR,
140                     ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR);
141                 isp_announced++;
142         }
143         return (0);
144 }
145
146 static int
147 isp_sbus_attach(device_t dev)
148 {
149         struct resource *regs;
150         int tval, iqd, isp_debug, role, rid, ispburst;
151         struct isp_sbussoftc *sbs;
152         ispsoftc_t *isp = NULL;
153         int locksetup = 0;
154         int ints_setup = 0;
155
156         /*
157          * Figure out if we're supposed to skip this one.
158          * If we are, we actually go to ISP_ROLE_NONE.
159          */
160
161         tval = 0;
162         if (resource_int_value(device_get_name(dev), device_get_unit(dev),
163             "disable", &tval) == 0 && tval) {
164                 device_printf(dev, "device is disabled\n");
165                 /* but return 0 so the !$)$)*!$*) unit isn't reused */
166                 return (0);
167         }
168         
169         role = 0;
170         if (resource_int_value(device_get_name(dev), device_get_unit(dev),
171             "role", &role) == 0 &&
172             ((role & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) == 0)) {
173                 device_printf(dev, "setting role to 0x%x\n", role);
174         } else {
175 #ifdef  ISP_TARGET_MODE
176                 role = ISP_ROLE_INITIATOR|ISP_ROLE_TARGET;
177 #else
178                 role = ISP_DEFAULT_ROLES;
179 #endif
180         }
181
182         sbs = malloc(sizeof (*sbs), M_DEVBUF, M_NOWAIT | M_ZERO);
183         if (sbs == NULL) {
184                 device_printf(dev, "cannot allocate softc\n");
185                 return (ENOMEM);
186         }
187
188         regs = NULL;
189         iqd = 0;
190         rid = 0;
191         regs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
192         if (regs == 0) {
193                 device_printf(dev, "unable to map registers\n");
194                 goto bad;
195         }
196         sbs->sbus_dev = dev;
197         sbs->sbus_reg = regs;
198         sbs->sbus_st = rman_get_bustag(regs);
199         sbs->sbus_sh = rman_get_bushandle(regs);
200         sbs->sbus_mdvec = mdvec;
201
202         sbs->sbus_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF;
203         sbs->sbus_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = SBUS_MBOX_REGS_OFF;
204         sbs->sbus_poff[SXP_BLOCK >> _BLK_REG_SHFT] = SBUS_SXP_REGS_OFF;
205         sbs->sbus_poff[RISC_BLOCK >> _BLK_REG_SHFT] = SBUS_RISC_REGS_OFF;
206         sbs->sbus_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF;
207         isp = &sbs->sbus_isp;
208         isp->isp_mdvec = &sbs->sbus_mdvec;
209         isp->isp_bustype = ISP_BT_SBUS;
210         isp->isp_type = ISP_HA_SCSI_UNKNOWN;
211         isp->isp_param = &sbs->sbus_param;
212         isp->isp_revision = 0;  /* XXX */
213         isp->isp_role = role;
214         isp->isp_dev = dev;
215
216         /*
217          * Get the clock frequency and convert it from HZ to MHz,
218          * rounding up. This defaults to 25MHz if there isn't a
219          * device specific one in the OFW device tree.
220          */
221         sbs->sbus_mdvec.dv_clock = (sbus_get_clockfreq(dev) + 500000)/1000000;
222
223         /*
224          * Now figure out what the proper burst sizes, etc., to use.
225          * Unfortunately, there is no ddi_dma_burstsizes here which
226          * walks up the tree finding the limiting burst size node (if
227          * any). We just use what's here for isp.
228          */
229         ispburst = sbus_get_burstsz(dev);
230         if (ispburst == 0) {
231                 ispburst = SBUS_BURST_32 - 1;
232         }
233         sbs->sbus_mdvec.dv_conf1 =  0;
234         if (ispburst & (1 << 5)) {
235                 sbs->sbus_mdvec.dv_conf1 = BIU_SBUS_CONF1_FIFO_32;
236         } else if (ispburst & (1 << 4)) {
237                 sbs->sbus_mdvec.dv_conf1 = BIU_SBUS_CONF1_FIFO_16;
238         } else if (ispburst & (1 << 3)) {
239                 sbs->sbus_mdvec.dv_conf1 =
240                     BIU_SBUS_CONF1_BURST8 | BIU_SBUS_CONF1_FIFO_8;
241         }
242         if (sbs->sbus_mdvec.dv_conf1) {
243                 sbs->sbus_mdvec.dv_conf1 |= BIU_BURST_ENABLE;
244         }
245
246         /*
247          * We don't trust NVRAM on SBus cards
248          */
249         isp->isp_confopts |= ISP_CFG_NONVRAM;
250
251         /*
252          * Mark things if we're a PTI SBus adapter.
253          */
254         if (strcmp("PTI,ptisp", ofw_bus_get_name(dev)) == 0 ||
255             strcmp("ptisp", ofw_bus_get_name(dev)) == 0) {
256                 SDPARAM(isp)->isp_ptisp = 1;
257         }
258
259
260 #if __FreeBSD_version >= 700000
261         isp->isp_osinfo.fw = firmware_get("isp_1000");
262         if (isp->isp_osinfo.fw) {
263                 union {
264                         const void *cp;
265                         uint16_t *sp;
266                 } stupid;
267                 stupid.cp = isp->isp_osinfo.fw->data;
268                 isp->isp_mdvec->dv_ispfw = stupid.sp;
269         }
270 #else
271         /*
272          * Try and find firmware for this device.
273          */
274         if (isp_get_firmware_p) {
275                 (*isp_get_firmware_p)(0, 0, 0x1000, &sbs->sbus_mdvec.dv_ispfw);
276         }
277 #endif
278
279         tval = 0;
280         if (resource_int_value(device_get_name(dev), device_get_unit(dev),
281             "fwload_disable", &tval) == 0 && tval != 0) {
282                 isp->isp_confopts |= ISP_CFG_NORELOAD;
283         }
284
285         isp->isp_osinfo.default_id = -1;
286         if (resource_int_value(device_get_name(dev), device_get_unit(dev),
287             "iid", &tval) == 0) {
288                 isp->isp_osinfo.default_id = tval;
289                 isp->isp_confopts |= ISP_CFG_OWNLOOPID;
290         }
291         if (isp->isp_osinfo.default_id == -1) {
292                 /*
293                  * XXX: should be a way to get properties w/o having
294                  * XXX: to call OF_xxx functions
295                  */
296                 isp->isp_osinfo.default_id = 7;
297         }
298
299         isp_debug = 0;
300         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
301             "debug", &isp_debug);
302
303         /* Make sure the lock is set up. */
304         mtx_init(&isp->isp_osinfo.lock, "isp", NULL, MTX_DEF);
305         locksetup++;
306
307         iqd = 0;
308         sbs->sbus_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &iqd,
309             RF_ACTIVE | RF_SHAREABLE);
310         if (sbs->sbus_ires == NULL) {
311                 device_printf(dev, "could not allocate interrupt\n");
312                 goto bad;
313         }
314
315         if (bus_setup_intr(dev, sbs->sbus_ires, ISP_IFLAGS,
316             isp_sbus_intr, isp, &sbs->ih)) {
317                 device_printf(dev, "could not setup interrupt\n");
318                 goto bad;
319         }
320         ints_setup++;
321
322         /*
323          * Set up logging levels.
324          */
325         if (isp_debug) {
326                 isp->isp_dblev = isp_debug;
327         } else {
328                 isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR;
329         }
330         if (bootverbose) {
331                 isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO;
332         }
333
334         /*
335          * Make sure we're in reset state.
336          */
337         ISP_LOCK(isp);
338         isp_reset(isp);
339         if (isp->isp_state != ISP_RESETSTATE) {
340                 isp_uninit(isp);
341                 ISP_UNLOCK(isp);
342                 goto bad;
343         }
344         isp_init(isp);
345         if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_INITSTATE) {
346                 isp_uninit(isp);
347                 ISP_UNLOCK(isp);
348                 goto bad;
349         }
350         isp_attach(isp);
351         if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_RUNSTATE) {
352                 isp_uninit(isp);
353                 ISP_UNLOCK(isp);
354                 goto bad;
355         }
356         ISP_UNLOCK(isp);
357         return (0);
358
359 bad:
360
361         if (sbs && ints_setup) {
362                 (void) bus_teardown_intr(dev, sbs->sbus_ires, sbs->ih);
363         }
364
365         if (sbs && sbs->sbus_ires) {
366                 bus_release_resource(dev, SYS_RES_IRQ, iqd, sbs->sbus_ires);
367         }
368
369         if (locksetup && isp) {
370                 mtx_destroy(&isp->isp_osinfo.lock);
371         }
372
373         if (regs) {
374                 (void) bus_release_resource(dev, 0, 0, regs);
375         }
376
377         if (sbs) {
378                 if (sbs->sbus_isp.isp_param) {
379                         free(sbs->sbus_isp.isp_param, M_DEVBUF);
380                 }
381                 free(sbs, M_DEVBUF);
382         }
383         return (ENXIO);
384 }
385
386 static void
387 isp_sbus_intr(void *arg)
388 {
389         ispsoftc_t *isp = arg;
390         uint32_t isr;
391         uint16_t sema, mbox;
392
393         ISP_LOCK(isp);
394         isp->isp_intcnt++;
395         if (ISP_READ_ISR(isp, &isr, &sema, &mbox) == 0) {
396                 isp->isp_intbogus++;
397         } else {
398                 isp_intr(isp, isr, sema, mbox);
399         }
400         ISP_UNLOCK(isp);
401 }
402
403 #define IspVirt2Off(a, x)       \
404         (((struct isp_sbussoftc *)a)->sbus_poff[((x) & _BLK_REG_MASK) >> \
405         _BLK_REG_SHFT] + ((x) & 0xff))
406
407 #define BXR2(sbc, off)          \
408         bus_space_read_2(sbc->sbus_st, sbc->sbus_sh, off)
409
410 static int
411 isp_sbus_rd_isr(ispsoftc_t *isp, uint32_t *isrp, uint16_t *semap, uint16_t *mbp)
412 {
413         struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
414         uint16_t isr, sema;
415
416         isr = BXR2(sbc, IspVirt2Off(isp, BIU_ISR));
417         sema = BXR2(sbc, IspVirt2Off(isp, BIU_SEMA));
418         isp_prt(isp, ISP_LOGDEBUG3, "ISR 0x%x SEMA 0x%x", isr, sema);
419         isr &= INT_PENDING_MASK(isp);
420         sema &= BIU_SEMA_LOCK;
421         if (isr == 0 && sema == 0) {
422                 return (0);
423         }
424         *isrp = isr;
425         if ((*semap = sema) != 0) {
426                 *mbp = BXR2(sbc, IspVirt2Off(isp, OUTMAILBOX0));
427         }
428         return (1);
429 }
430
431 static uint32_t
432 isp_sbus_rd_reg(ispsoftc_t *isp, int regoff)
433 {
434         uint16_t rval;
435         struct isp_sbussoftc *sbs = (struct isp_sbussoftc *) isp;
436         int offset = sbs->sbus_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
437         offset += (regoff & 0xff);
438         rval = bus_space_read_2(sbs->sbus_st, sbs->sbus_sh, offset);
439         isp_prt(isp, ISP_LOGDEBUG3,
440             "isp_sbus_rd_reg(off %x) = %x", regoff, rval);
441         return (rval);
442 }
443
444 static void
445 isp_sbus_wr_reg(ispsoftc_t *isp, int regoff, uint32_t val)
446 {
447         struct isp_sbussoftc *sbs = (struct isp_sbussoftc *) isp;
448         int offset = sbs->sbus_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
449         offset += (regoff & 0xff);
450         isp_prt(isp, ISP_LOGDEBUG3,
451             "isp_sbus_wr_reg(off %x) = %x", regoff, val);
452         bus_space_write_2(sbs->sbus_st, sbs->sbus_sh, offset, val);
453 }
454
455 struct imush {
456         ispsoftc_t *isp;
457         int error;
458 };
459
460 static void imc(void *, bus_dma_segment_t *, int, int);
461
462 static void
463 imc(void *arg, bus_dma_segment_t *segs, int nseg, int error)
464 {
465         struct imush *imushp = (struct imush *) arg;
466         if (error) {
467                 imushp->error = error;
468         } else {
469                 ispsoftc_t *isp =imushp->isp;
470                 bus_addr_t addr = segs->ds_addr;
471
472                 isp->isp_rquest_dma = addr;
473                 addr += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
474                 isp->isp_result_dma = addr;
475         }
476 }
477
478 /*
479  * Should be BUS_SPACE_MAXSIZE, but MAXPHYS is larger than BUS_SPACE_MAXSIZE
480  */
481 #define ISP_NSEGS ((MAXPHYS / PAGE_SIZE) + 1)  
482
483 static int
484 isp_sbus_mbxdma(ispsoftc_t *isp)
485 {
486         struct isp_sbussoftc *sbs = (struct isp_sbussoftc *)isp;
487         caddr_t base;
488         uint32_t len;
489         int i, error, ns;
490         struct imush im;
491
492         /*
493          * Already been here? If so, leave...
494          */
495         if (isp->isp_rquest) {
496                 return (0);
497         }
498
499         ISP_UNLOCK(isp);
500
501         if (bus_dma_tag_create(NULL, 1, BUS_SPACE_MAXADDR_24BIT+1,
502             BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR_32BIT,
503             NULL, NULL, BUS_SPACE_MAXSIZE_32BIT, ISP_NSEGS,
504             BUS_SPACE_MAXADDR_24BIT, 0, busdma_lock_mutex, &Giant,
505             &sbs->dmat)) {
506                 isp_prt(isp, ISP_LOGERR, "could not create master dma tag");
507                 ISP_LOCK(isp);
508                 return(1);
509         }
510
511         len = sizeof (XS_T **) * isp->isp_maxcmds;
512         isp->isp_xflist = (XS_T **) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
513         if (isp->isp_xflist == NULL) {
514                 isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array");
515                 ISP_LOCK(isp);
516                 return (1);
517         }
518         len = sizeof (bus_dmamap_t) * isp->isp_maxcmds;
519         sbs->dmaps = (bus_dmamap_t *) malloc(len, M_DEVBUF,  M_WAITOK);
520         if (sbs->dmaps == NULL) {
521                 isp_prt(isp, ISP_LOGERR, "can't alloc dma map storage");
522                 free(isp->isp_xflist, M_DEVBUF);
523                 ISP_LOCK(isp);
524                 return (1);
525         }
526
527         /*
528          * Allocate and map the request, result queues, plus FC scratch area.
529          */
530         len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
531         len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
532
533         ns = (len / PAGE_SIZE) + 1;
534         if (bus_dma_tag_create(sbs->dmat, QENTRY_LEN, BUS_SPACE_MAXADDR_24BIT+1,
535             BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR_32BIT, NULL, NULL,
536             len, ns, BUS_SPACE_MAXADDR_24BIT, 0, busdma_lock_mutex, &Giant,
537             &isp->isp_cdmat)) {
538                 isp_prt(isp, ISP_LOGERR,
539                     "cannot create a dma tag for control spaces");
540                 free(sbs->dmaps, M_DEVBUF);
541                 free(isp->isp_xflist, M_DEVBUF);
542                 ISP_LOCK(isp);
543                 return (1);
544         }
545
546         if (bus_dmamem_alloc(isp->isp_cdmat, (void **)&base, BUS_DMA_NOWAIT,
547             &isp->isp_cdmap) != 0) {
548                 isp_prt(isp, ISP_LOGERR,
549                     "cannot allocate %d bytes of CCB memory", len);
550                 bus_dma_tag_destroy(isp->isp_cdmat);
551                 free(isp->isp_xflist, M_DEVBUF);
552                 free(sbs->dmaps, M_DEVBUF);
553                 ISP_LOCK(isp);
554                 return (1);
555         }
556
557         for (i = 0; i < isp->isp_maxcmds; i++) {
558                 error = bus_dmamap_create(sbs->dmat, 0, &sbs->dmaps[i]);
559                 if (error) {
560                         isp_prt(isp, ISP_LOGERR,
561                             "error %d creating per-cmd DMA maps", error);
562                         while (--i >= 0) {
563                                 bus_dmamap_destroy(sbs->dmat, sbs->dmaps[i]);
564                         }
565                         goto bad;
566                 }
567         }
568
569         im.isp = isp;
570         im.error = 0;
571         bus_dmamap_load(isp->isp_cdmat, isp->isp_cdmap, base, len, imc, &im, 0);
572         if (im.error) {
573                 isp_prt(isp, ISP_LOGERR,
574                     "error %d loading dma map for control areas", im.error);
575                 goto bad;
576         }
577
578         isp->isp_rquest = base;
579         base += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
580         ISP_LOCK(isp);
581         isp->isp_result = base;
582         return (0);
583
584 bad:
585         bus_dmamem_free(isp->isp_cdmat, base, isp->isp_cdmap);
586         bus_dma_tag_destroy(isp->isp_cdmat);
587         free(isp->isp_xflist, M_DEVBUF);
588         free(sbs->dmaps, M_DEVBUF);
589         ISP_LOCK(isp);
590         isp->isp_rquest = NULL;
591         return (1);
592 }
593
594 typedef struct {
595         ispsoftc_t *isp;
596         void *cmd_token;
597         void *rq;
598         uint32_t *nxtip;
599         uint32_t optr;
600         int error;
601 } mush_t;
602
603 #define MUSHERR_NOQENTRIES      -2
604
605
606 static void dma2(void *, bus_dma_segment_t *, int, int);
607
608 static void
609 dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
610 {
611         mush_t *mp;
612         ispsoftc_t *isp;
613         struct ccb_scsiio *csio;
614         struct isp_sbussoftc *sbs;
615         bus_dmamap_t *dp;
616         bus_dma_segment_t *eseg;
617         ispreq_t *rq;
618         int seglim, datalen;
619         uint16_t nxti;
620
621         mp = (mush_t *) arg;
622         if (error) {
623                 mp->error = error;
624                 return;
625         }
626
627         if (nseg < 1) {
628                 isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg);
629                 mp->error = EFAULT;
630                 return;
631         }
632         csio = mp->cmd_token;
633         isp = mp->isp;
634         rq = mp->rq;
635         sbs = (struct isp_sbussoftc *)mp->isp;
636         dp = &sbs->dmaps[isp_handle_index(rq->req_handle)];
637         nxti = *mp->nxtip;
638
639         if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
640                 bus_dmamap_sync(sbs->dmat, *dp, BUS_DMASYNC_PREREAD);
641         } else {
642                 bus_dmamap_sync(sbs->dmat, *dp, BUS_DMASYNC_PREWRITE);
643         }
644
645         datalen = XS_XFRLEN(csio);
646
647         /*
648          * We're passed an initial partially filled in entry that
649          * has most fields filled in except for data transfer
650          * related values.
651          *
652          * Our job is to fill in the initial request queue entry and
653          * then to start allocating and filling in continuation entries
654          * until we've covered the entire transfer.
655          */
656
657         if (csio->cdb_len > 12) {
658                 seglim = 0;
659         } else {
660                 seglim = ISP_RQDSEG;
661         }
662         if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
663                 rq->req_flags |= REQFLAG_DATA_IN;
664         } else {
665                 rq->req_flags |= REQFLAG_DATA_OUT;
666         }
667
668         eseg = dm_segs + nseg;
669
670         while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) {
671                 rq->req_dataseg[rq->req_seg_count].ds_base = dm_segs->ds_addr;
672                 rq->req_dataseg[rq->req_seg_count].ds_count = dm_segs->ds_len;
673                 datalen -= dm_segs->ds_len;
674                 rq->req_seg_count++;
675                 dm_segs++;
676         }
677
678         while (datalen > 0 && dm_segs != eseg) {
679                 uint16_t onxti;
680                 ispcontreq_t local, *crq = &local, *cqe;
681
682                 cqe = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti);
683                 onxti = nxti;
684                 nxti = ISP_NXT_QENTRY(onxti, RQUEST_QUEUE_LEN(isp));
685                 if (nxti == mp->optr) {
686                         isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow++");
687                         mp->error = MUSHERR_NOQENTRIES;
688                         return;
689                 }
690                 rq->req_header.rqs_entry_count++;
691                 MEMZERO((void *)crq, sizeof (*crq));
692                 crq->req_header.rqs_entry_count = 1;
693                 crq->req_header.rqs_entry_type = RQSTYPE_DATASEG;
694
695                 seglim = 0;
696                 while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) {
697                         crq->req_dataseg[seglim].ds_base =
698                             dm_segs->ds_addr;
699                         crq->req_dataseg[seglim].ds_count =
700                             dm_segs->ds_len;
701                         rq->req_seg_count++;
702                         dm_segs++;
703                         seglim++;
704                         datalen -= dm_segs->ds_len;
705                 }
706                 isp_put_cont_req(isp, crq, cqe);
707                 MEMORYBARRIER(isp, SYNC_REQUEST, onxti, QENTRY_LEN);
708         }
709         *mp->nxtip = nxti;
710 }
711
712 static int
713 isp_sbus_dmasetup(ispsoftc_t *isp, struct ccb_scsiio *csio, ispreq_t *rq,
714         uint32_t *nxtip, uint32_t optr)
715 {
716         struct isp_sbussoftc *sbs = (struct isp_sbussoftc *)isp;
717         ispreq_t *qep;
718         bus_dmamap_t *dp = NULL;
719         mush_t mush, *mp;
720         void (*eptr)(void *, bus_dma_segment_t *, int, int);
721
722         qep = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx);
723         eptr = dma2;
724
725
726         if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE ||
727             (csio->dxfer_len == 0)) {
728                 rq->req_seg_count = 1;
729                 goto mbxsync;
730         }
731
732         /*
733          * Do a virtual grapevine step to collect info for
734          * the callback dma allocation that we have to use...
735          */
736         mp = &mush;
737         mp->isp = isp;
738         mp->cmd_token = csio;
739         mp->rq = rq;
740         mp->nxtip = nxtip;
741         mp->optr = optr;
742         mp->error = 0;
743
744         if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
745                 if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) {
746                         int error, s;
747                         dp = &sbs->dmaps[isp_handle_index(rq->req_handle)];
748                         s = splsoftvm();
749                         error = bus_dmamap_load(sbs->dmat, *dp,
750                             csio->data_ptr, csio->dxfer_len, eptr, mp, 0);
751                         if (error == EINPROGRESS) {
752                                 bus_dmamap_unload(sbs->dmat, *dp);
753                                 mp->error = EINVAL;
754                                 isp_prt(isp, ISP_LOGERR,
755                                     "deferred dma allocation not supported");
756                         } else if (error && mp->error == 0) {
757 #ifdef  DIAGNOSTIC
758                                 isp_prt(isp, ISP_LOGERR,
759                                     "error %d in dma mapping code", error);
760 #endif
761                                 mp->error = error;
762                         }
763                         splx(s);
764                 } else {
765                         /* Pointer to physical buffer */
766                         struct bus_dma_segment seg;
767                         seg.ds_addr = (bus_addr_t)csio->data_ptr;
768                         seg.ds_len = csio->dxfer_len;
769                         (*eptr)(mp, &seg, 1, 0);
770                 }
771         } else {
772                 struct bus_dma_segment *segs;
773
774                 if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) {
775                         isp_prt(isp, ISP_LOGERR,
776                             "Physical segment pointers unsupported");
777                         mp->error = EINVAL;
778                 } else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) {
779                         isp_prt(isp, ISP_LOGERR,
780                             "Virtual segment addresses unsupported");
781                         mp->error = EINVAL;
782                 } else {
783                         /* Just use the segments provided */
784                         segs = (struct bus_dma_segment *) csio->data_ptr;
785                         (*eptr)(mp, segs, csio->sglist_cnt, 0);
786                 }
787         }
788         if (mp->error) {
789                 int retval = CMD_COMPLETE;
790                 if (mp->error == MUSHERR_NOQENTRIES) {
791                         retval = CMD_EAGAIN;
792                 } else if (mp->error == EFBIG) {
793                         XS_SETERR(csio, CAM_REQ_TOO_BIG);
794                 } else if (mp->error == EINVAL) {
795                         XS_SETERR(csio, CAM_REQ_INVALID);
796                 } else {
797                         XS_SETERR(csio, CAM_UNREC_HBA_ERROR);
798                 }
799                 return (retval);
800         }
801 mbxsync:
802         if (isp->isp_dblev & ISP_LOGDEBUG1) {
803                 isp_print_bytes(isp, "Request Queue Entry", QENTRY_LEN, rq);
804         }
805         switch (rq->req_header.rqs_entry_type) {
806         case RQSTYPE_REQUEST:
807                 isp_put_request(isp, rq, qep);
808                 break;
809         case RQSTYPE_CMDONLY:
810                 isp_put_extended_request(isp, (ispextreq_t *)rq,
811                     (ispextreq_t *)qep);
812                 break;
813         }
814         return (CMD_QUEUED);
815 }
816
817 static void
818 isp_sbus_dmateardown(ispsoftc_t *isp, XS_T *xs, uint32_t handle)
819 {
820         struct isp_sbussoftc *sbs = (struct isp_sbussoftc *)isp;
821         bus_dmamap_t *dp = &sbs->dmaps[isp_handle_index(handle)];
822         if ((xs->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
823                 bus_dmamap_sync(sbs->dmat, *dp, BUS_DMASYNC_POSTREAD);
824         } else {
825                 bus_dmamap_sync(sbs->dmat, *dp, BUS_DMASYNC_POSTWRITE);
826         }
827         bus_dmamap_unload(sbs->dmat, *dp);
828 }
829
830 static void
831 isp_sbus_reset1(ispsoftc_t *isp)
832 {
833         ISP_ENABLE_INTS(isp);
834 }
835
836 static void
837 isp_sbus_dumpregs(ispsoftc_t *isp, const char *msg)
838 {
839         if (msg)
840                 printf("%s: %s\n", device_get_nameunit(isp->isp_dev), msg);
841         else
842                 printf("%s:\n", device_get_nameunit(isp->isp_dev));
843         printf("    biu_conf1=%x", ISP_READ(isp, BIU_CONF1));
844         printf(" biu_icr=%x biu_isr=%x biu_sema=%x ", ISP_READ(isp, BIU_ICR),
845             ISP_READ(isp, BIU_ISR), ISP_READ(isp, BIU_SEMA));
846         printf("risc_hccr=%x\n", ISP_READ(isp, HCCR));
847
848
849         ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE);
850         printf("    cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n",
851                 ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS),
852                 ISP_READ(isp, CDMA_FIFO_STS));
853         printf("    ddma_conf=%x ddma_sts=%x ddma_fifostat=%x\n",
854                 ISP_READ(isp, DDMA_CONF), ISP_READ(isp, DDMA_STATUS),
855                 ISP_READ(isp, DDMA_FIFO_STS));
856         printf("    sxp_int=%x sxp_gross=%x sxp(scsi_ctrl)=%x\n",
857                 ISP_READ(isp, SXP_INTERRUPT),
858                 ISP_READ(isp, SXP_GROSS_ERR),
859                 ISP_READ(isp, SXP_PINS_CTRL));
860         ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE);
861         printf("    mbox regs: %x %x %x %x %x\n",
862             ISP_READ(isp, OUTMAILBOX0), ISP_READ(isp, OUTMAILBOX1),
863             ISP_READ(isp, OUTMAILBOX2), ISP_READ(isp, OUTMAILBOX3),
864             ISP_READ(isp, OUTMAILBOX4));
865 }