diff --git a/sys/dev/eisa/ahb.c b/sys/dev/eisa/ahb.c index 563177b8619b..d64653701b08 100644 --- a/sys/dev/eisa/ahb.c +++ b/sys/dev/eisa/ahb.c @@ -1,4 +1,4 @@ -/* $NetBSD: ahb.c,v 1.8 1997/03/28 23:47:14 mycroft Exp $ */ +/* $NetBSD: ahb.c,v 1.9 1997/06/06 23:30:02 thorpej Exp $ */ #undef AHBDEBUG #ifdef DDB @@ -7,6 +7,43 @@ #define integrate static inline #endif +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + /* * Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved. * @@ -83,13 +120,14 @@ #define ECB_HASH_SHIFT 9 #define ECB_HASH(x) ((((long)(x))>>ECB_HASH_SHIFT) & (ECB_HASH_SIZE - 1)) -#define KVTOPHYS(x) vtophys(x) +#define AHB_MAXXFER ((AHB_NSEG - 1) << PGSHIFT) struct ahb_softc { struct device sc_dev; bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; + bus_dma_tag_t sc_dmat; void *sc_ih; struct ahb_ecb *sc_ecbhash[ECB_HASH_SIZE]; @@ -117,6 +155,7 @@ void ahbminphys __P((struct buf *)); int ahb_scsi_cmd __P((struct scsi_xfer *)); int ahb_poll __P((struct ahb_softc *, struct scsi_xfer *, int)); void ahb_timeout __P((void *)); +int ahb_create_ecbs __P((struct ahb_softc *)); integrate void ahb_reset_ecb __P((struct ahb_softc *, struct ahb_ecb *)); integrate void ahb_init_ecb __P((struct ahb_softc *, struct ahb_ecb *)); @@ -136,7 +175,11 @@ struct scsi_device ahb_dev = { NULL, /* Use default 'done' routine */ }; +#ifdef __BROKEN_INDIRECT_CONFIG int ahbmatch __P((struct device *, void *, void *)); +#else +int ahbmatch __P((struct device *, struct cfdata *, void *)); +#endif void ahbattach __P((struct device *, struct device *, void *)); struct cfattach ahb_ca = { @@ -149,6 +192,9 @@ struct cfdriver ahb_cd = { #define AHB_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */ +/* XXX Should put this in a better place. */ +#define offsetof(type, member) ((size_t)(&((type *)0)->member)) + /* * Check the slots looking for a board we recognise * If we find one, note it's address (slot) and call @@ -157,7 +203,12 @@ struct cfdriver ahb_cd = { int ahbmatch(parent, match, aux) struct device *parent; - void *match, *aux; +#ifdef __BROKEN_INDIRECT_CONFIG + void *match; +#else + struct cfdata *match; +#endif + void *aux; { struct eisa_attach_args *ea = aux; bus_space_tag_t iot = ea->ea_iot; @@ -217,6 +268,7 @@ ahbattach(parent, self, aux) sc->sc_iot = iot; sc->sc_ioh = ioh; + sc->sc_dmat = ea->ea_dmat; if (ahb_find(iot, ioh, &apd)) panic("ahbattach: ahb_find failed!"); @@ -284,7 +336,12 @@ ahb_send_mbox(sc, opcode, ecb) Debugger(); } - bus_space_write_4(iot, ioh, MBOXOUT0, KVTOPHYS(ecb)); /* don't know this will work */ + /* + * don't know if this will work. + * XXX WHAT DOES THIS COMMENT MEAN?! --thorpej + */ + bus_space_write_4(iot, ioh, MBOXOUT0, + ecb->dmamap_self->dm_segs[0].ds_addr); bus_space_write_1(iot, ioh, ATTN, opcode | ecb->xs->sc_link->target); if ((ecb->xs->flags & SCSI_POLL) == 0) @@ -433,25 +490,87 @@ ahb_free_ecb(sc, ecb) splx(s); } +/* + * Create a set of ecbs and add them to the free list. + */ integrate void ahb_init_ecb(sc, ecb) struct ahb_softc *sc; struct ahb_ecb *ecb; { + bus_dma_tag_t dmat = sc->sc_dmat; int hashnum; + /* + * XXX Should we put a DIAGNOSTIC check for multiple + * XXX ECB inits here? + */ + bzero(ecb, sizeof(struct ahb_ecb)); + + /* + * Create the DMA maps for this ECB. + */ + if (bus_dmamap_create(dmat, sizeof(struct ahb_ecb), 1, + sizeof(struct ahb_ecb), 0, BUS_DMA_NOWAIT, &ecb->dmamap_self) || + + /* XXX What's a good value for this? */ + bus_dmamap_create(dmat, AHB_MAXXFER, AHB_NSEG, AHB_MAXXFER, + 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &ecb->dmamap_xfer)) + panic("ahb_init_ecb: can't create DMA maps"); + + /* + * Load the permanent DMA maps. + */ + if (bus_dmamap_load(dmat, ecb->dmamap_self, ecb, + sizeof(struct ahb_ecb), NULL, BUS_DMA_NOWAIT)) + panic("ahb_init_ecb: can't load permanent maps"); + /* * put in the phystokv hash table * Never gets taken out. */ - ecb->hashkey = KVTOPHYS(ecb); + ecb->hashkey = ecb->dmamap_self->dm_segs[0].ds_addr; hashnum = ECB_HASH(ecb->hashkey); ecb->nexthash = sc->sc_ecbhash[hashnum]; sc->sc_ecbhash[hashnum] = ecb; ahb_reset_ecb(sc, ecb); } +int +ahb_create_ecbs(sc) + struct ahb_softc *sc; +{ + bus_dma_segment_t seg; + bus_size_t size; + struct ahb_ecb *ecb; + int rseg, error; + + size = NBPG; + error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &seg, 1, &rseg, + BUS_DMA_NOWAIT); + if (error) + return (error); + + error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, + (caddr_t *)&ecb, BUS_DMA_NOWAIT|BUS_DMAMEM_NOSYNC); + if (error) { + bus_dmamem_free(sc->sc_dmat, &seg, rseg); + return (error); + } + + bzero(ecb, size); + while (size > sizeof(struct ahb_ecb)) { + ahb_init_ecb(sc, ecb); + sc->sc_numecbs++; + TAILQ_INSERT_TAIL(&sc->sc_free_ecb, ecb, chain); + (caddr_t)ecb += ALIGN(sizeof(struct ahb_ecb)); + size -= ALIGN(sizeof(struct ahb_ecb)); + } + + return (0); +} + /* * Get a free ecb * @@ -479,16 +598,12 @@ ahb_get_ecb(sc, flags) break; } if (sc->sc_numecbs < AHB_ECB_MAX) { - ecb = (struct ahb_ecb *) malloc(sizeof(struct ahb_ecb), - M_TEMP, M_NOWAIT); - if (!ecb) { - printf("%s: can't malloc ecb\n", + if (ahb_create_ecbs(sc)) { + printf("%s: can't allocate ecbs\n", sc->sc_dev.dv_xname); goto out; } - ahb_init_ecb(sc, ecb); - sc->sc_numecbs++; - break; + continue; } if ((flags & SCSI_NOSLEEP) != 0) goto out; @@ -530,10 +645,23 @@ ahb_done(sc, ecb) struct ahb_softc *sc; struct ahb_ecb *ecb; { + bus_dma_tag_t dmat = sc->sc_dmat; struct scsi_sense_data *s1, *s2; struct scsi_xfer *xs = ecb->xs; SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahb_done\n")); + + /* + * If we were a data transfer, unload the map that described + * the data buffer. + */ + if (xs->datalen) { + bus_dmamap_sync(dmat, ecb->dmamap_xfer, + (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD : + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(dmat, ecb->dmamap_xfer); + } + /* * Otherwise, put the results of the operation * into the xfer and call whoever started it @@ -689,8 +817,8 @@ ahbminphys(bp) struct buf *bp; { - if (bp->b_bcount > ((AHB_NSEG - 1) << PGSHIFT)) - bp->b_bcount = ((AHB_NSEG - 1) << PGSHIFT); + if (bp->b_bcount > AHB_MAXXFER) + bp->b_bcount = AHB_MAXXFER; minphys(bp); } @@ -704,14 +832,12 @@ ahb_scsi_cmd(xs) { struct scsi_link *sc_link = xs->sc_link; struct ahb_softc *sc = sc_link->adapter_softc; + bus_dma_tag_t dmat = sc->sc_dmat; struct ahb_ecb *ecb; - struct ahb_dma_seg *sg; - int seg; /* scatter gather seg being worked on */ - u_long thiskv, thisphys, nextphys; - int bytes_this_seg, bytes_this_page, datalen, flags; - int s; + int error, seg, flags, s; SC_DEBUG(sc_link, SDEV_DB2, ("ahb_scsi_cmd\n")); + /* * get a ecb (mbox-out) to use. If the transfer * is from a buf (possibly from interrupt time) @@ -759,96 +885,65 @@ ahb_scsi_cmd(xs) ecb->opt1 = ECB_SES /*| ECB_DSB*/ | ECB_ARS; ecb->opt2 = sc_link->lun | ECB_NRB; bcopy(xs->cmd, &ecb->scsi_cmd, ecb->scsi_cmd_length = xs->cmdlen); - ecb->sense_ptr = KVTOPHYS(&ecb->ecb_sense); + ecb->sense_ptr = ecb->dmamap_self->dm_segs[0].ds_addr + + offsetof(struct ahb_ecb, ecb_sense); ecb->req_sense_length = sizeof(ecb->ecb_sense); - ecb->status = KVTOPHYS(&ecb->ecb_status); + ecb->status = ecb->dmamap_self->dm_segs[0].ds_addr + + offsetof(struct ahb_ecb, ecb_status); ecb->ecb_status.host_stat = 0x00; ecb->ecb_status.target_stat = 0x00; if (xs->datalen) { - sg = ecb->ahb_dma; - seg = 0; -#ifdef TFS + /* + * Map the DMA transfer. + */ +#ifdef TFS if (flags & SCSI_DATA_UIO) { - struct iovec *iovp = ((struct uio *) xs->data)->uio_iov; - datalen = ((struct uio *) xs->data)->uio_iovcnt; - xs->datalen = 0; - while (datalen && seg < AHB_NSEG) { - sg->seg_addr = (physaddr)iovp->iov_base; - sg->seg_len = iovp->iov_len; - xs->datalen += iovp->iov_len; - SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)", - iovp->iov_len, iovp->iov_base)); - sg++; - iovp++; - seg++; - datalen--; - } - } - else -#endif /*TFS */ + error = bus_dmamap_load_uio(sc->sc_dmat, + ecb->dmamap_xfer, (struct uio *)xs->data, + (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : + BUS_DMA_WAITOK); + } else +#endif /* TFS */ { - /* - * Set up the scatter gather block - */ - SC_DEBUG(sc_link, SDEV_DB4, - ("%d @0x%x:- ", xs->datalen, xs->data)); - datalen = xs->datalen; - thiskv = (long) xs->data; - thisphys = KVTOPHYS(thiskv); - - while (datalen && seg < AHB_NSEG) { - bytes_this_seg = 0; - - /* put in the base address */ - sg->seg_addr = thisphys; - - SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys)); - - /* do it at least once */ - nextphys = thisphys; - while (datalen && thisphys == nextphys) { - /* - * This page is contiguous (physically) - * with the the last, just extend the - * length - */ - /* how far to the end of the page */ - nextphys = (thisphys & ~PGOFSET) + NBPG; - bytes_this_page = nextphys - thisphys; - /**** or the data ****/ - bytes_this_page = min(bytes_this_page, - datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; - - /* get more ready for the next page */ - thiskv = (thiskv & ~PGOFSET) + NBPG; - if (datalen) - thisphys = KVTOPHYS(thiskv); - } - /* - * next page isn't contiguous, finish the seg - */ - SC_DEBUGN(sc_link, SDEV_DB4, - ("(0x%x)", bytes_this_seg)); - sg->seg_len = bytes_this_seg; - sg++; - seg++; - } + error = bus_dmamap_load(sc->sc_dmat, + ecb->dmamap_xfer, xs->data, xs->datalen, NULL, + (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : + BUS_DMA_WAITOK); } - /*end of iov/kv decision */ - SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); - if (datalen) { - /* - * there's still data, must have run out of segs! - */ - printf("%s: ahb_scsi_cmd, more than %d dma segs\n", - sc->sc_dev.dv_xname, AHB_NSEG); + + if (error) { + if (error == EFBIG) { + printf("%s: ahb_scsi_cmd, more than %d" + " dma segments\n", + sc->sc_dev.dv_xname, AHB_NSEG); + } else { + printf("%s: ahb_scsi_cmd, error %d loading" + " dma map\n", + sc->sc_dev.dv_xname, error); + } goto bad; } - ecb->data_addr = KVTOPHYS(ecb->ahb_dma); - ecb->data_length = seg * sizeof(struct ahb_dma_seg); + + bus_dmamap_sync(dmat, ecb->dmamap_xfer, + (flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD : + BUS_DMASYNC_PREWRITE); + + /* + * Load the hardware scatter/gather map with the + * contents of the DMA map. + */ + for (seg = 0; seg < ecb->dmamap_xfer->dm_nsegs; seg++) { + ecb->ahb_dma[seg].seg_addr = + ecb->dmamap_xfer->dm_segs[seg].ds_addr; + ecb->ahb_dma[seg].seg_len = + ecb->dmamap_xfer->dm_segs[seg].ds_len; + } + + ecb->data_addr = ecb->dmamap_self->dm_segs[0].ds_addr + + offsetof(struct ahb_ecb, ahb_dma); + ecb->data_length = ecb->dmamap_xfer->dm_nsegs * + sizeof(struct ahb_dma_seg); ecb->opt1 |= ECB_S_G; } else { /* No data xfer, use non S/G values */ ecb->data_addr = (physaddr)0; diff --git a/sys/dev/eisa/ahbreg.h b/sys/dev/eisa/ahbreg.h index d519e86548bf..3316030ae4ea 100644 --- a/sys/dev/eisa/ahbreg.h +++ b/sys/dev/eisa/ahbreg.h @@ -1,4 +1,41 @@ -/* $NetBSD: ahbreg.h,v 1.2 1996/09/01 00:54:34 mycroft Exp $ */ +/* $NetBSD: ahbreg.h,v 1.3 1997/06/06 23:30:03 thorpej Exp $ */ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ /* * Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved. @@ -215,4 +252,21 @@ struct ahb_ecb { #define ECB_IMMED 0x04 #define ECB_IMMED_FAIL 0x08 int timeout; + + /* + * DMA maps used by the ECB. These maps are created + * in ahb_init_ecb(). + */ + + /* + * This DMA map maps an individual ECB. This map is + * permanently loaded in ahb_init_ecb(). + */ + bus_dmamap_t dmamap_self; + + /* + * This DMA map maps the buffer involved in the transfer. + * Its contents are loaded into "ahb_dma" above. + */ + bus_dmamap_t dmamap_xfer; }; diff --git a/sys/dev/eisa/bha_eisa.c b/sys/dev/eisa/bha_eisa.c index 043b3e082078..13a959f72f2b 100644 --- a/sys/dev/eisa/bha_eisa.c +++ b/sys/dev/eisa/bha_eisa.c @@ -1,4 +1,4 @@ -/* $NetBSD: bha_eisa.c,v 1.7 1997/03/28 23:47:15 mycroft Exp $ */ +/* $NetBSD: bha_eisa.c,v 1.8 1997/06/06 23:30:04 thorpej Exp $ */ /* * Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved. @@ -127,9 +127,12 @@ bha_eisa_attach(parent, self, aux) sc->sc_iot = iot; sc->sc_ioh = ioh; + sc->sc_dmat = ea->ea_dmat; if (!bha_find(iot, ioh, &bpd)) panic("bha_eisa_attach: bha_find failed"); + sc->sc_dmaflags = 0; + if (eisa_intr_map(ec, bpd.sc_irq, &ih)) { printf("%s: couldn't map interrupt (%d)\n", sc->sc_dev.dv_xname, bpd.sc_irq); diff --git a/sys/dev/eisa/eisa.c b/sys/dev/eisa/eisa.c index 276e764379dd..77b13fb3a57f 100644 --- a/sys/dev/eisa/eisa.c +++ b/sys/dev/eisa/eisa.c @@ -1,4 +1,4 @@ -/* $NetBSD: eisa.c,v 1.16 1996/12/05 01:25:36 cgd Exp $ */ +/* $NetBSD: eisa.c,v 1.17 1997/06/06 23:30:06 thorpej Exp $ */ /* * Copyright (c) 1995, 1996 Christopher G. Demetriou @@ -146,6 +146,7 @@ eisaattach(parent, self, aux) { struct eisabus_attach_args *eba = aux; bus_space_tag_t iot, memt; + bus_dma_tag_t dmat; eisa_chipset_tag_t ec; int slot, maxnslots; @@ -155,6 +156,7 @@ eisaattach(parent, self, aux) iot = eba->eba_iot; memt = eba->eba_memt; ec = eba->eba_ec; + dmat = eba->eba_dmat; /* * Search for and attach subdevices. @@ -172,6 +174,7 @@ eisaattach(parent, self, aux) ea.ea_iot = iot; ea.ea_memt = memt; ea.ea_ec = ec; + ea.ea_dmat = dmat; ea.ea_slot = slot; slotaddr = EISA_SLOT_ADDR(slot); diff --git a/sys/dev/eisa/eisavar.h b/sys/dev/eisa/eisavar.h index 0c8d451e7bb0..e72daa43c495 100644 --- a/sys/dev/eisa/eisavar.h +++ b/sys/dev/eisa/eisavar.h @@ -1,4 +1,4 @@ -/* $NetBSD: eisavar.h,v 1.10 1996/10/21 22:31:03 thorpej Exp $ */ +/* $NetBSD: eisavar.h,v 1.11 1997/06/06 23:30:07 thorpej Exp $ */ /* * Copyright (c) 1995, 1996 Christopher G. Demetriou @@ -72,6 +72,7 @@ struct eisabus_attach_args { char *eba_busname; /* XXX should be common */ bus_space_tag_t eba_iot; /* eisa i/o space tag */ bus_space_tag_t eba_memt; /* eisa mem space tag */ + bus_dma_tag_t eba_dmat; /* DMA tag */ eisa_chipset_tag_t eba_ec; }; @@ -81,6 +82,7 @@ struct eisabus_attach_args { struct eisa_attach_args { bus_space_tag_t ea_iot; /* eisa i/o space tag */ bus_space_tag_t ea_memt; /* eisa mem space tag */ + bus_dma_tag_t ea_dmat; /* DMA tag */ eisa_chipset_tag_t ea_ec; eisa_slot_t ea_slot; diff --git a/sys/dev/eisa/uha_eisa.c b/sys/dev/eisa/uha_eisa.c index 1ce0395889ef..a87f8d7d1558 100644 --- a/sys/dev/eisa/uha_eisa.c +++ b/sys/dev/eisa/uha_eisa.c @@ -1,4 +1,4 @@ -/* $NetBSD: uha_eisa.c,v 1.7 1997/03/29 02:32:30 mycroft Exp $ */ +/* $NetBSD: uha_eisa.c,v 1.8 1997/06/06 23:30:09 thorpej Exp $ */ /* * Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved. @@ -52,7 +52,11 @@ #define UHA_EISA_SLOT_OFFSET 0xc80 #define UHA_EISA_IOSIZE 0x020 +#ifdef __BROKEN_INDIRECT_CONFIG int uha_eisa_match __P((struct device *, void *, void *)); +#else +int uha_eisa_match __P((struct device *, struct cfdata *, void *)); +#endif void uha_eisa_attach __P((struct device *, struct device *, void *)); struct cfattach uha_eisa_ca = { @@ -62,7 +66,6 @@ struct cfattach uha_eisa_ca = { #ifndef DDB #define Debugger() panic("should call debugger here (uha_eisa.c)") #endif /* ! DDB */ -#define KVTOPHYS(x) vtophys(x) int u24_find __P((bus_space_tag_t, bus_space_handle_t, struct uha_probe_data *)); @@ -79,7 +82,12 @@ void u24_init __P((struct uha_softc *)); int uha_eisa_match(parent, match, aux) struct device *parent; - void *match, *aux; +#ifdef __BROKEN_INDIRECT_CONFIG + void *match; +#else + struct cfdata *match; +#endif + void *aux; { struct eisa_attach_args *ea = aux; bus_space_tag_t iot = ea->ea_iot; @@ -112,6 +120,7 @@ uha_eisa_attach(parent, self, aux) struct eisa_attach_args *ea = aux; struct uha_softc *sc = (void *)self; bus_space_tag_t iot = ea->ea_iot; + bus_dma_tag_t dmat = ea->ea_dmat; bus_space_handle_t ioh; struct uha_probe_data upd; eisa_chipset_tag_t ec = ea->ea_ec; @@ -130,9 +139,12 @@ uha_eisa_attach(parent, self, aux) sc->sc_iot = iot; sc->sc_ioh = ioh; + sc->sc_dmat = dmat; if (!u24_find(iot, ioh, &upd)) panic("uha_eisa_attach: u24_find failed!"); + sc->sc_dmaflags = 0; + if (eisa_intr_map(ec, upd.sc_irq, &ih)) { printf("%s: couldn't map interrupt (%d)\n", sc->sc_dev.dv_xname, upd.sc_irq); @@ -239,7 +251,8 @@ u24_start_mbox(sc, mscp) Debugger(); } - bus_space_write_4(iot, ioh, U24_OGMPTR, KVTOPHYS(mscp)); + bus_space_write_4(iot, ioh, U24_OGMPTR, + mscp->dmamap_self->dm_segs[0].ds_addr); if (mscp->flags & MSCP_ABORT) bus_space_write_1(iot, ioh, U24_OGMCMD, 0x80); else diff --git a/sys/dev/ic/aha.c b/sys/dev/ic/aha.c index 2d6cc5ecdd0a..10357e5452b4 100644 --- a/sys/dev/ic/aha.c +++ b/sys/dev/ic/aha.c @@ -1,4 +1,4 @@ -/* $NetBSD: aha.c,v 1.4 1997/03/28 23:47:08 mycroft Exp $ */ +/* $NetBSD: aha.c,v 1.5 1997/06/06 23:30:58 thorpej Exp $ */ #undef AHADIAG #ifdef DDB @@ -7,6 +7,43 @@ #define integrate static inline #endif +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + /* * Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved. * @@ -76,7 +113,7 @@ #define Debugger() panic("should call debugger here (aha1542.c)") #endif /* ! DDB */ -#define KVTOPHYS(x) vtophys(x) +#define AHA_MAXXFER ((AHA_NSEG - 1) << PGSHIFT) #ifdef AHADEBUG int aha_debug = 1; @@ -100,6 +137,7 @@ void ahaminphys __P((struct buf *)); int aha_scsi_cmd __P((struct scsi_xfer *)); int aha_poll __P((struct aha_softc *, struct scsi_xfer *, int)); void aha_timeout __P((void *arg)); +int aha_create_ccbs __P((struct aha_softc *, void *, size_t)); struct scsi_adapter aha_switch = { aha_scsi_cmd, @@ -123,6 +161,9 @@ struct cfdriver aha_cd = { #define AHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */ #define AHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */ +/* XXX Should put this in a better place. */ +#define offsetof(type, member) ((size_t)(&((type *)0)->member)) + /* * aha_cmd(iot, ioh, sc, icnt, ibuf, ocnt, obuf) * @@ -261,11 +302,12 @@ aha_attach(sc, apd) struct aha_probe_data *apd; { - aha_inquire_setup_information(sc); - aha_init(sc); TAILQ_INIT(&sc->sc_free_ccb); TAILQ_INIT(&sc->sc_waiting_ccb); + aha_inquire_setup_information(sc); + aha_init(sc); + /* * fill in the prototype scsi_link. */ @@ -458,20 +500,92 @@ aha_init_ccb(sc, ccb) struct aha_softc *sc; struct aha_ccb *ccb; { + bus_dma_tag_t dmat = sc->sc_dmat; int hashnum; + /* + * XXX Should we put a DIAGNOSTIC check for multiple + * XXX CCB inits here? + */ + bzero(ccb, sizeof(struct aha_ccb)); + + /* + * Create DMA maps for this CCB. + */ + if (bus_dmamap_create(dmat, sizeof(struct aha_ccb), 1, + sizeof(struct aha_ccb), 0, BUS_DMA_NOWAIT, &ccb->dmamap_self) || + + /* XXX What's a good value for this? */ + bus_dmamap_create(dmat, AHA_MAXXFER, AHA_NSEG, AHA_MAXXFER, + 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &ccb->dmamap_xfer)) + panic("aha_init_ccb: can't create DMA maps"); + + /* + * Load the permanent DMA maps. + */ + if (bus_dmamap_load(dmat, ccb->dmamap_self, ccb, + sizeof(struct aha_ccb), NULL, BUS_DMA_NOWAIT)) + panic("aha_init_ccb: can't load permanent maps"); + /* * put in the phystokv hash table * Never gets taken out. */ - ccb->hashkey = KVTOPHYS(ccb); + ccb->hashkey = ccb->dmamap_self->dm_segs[0].ds_addr; hashnum = CCB_HASH(ccb->hashkey); ccb->nexthash = sc->sc_ccbhash[hashnum]; sc->sc_ccbhash[hashnum] = ccb; aha_reset_ccb(sc, ccb); } +/* + * Create a set of ccbs and add them to the free list. + */ +int +aha_create_ccbs(sc, mem, size) + struct aha_softc *sc; + void *mem; + size_t size; +{ + bus_dma_segment_t seg; + struct aha_ccb *ccb; + int rseg, error; + + if (sc->sc_numccbs >= AHA_CCB_MAX) + return (0); + + if ((ccb = mem) != NULL) + goto have_mem; + + size = NBPG; + error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &seg, 1, &rseg, + BUS_DMA_NOWAIT); + if (error) + return (error); + + error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, + (caddr_t *)&ccb, BUS_DMA_NOWAIT|BUS_DMAMEM_NOSYNC); + if (error) { + bus_dmamem_free(sc->sc_dmat, &seg, rseg); + return (error); + } + + have_mem: + bzero(ccb, size); + while (size > sizeof(struct aha_ccb)) { + aha_init_ccb(sc, ccb); + sc->sc_numccbs++; + if (sc->sc_numccbs >= AHA_CCB_MAX) + break; + TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, chain); + (caddr_t)ccb += ALIGN(sizeof(struct aha_ccb)); + size -= ALIGN(sizeof(struct aha_ccb)); + } + + return (0); +} + /* * Get a free ccb * @@ -499,16 +613,12 @@ aha_get_ccb(sc, flags) break; } if (sc->sc_numccbs < AHA_CCB_MAX) { - ccb = (struct aha_ccb *) malloc(sizeof(struct aha_ccb), - M_TEMP, M_NOWAIT); - if (!ccb) { - printf("%s: can't malloc ccb\n", + if (aha_create_ccbs(sc, NULL, 0)) { + printf("%s: can't allocate ccbs\n", sc->sc_dev.dv_xname); goto out; } - aha_init_ccb(sc, ccb); - sc->sc_numccbs++; - break; + continue; } if ((flags & SCSI_NOSLEEP) != 0) goto out; @@ -619,7 +729,7 @@ aha_start_ccbs(sc) #endif /* Link ccb to mbo. */ - ltophys(KVTOPHYS(ccb), wmbo->ccb_addr); + ltophys(ccb->dmamap_self->dm_segs[0].ds_addr, wmbo->ccb_addr); if (ccb->flags & CCB_ABORT) wmbo->cmd = AHA_MBO_ABORT; else @@ -648,10 +758,23 @@ aha_done(sc, ccb) struct aha_softc *sc; struct aha_ccb *ccb; { + bus_dma_tag_t dmat = sc->sc_dmat; struct scsi_sense_data *s1, *s2; struct scsi_xfer *xs = ccb->xs; SC_DEBUG(xs->sc_link, SDEV_DB2, ("aha_done\n")); + + /* + * If we were a data transfer, unload the map that described + * the data buffer. + */ + if (xs->datalen) { + bus_dmamap_sync(dmat, ccb->dmamap_xfer, + (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD : + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(dmat, ccb->dmamap_xfer); + } + /* * Otherwise, put the results of the operation * into the xfer and call whoever started it @@ -814,10 +937,11 @@ aha_init(sc) { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; + bus_dma_segment_t seg; struct aha_devices devices; struct aha_setup setup; struct aha_mailbox mailbox; - int i; + int i, rseg; /* * XXX @@ -885,6 +1009,33 @@ aha_init(sc) setup.reply.sync[i].offset, setup.reply.sync[i].period * 50 + 200); } + /* + * Allocate the mailbox. + */ + if (bus_dmamem_alloc(sc->sc_dmat, NBPG, NBPG, 0, &seg, 1, + &rseg, BUS_DMA_NOWAIT) || + bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG, + (caddr_t *)&wmbx, BUS_DMA_NOWAIT|BUS_DMAMEM_NOSYNC)) + panic("aha_init: can't create or map mailbox"); + + /* + * Since DMA memory allocation is always rounded up to a + * page size, create some ccbs from the leftovers. + */ + if (aha_create_ccbs(sc, ((caddr_t)wmbx) + + ALIGN(sizeof(struct aha_mbx)), + NBPG - ALIGN(sizeof(struct aha_mbx)))) + panic("aha_init: can't create ccbs"); + + /* + * Create and load the mailbox DMA map. + */ + if (bus_dmamap_create(sc->sc_dmat, sizeof(struct aha_mbx), 1, + sizeof(struct aha_mbx), 0, BUS_DMA_NOWAIT, &sc->sc_dmamap_mbox) || + bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap_mbox, wmbx, + sizeof(struct aha_mbx), NULL, BUS_DMA_NOWAIT)) + panic("aha_init: can't create or load mailbox dma map"); + /* * Set up initial mail box for round-robin operation. */ @@ -899,7 +1050,7 @@ aha_init(sc) /* Initialize mail box. */ mailbox.cmd.opcode = AHA_MBX_INIT; mailbox.cmd.nmbx = AHA_MBX_SIZE; - ltophys(KVTOPHYS(wmbx), mailbox.cmd.addr); + ltophys(sc->sc_dmamap_mbox->dm_segs[0].ds_addr, mailbox.cmd.addr); aha_cmd(iot, ioh, sc, sizeof(mailbox.cmd), (u_char *)&mailbox.cmd, 0, (u_char *)0); @@ -996,8 +1147,8 @@ ahaminphys(bp) struct buf *bp; { - if (bp->b_bcount > ((AHA_NSEG - 1) << PGSHIFT)) - bp->b_bcount = ((AHA_NSEG - 1) << PGSHIFT); + if (bp->b_bcount > AHA_MAXXFER) + bp->b_bcount = AHA_MAXXFER; minphys(bp); } @@ -1011,15 +1162,9 @@ aha_scsi_cmd(xs) { struct scsi_link *sc_link = xs->sc_link; struct aha_softc *sc = sc_link->adapter_softc; + bus_dma_tag_t dmat = sc->sc_dmat; struct aha_ccb *ccb; - struct aha_scat_gath *sg; - int seg; /* scatter gather seg being worked on */ - u_long thiskv, thisphys, nextphys; - int bytes_this_seg, bytes_this_page, datalen, flags; -#ifdef TFS - struct iovec *iovp; -#endif - int s; + int error, seg, flags, s; SC_DEBUG(sc_link, SDEV_DB2, ("aha_scsi_cmd\n")); /* @@ -1050,97 +1195,60 @@ aha_scsi_cmd(xs) } if (xs->datalen) { - sg = ccb->scat_gath; - seg = 0; -#ifdef TFS + /* + * Map the DMA transfer. + */ +#ifdef TFS if (flags & SCSI_DATA_UIO) { - iovp = ((struct uio *)xs->data)->uio_iov; - datalen = ((struct uio *)xs->data)->uio_iovcnt; - xs->datalen = 0; - while (datalen && seg < AHA_NSEG) { - ltophys(iovp->iov_base, sg->seg_addr); - ltophys(iovp->iov_len, sg->seg_len); - xs->datalen += iovp->iov_len; - SC_DEBUGN(sc_link, SDEV_DB4, ("UIO(0x%x@0x%x)", - iovp->iov_len, iovp->iov_base)); - sg++; - iovp++; - seg++; - datalen--; - } + error = bus_dmamap_load_uio(dmat, + ccb->dmamap_xfer, (struct uio *)xs->data, + (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : + BUS_DMA_WAITOK); } else -#endif /* TFS */ +#endif { - /* - * Set up the scatter-gather block. - */ - SC_DEBUG(sc_link, SDEV_DB4, - ("%d @0x%x:- ", xs->datalen, xs->data)); - - datalen = xs->datalen; - thiskv = (int)xs->data; - thisphys = KVTOPHYS(thiskv); - - while (datalen && seg < AHA_NSEG) { - bytes_this_seg = 0; - - /* put in the base address */ - ltophys(thisphys, sg->seg_addr); - - SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys)); - - /* do it at least once */ - nextphys = thisphys; - while (datalen && thisphys == nextphys) { - /* - * This page is contiguous (physically) - * with the the last, just extend the - * length - */ - /* check it fits on the ISA bus */ - if (thisphys > 0xFFFFFF) { - printf("%s: DMA beyond" - " end of ISA\n", - sc->sc_dev.dv_xname); - goto bad; - } - /* how far to the end of the page */ - nextphys = (thisphys & ~PGOFSET) + NBPG; - bytes_this_page = nextphys - thisphys; - /**** or the data ****/ - bytes_this_page = min(bytes_this_page, - datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; - - /* get more ready for the next page */ - thiskv = (thiskv & ~PGOFSET) + NBPG; - if (datalen) - thisphys = KVTOPHYS(thiskv); - } - /* - * next page isn't contiguous, finish the seg - */ - SC_DEBUGN(sc_link, SDEV_DB4, - ("(0x%x)", bytes_this_seg)); - ltophys(bytes_this_seg, sg->seg_len); - sg++; - seg++; - } + error = bus_dmamap_load(dmat, + ccb->dmamap_xfer, xs->data, xs->datalen, NULL, + (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : + BUS_DMA_WAITOK); } - /* end of iov/kv decision */ - SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); - if (datalen) { - /* - * there's still data, must have run out of segs! - */ - printf("%s: aha_scsi_cmd, more than %d dma segs\n", - sc->sc_dev.dv_xname, AHA_NSEG); + + if (error) { + if (error == EFBIG) { + printf("%s: aha_scsi_cmd, more than %d" + " dma segments\n", + sc->sc_dev.dv_xname, AHA_NSEG); + } else { + printf("%s: aha_scsi_cmd, error %d loading" + " dma map\n", + sc->sc_dev.dv_xname, error); + } goto bad; } - ltophys(KVTOPHYS(ccb->scat_gath), ccb->data_addr); - ltophys(seg * sizeof(struct aha_scat_gath), ccb->data_length); - } else { /* No data xfer, use non S/G values */ + + bus_dmamap_sync(dmat, ccb->dmamap_xfer, + (flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD : + BUS_DMASYNC_PREWRITE); + + /* + * Load the hardware scatter/gather map with the + * contents of the DMA map. + */ + for (seg = 0; seg < ccb->dmamap_xfer->dm_nsegs; seg++) { + ltophys(ccb->dmamap_xfer->dm_segs[seg].ds_addr, + ccb->scat_gath[seg].seg_addr); + ltophys(ccb->dmamap_xfer->dm_segs[seg].ds_len, + ccb->scat_gath[seg].seg_len); + } + + ltophys(ccb->dmamap_self->dm_segs[0].ds_addr + + offsetof(struct aha_ccb, scat_gath), ccb->data_addr); + ltophys(ccb->dmamap_xfer->dm_nsegs * + sizeof(struct aha_scat_gath), ccb->data_length); + } else { + /* + * No data xfer, use non S/G values. + */ ltophys(0, ccb->data_addr); ltophys(0, ccb->data_length); } diff --git a/sys/dev/ic/ahareg.h b/sys/dev/ic/ahareg.h index 7b6ca0fd7ea7..4cae6d3f0bc4 100644 --- a/sys/dev/ic/ahareg.h +++ b/sys/dev/ic/ahareg.h @@ -1,4 +1,41 @@ -/* $NetBSD: ahareg.h,v 1.2 1997/03/15 18:11:23 is Exp $ */ +/* $NetBSD: ahareg.h,v 1.3 1997/06/06 23:30:59 thorpej Exp $ */ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ /* * Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved. @@ -174,6 +211,23 @@ struct aha_ccb { #define CCB_SENDING 0x04 #endif int timeout; + + /* + * DMA maps used by the CCB. These maps are created + * in aha_init_ccb(). + */ + + /* + * This DMA map maps an individual CCB. This map is permanently + * loaded in aha_init_ccb(). + */ + bus_dmamap_t dmamap_self; + + /* + * This DMA map maps the buffer involved in the transfer. + * Its contents are loaded into "scat_gath" above. + */ + bus_dmamap_t dmamap_xfer; }; /* diff --git a/sys/dev/ic/ahavar.h b/sys/dev/ic/ahavar.h index 9c19234dbffe..1405babb3775 100644 --- a/sys/dev/ic/ahavar.h +++ b/sys/dev/ic/ahavar.h @@ -1,4 +1,4 @@ -/* $NetBSD: ahavar.h,v 1.3 1997/03/28 23:47:10 mycroft Exp $ */ +/* $NetBSD: ahavar.h,v 1.4 1997/06/06 23:31:00 thorpej Exp $ */ /* * Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved. @@ -59,10 +59,12 @@ struct aha_softc { bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; + bus_dma_tag_t sc_dmat; + bus_dmamap_t sc_dmamap_mbox; /* maps the mailbox */ void *sc_ih; - struct aha_mbx sc_mbx; /* all our mailboxes */ -#define wmbx (&sc->sc_mbx) + struct aha_mbx *sc_mbx; /* all our mailboxes */ +#define wmbx (sc->sc_mbx) struct aha_ccb *sc_ccbhash[CCB_HASH_SIZE]; TAILQ_HEAD(, aha_ccb) sc_free_ccb, sc_waiting_ccb; int sc_numccbs, sc_mbofull; diff --git a/sys/dev/ic/bha.c b/sys/dev/ic/bha.c index 479435f0f397..72d834d78568 100644 --- a/sys/dev/ic/bha.c +++ b/sys/dev/ic/bha.c @@ -1,4 +1,4 @@ -/* $NetBSD: bha.c,v 1.12 1997/04/11 01:34:25 thorpej Exp $ */ +/* $NetBSD: bha.c,v 1.13 1997/06/06 23:31:01 thorpej Exp $ */ #undef BHADIAG #ifdef DDB @@ -7,6 +7,43 @@ #define integrate static inline #endif +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + /* * Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved. * @@ -76,14 +113,7 @@ #define Debugger() panic("should call debugger here (bha.c)") #endif /* ! DDB */ -#ifdef alpha /* XXX */ -/* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */ -extern vm_offset_t alpha_XXX_dmamap(vm_offset_t); -#undef vtophys -#define vtophys(va) alpha_XXX_dmamap((vm_offset_t) va) -#endif /* alpha */ - -#define KVTOPHYS(x) vtophys(x) +#define BHA_MAXXFER ((BHA_NSEG - 1) << PGSHIFT) #ifdef BHADEBUG int bha_debug = 0; @@ -102,11 +132,11 @@ void bha_collect_mbo __P((struct bha_softc *)); void bha_start_ccbs __P((struct bha_softc *)); void bha_done __P((struct bha_softc *, struct bha_ccb *)); void bha_init __P((struct bha_softc *)); -void bha_inquire_setup_information __P((struct bha_softc *)); void bhaminphys __P((struct buf *)); int bha_scsi_cmd __P((struct scsi_xfer *)); int bha_poll __P((struct bha_softc *, struct scsi_xfer *, int)); void bha_timeout __P((void *arg)); +int bha_create_ccbs __P((struct bha_softc *, void *, size_t)); struct scsi_adapter bha_switch = { bha_scsi_cmd, @@ -130,6 +160,9 @@ struct cfdriver bha_cd = { #define BHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */ #define BHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */ +/* XXX Should put this in a better place. */ +#define offsetof(type, member) ((size_t)(&((type *)0)->member)) + /* * bha_cmd(iot, ioh, sc, icnt, ibuf, ocnt, obuf) * @@ -287,11 +320,16 @@ bha_attach(sc, bpd) sc->sc_link.openings = 4; sc->sc_link.max_target = bpd->sc_iswide ? 15 : 7; - bha_inquire_setup_information(sc); - bha_init(sc); TAILQ_INIT(&sc->sc_free_ccb); TAILQ_INIT(&sc->sc_waiting_ccb); + bha_inquire_setup_information(sc); + + printf("%s: model BT-%s, firmware %s\n", sc->sc_dev.dv_xname, + sc->sc_model, sc->sc_firmware); + + bha_init(sc); + /* * ask the adapter what subunits are present */ @@ -473,20 +511,94 @@ bha_init_ccb(sc, ccb) struct bha_softc *sc; struct bha_ccb *ccb; { + bus_dma_tag_t dmat = sc->sc_dmat; int hashnum; + /* + * XXX Should we put a DIAGNOSTIC check for multiple + * XXX CCB inits here? + */ + bzero(ccb, sizeof(struct bha_ccb)); + + /* + * Create DMA maps for this CCB. + */ + if (bus_dmamap_create(dmat, sizeof(struct bha_ccb), 1, + sizeof(struct bha_ccb), 0, BUS_DMA_NOWAIT | sc->sc_dmaflags, + &ccb->dmamap_self) || + + /* XXX What's a good value for this? */ + bus_dmamap_create(dmat, BHA_MAXXFER, BHA_NSEG, BHA_MAXXFER, + 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW | sc->sc_dmaflags, + &ccb->dmamap_xfer)) + panic("bha_init_ccb: can't create DMA maps"); + + /* + * Load the permanent DMA maps. + */ + if (bus_dmamap_load(dmat, ccb->dmamap_self, ccb, + sizeof(struct bha_ccb), NULL, BUS_DMA_NOWAIT)) + panic("bha_init_ccb: can't load permanent maps"); + /* * put in the phystokv hash table * Never gets taken out. */ - ccb->hashkey = KVTOPHYS(ccb); + ccb->hashkey = ccb->dmamap_self->dm_segs[0].ds_addr; hashnum = CCB_HASH(ccb->hashkey); ccb->nexthash = sc->sc_ccbhash[hashnum]; sc->sc_ccbhash[hashnum] = ccb; bha_reset_ccb(sc, ccb); } +/* + * Create a set of ccbs and add them to the free list. + */ +int +bha_create_ccbs(sc, mem, size) + struct bha_softc *sc; + void *mem; + size_t size; +{ + bus_dma_segment_t seg; + struct bha_ccb *ccb; + int rseg, error; + + if (sc->sc_numccbs >= BHA_CCB_MAX) + return (0); + + if ((ccb = mem) != NULL) + goto have_mem; + + size = NBPG; + error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &seg, 1, &rseg, + BUS_DMA_NOWAIT); + if (error) + return (error); + + error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, + (caddr_t *)&ccb, BUS_DMA_NOWAIT|BUS_DMAMEM_NOSYNC); + if (error) { + bus_dmamem_free(sc->sc_dmat, &seg, rseg); + return (error); + } + + have_mem: + bzero(ccb, size); + while (size > sizeof(struct bha_ccb)) { + bha_init_ccb(sc, ccb); + sc->sc_numccbs++; + if (sc->sc_numccbs >= BHA_CCB_MAX) + break; + TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, chain); + (caddr_t)ccb += ALIGN(sizeof(struct bha_ccb)); + size -= ALIGN(sizeof(struct bha_ccb)); + } + + return (0); +} + /* * Get a free ccb * @@ -514,16 +626,12 @@ bha_get_ccb(sc, flags) break; } if (sc->sc_numccbs < BHA_CCB_MAX) { - ccb = (struct bha_ccb *) malloc(sizeof(struct bha_ccb), - M_TEMP, M_NOWAIT); - if (!ccb) { - printf("%s: can't malloc ccb\n", + if (bha_create_ccbs(sc, NULL, 0)) { + printf("%s: can't allocate ccbs\n", sc->sc_dev.dv_xname); goto out; } - bha_init_ccb(sc, ccb); - sc->sc_numccbs++; - break; + continue; } if ((flags & SCSI_NOSLEEP) != 0) goto out; @@ -634,7 +742,7 @@ bha_start_ccbs(sc) #endif /* Link ccb to mbo. */ - ltophys(KVTOPHYS(ccb), wmbo->ccb_addr); + ltophys(ccb->dmamap_self->dm_segs[0].ds_addr, wmbo->ccb_addr); if (ccb->flags & CCB_ABORT) wmbo->cmd = BHA_MBO_ABORT; else @@ -663,10 +771,23 @@ bha_done(sc, ccb) struct bha_softc *sc; struct bha_ccb *ccb; { + bus_dma_tag_t dmat = sc->sc_dmat; struct scsi_sense_data *s1, *s2; struct scsi_xfer *xs = ccb->xs; SC_DEBUG(xs->sc_link, SDEV_DB2, ("bha_done\n")); + + /* + * If we were a data transfer, unload the map that described + * the data buffer. + */ + if (xs->datalen) { + bus_dmamap_sync(dmat, ccb->dmamap_xfer, + (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD : + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(dmat, ccb->dmamap_xfer); + } + /* * Otherwise, put the results of the operation * into the xfer and call whoever started it @@ -921,11 +1042,12 @@ bha_init(sc) { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; + bus_dma_segment_t seg; struct bha_devices devices; struct bha_setup setup; struct bha_mailbox mailbox; struct bha_period period; - int i, rlen; + int i, rlen, rseg; /* Enable round-robin scheme - appeared at firmware rev. 3.31. */ if (strcmp(sc->sc_firmware, "3.31") >= 0) { @@ -1014,6 +1136,34 @@ bha_init(sc) } } + /* + * Allocate the mailbox. + */ + if (bus_dmamem_alloc(sc->sc_dmat, NBPG, NBPG, 0, &seg, 1, + &rseg, BUS_DMA_NOWAIT) || + bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG, + (caddr_t *)&wmbx, BUS_DMA_NOWAIT|BUS_DMAMEM_NOSYNC)) + panic("bha_init: can't create or map mailbox"); + + /* + * Since DMA memory allocation is always rounded up to a + * page size, create some ccbs from the leftovers. + */ + if (bha_create_ccbs(sc, ((caddr_t)wmbx) + + ALIGN(sizeof(struct bha_mbx)), + NBPG - ALIGN(sizeof(struct bha_mbx)))) + panic("bha_init: can't create ccbs"); + + /* + * Create and load the mailbox DMA map. + */ + if (bus_dmamap_create(sc->sc_dmat, sizeof(struct bha_mbx), 1, + sizeof(struct bha_mbx), 0, BUS_DMA_NOWAIT | sc->sc_dmaflags, + &sc->sc_dmamap_mbox) || + bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap_mbox, wmbx, + sizeof(struct bha_mbx), NULL, BUS_DMA_NOWAIT)) + panic("bha_init: can't create or load mailbox dma map"); + /* * Set up initial mail box for round-robin operation. */ @@ -1028,7 +1178,7 @@ bha_init(sc) /* Initialize mail box. */ mailbox.cmd.opcode = BHA_MBX_INIT_EXTENDED; mailbox.cmd.nmbx = BHA_MBX_SIZE; - ltophys(KVTOPHYS(wmbx), mailbox.cmd.addr); + ltophys(sc->sc_dmamap_mbox->dm_segs[0].ds_addr, mailbox.cmd.addr); bha_cmd(iot, ioh, sc, sizeof(mailbox.cmd), (u_char *)&mailbox.cmd, 0, (u_char *)0); @@ -1097,9 +1247,6 @@ bha_inquire_setup_information(sc) *p = '\0'; } else strcpy(sc->sc_model, "542B"); - - printf("%s: model BT-%s, firmware %s\n", sc->sc_dev.dv_xname, - sc->sc_model, sc->sc_firmware); } void @@ -1107,8 +1254,8 @@ bhaminphys(bp) struct buf *bp; { - if (bp->b_bcount > ((BHA_NSEG - 1) << PGSHIFT)) - bp->b_bcount = ((BHA_NSEG - 1) << PGSHIFT); + if (bp->b_bcount > BHA_MAXXFER) + bp->b_bcount = BHA_MAXXFER; minphys(bp); } @@ -1122,15 +1269,9 @@ bha_scsi_cmd(xs) { struct scsi_link *sc_link = xs->sc_link; struct bha_softc *sc = sc_link->adapter_softc; + bus_dma_tag_t dmat = sc->sc_dmat; struct bha_ccb *ccb; - struct bha_scat_gath *sg; - int seg; /* scatter gather seg being worked on */ - u_long thiskv, thisphys, nextphys; - int bytes_this_seg, bytes_this_page, datalen, flags; -#ifdef TFS - struct iovec *iovp; -#endif - int s; + int error, seg, flags, s; SC_DEBUG(sc_link, SDEV_DB2, ("bha_scsi_cmd\n")); /* @@ -1161,92 +1302,60 @@ bha_scsi_cmd(xs) } if (xs->datalen) { - sg = ccb->scat_gath; - seg = 0; -#ifdef TFS + /* + * Map the DMA transfer. + */ +#ifdef TFS if (flags & SCSI_DATA_UIO) { - iovp = ((struct uio *)xs->data)->uio_iov; - datalen = ((struct uio *)xs->data)->uio_iovcnt; - xs->datalen = 0; - while (datalen && seg < BHA_NSEG) { - ltophys(iovp->iov_base, sg->seg_addr); - ltophys(iovp->iov_len, sg->seg_len); - xs->datalen += iovp->iov_len; - SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)", - iovp->iov_len, iovp->iov_base)); - sg++; - iovp++; - seg++; - datalen--; - } + error = bus_dmamap_load_uio(dmat, + ccb->dmamap_xfer, (struct uio *)xs->data, + (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : + BUS_DMA_WAITOK); } else -#endif /* TFS */ +#endif /* TFS */ { - /* - * Set up the scatter-gather block. - */ - SC_DEBUG(sc_link, SDEV_DB4, - ("%d @0x%x:- ", xs->datalen, xs->data)); - - datalen = xs->datalen; - thiskv = (u_long)xs->data; - thisphys = KVTOPHYS(thiskv); - - while (datalen && seg < BHA_NSEG) { - bytes_this_seg = 0; - - /* put in the base address */ - ltophys(thisphys, sg->seg_addr); - - SC_DEBUGN(sc_link, SDEV_DB4, - ("0x%x", thisphys)); - - /* do it at least once */ - nextphys = thisphys; - while (datalen && thisphys == nextphys) { - /* - * This page is contiguous (physically) - * with the the last, just extend the - * length - */ - /* how far to the end of the page */ - nextphys = - (thisphys & ~PGOFSET) + NBPG; - bytes_this_page = nextphys - thisphys; - /**** or the data ****/ - bytes_this_page = min(bytes_this_page, - datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; - - /* get more ready for the next page */ - thiskv = (thiskv & ~PGOFSET) + NBPG; - if (datalen) - thisphys = KVTOPHYS(thiskv); - } - /* - * next page isn't contiguous, finish the seg - */ - SC_DEBUGN(sc_link, SDEV_DB4, - ("(0x%x)", bytes_this_seg)); - ltophys(bytes_this_seg, sg->seg_len); - sg++; - seg++; - } + error = bus_dmamap_load(dmat, + ccb->dmamap_xfer, xs->data, xs->datalen, NULL, + (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : + BUS_DMA_WAITOK); } - /* end of iov/kv decision */ - SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); - if (datalen) { - /* - * there's still data, must have run out of segs! - */ - printf("%s: bha_scsi_cmd, more than %d dma segs\n", - sc->sc_dev.dv_xname, BHA_NSEG); + + if (error) { + if (error == EFBIG) { + printf("%s: bha_scsi_cmd, more than %d" + " dma segments\n", + sc->sc_dev.dv_xname, BHA_NSEG); + } else { + printf("%s: bha_scsi_cmd, error %d loading" + " dma map\n", + sc->sc_dev.dv_xname, error); + } goto bad; } - ltophys(KVTOPHYS(ccb->scat_gath), ccb->data_addr); - ltophys(seg * sizeof(struct bha_scat_gath), ccb->data_length); - } else { /* No data xfer, use non S/G values */ + + bus_dmamap_sync(dmat, ccb->dmamap_xfer, + (flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD : + BUS_DMASYNC_PREWRITE); + + /* + * Load the hardware scatter/gather map with the + * contents of the DMA map. + */ + for (seg = 0; seg < ccb->dmamap_xfer->dm_nsegs; seg++) { + ltophys(ccb->dmamap_xfer->dm_segs[seg].ds_addr, + ccb->scat_gath[seg].seg_addr); + ltophys(ccb->dmamap_xfer->dm_segs[seg].ds_len, + ccb->scat_gath[seg].seg_len); + } + + ltophys(ccb->dmamap_self->dm_segs[0].ds_addr + + offsetof(struct bha_ccb, scat_gath), ccb->data_addr); + ltophys(ccb->dmamap_xfer->dm_nsegs * + sizeof(struct bha_scat_gath), ccb->data_length); + } else { + /* + * No data xfer, use non S/G values. + */ ltophys(0, ccb->data_addr); ltophys(0, ccb->data_length); } @@ -1255,7 +1364,8 @@ bha_scsi_cmd(xs) ccb->data_in = 0; ccb->target = sc_link->target; ccb->lun = sc_link->lun; - ltophys(KVTOPHYS(&ccb->scsi_sense), ccb->sense_ptr); + ltophys(ccb->dmamap_self->dm_segs[0].ds_addr + + offsetof(struct bha_ccb, scsi_sense), ccb->sense_ptr); ccb->req_sense_length = sizeof(ccb->scsi_sense); ccb->host_stat = 0x00; ccb->target_stat = 0x00; diff --git a/sys/dev/ic/bhareg.h b/sys/dev/ic/bhareg.h index b0f8b5189d01..410f90651e72 100644 --- a/sys/dev/ic/bhareg.h +++ b/sys/dev/ic/bhareg.h @@ -1,4 +1,41 @@ -/* $NetBSD: bhareg.h,v 1.6 1997/01/04 16:47:03 jonathan Exp $ */ +/* $NetBSD: bhareg.h,v 1.7 1997/06/06 23:31:03 thorpej Exp $ */ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ /* * Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved. @@ -199,6 +236,23 @@ struct bha_ccb { #define CCB_SENDING 0x04 #endif int timeout; + + /* + * DMA maps used by the CCB. These maps are created + * in bha_init_ccb(). + */ + + /* + * This DMA map maps an individual CCB. This map is + * permanently loaded in bha_init_ccb(). + */ + bus_dmamap_t dmamap_self; + + /* + * This DMA map maps the buffer involved in the transfer. + * Its contents are loaded into "scat_gath" above. + */ + bus_dmamap_t dmamap_xfer; }; /* diff --git a/sys/dev/ic/bhavar.h b/sys/dev/ic/bhavar.h index 5119c174fa87..be8a79e536fa 100644 --- a/sys/dev/ic/bhavar.h +++ b/sys/dev/ic/bhavar.h @@ -1,4 +1,4 @@ -/* $NetBSD: bhavar.h,v 1.6 1997/03/28 23:47:11 mycroft Exp $ */ +/* $NetBSD: bhavar.h,v 1.7 1997/06/06 23:31:04 thorpej Exp $ */ /* * Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved. @@ -59,10 +59,13 @@ struct bha_softc { bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; + bus_dma_tag_t sc_dmat; + bus_dmamap_t sc_dmamap_mbox; /* maps the mailbox */ + int sc_dmaflags; /* bus-specific dma map flags */ void *sc_ih; - struct bha_mbx sc_mbx; /* all our mailboxes */ -#define wmbx (&sc->sc_mbx) + struct bha_mbx *sc_mbx; /* all our mailboxes */ +#define wmbx (sc->sc_mbx) struct bha_ccb *sc_ccbhash[CCB_HASH_SIZE]; TAILQ_HEAD(, bha_ccb) sc_free_ccb, sc_waiting_ccb; int sc_numccbs, sc_mbofull; @@ -86,3 +89,4 @@ void bha_attach __P((struct bha_softc *, struct bha_probe_data *)); int bha_intr __P((void *)); int bha_disable_isacompat __P((struct bha_softc *)); +void bha_inquire_setup_information __P((struct bha_softc *)); diff --git a/sys/dev/ic/uha.c b/sys/dev/ic/uha.c index e59c3f394fbd..b81d391eb1fc 100644 --- a/sys/dev/ic/uha.c +++ b/sys/dev/ic/uha.c @@ -1,4 +1,4 @@ -/* $NetBSD: uha.c,v 1.7 1997/03/29 02:32:31 mycroft Exp $ */ +/* $NetBSD: uha.c,v 1.8 1997/06/06 23:31:05 thorpej Exp $ */ #undef UHADEBUG #ifdef DDB @@ -7,6 +7,43 @@ #define integrate static inline #endif +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + /* * Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved. * @@ -83,7 +120,7 @@ #define Debugger() panic("should call debugger here (uha.c)") #endif /* ! DDB */ -#define KVTOPHYS(x) vtophys(x) +#define UHA_MAXXFER ((UHA_NSEG - 1) << PGSHIFT) integrate void uha_reset_mscp __P((struct uha_softc *, struct uha_mscp *)); void uha_free_mscp __P((struct uha_softc *, struct uha_mscp *)); @@ -91,6 +128,7 @@ integrate void uha_init_mscp __P((struct uha_softc *, struct uha_mscp *)); struct uha_mscp *uha_get_mscp __P((struct uha_softc *, int)); void uhaminphys __P((struct buf *)); int uha_scsi_cmd __P((struct scsi_xfer *)); +int uha_create_mscps __P((struct uha_softc *, void *, size_t)); struct scsi_adapter uha_switch = { uha_scsi_cmd, @@ -113,6 +151,9 @@ struct cfdriver uha_cd = { #define UHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */ +/* XXX Should put this in a better place. */ +#define offsetof(type, member) ((size_t)(&((type *)0)->member)) + /* * Attach all the sub-devices we can find */ @@ -122,9 +163,10 @@ uha_attach(sc, upd) struct uha_probe_data *upd; { - (sc->init)(sc); TAILQ_INIT(&sc->sc_free_mscp); + (sc->init)(sc); + /* * fill in the prototype scsi_link. */ @@ -181,20 +223,94 @@ uha_init_mscp(sc, mscp) struct uha_softc *sc; struct uha_mscp *mscp; { + bus_dma_tag_t dmat = sc->sc_dmat; int hashnum; + /* + * XXX Should we put a DIAGNOSTIC check for multiple + * XXX MSCP inits here? + */ + bzero(mscp, sizeof(struct uha_mscp)); + + /* + * Create the DMA maps for this MSCP. + */ + if (bus_dmamap_create(dmat, sizeof(struct uha_mscp), 1, + sizeof(struct uha_mscp), 0, BUS_DMA_NOWAIT | sc->sc_dmaflags, + &mscp->dmamap_self) || + + /* XXX What's a good value for this? */ + bus_dmamap_create(dmat, UHA_MAXXFER, UHA_NSEG, UHA_MAXXFER, + 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW | sc->sc_dmaflags, + &mscp->dmamap_xfer)) + panic("uha_init_mscp: can't create DMA maps"); + + /* + * Load the permanent DMA maps. + */ + if (bus_dmamap_load(dmat, mscp->dmamap_self, mscp, + sizeof(struct uha_mscp), NULL, BUS_DMA_NOWAIT)) + panic("uha_init_mscp: can't load permanent maps"); + /* * put in the phystokv hash table * Never gets taken out. */ - mscp->hashkey = KVTOPHYS(mscp); + mscp->hashkey = mscp->dmamap_self->dm_segs[0].ds_addr; hashnum = MSCP_HASH(mscp->hashkey); mscp->nexthash = sc->sc_mscphash[hashnum]; sc->sc_mscphash[hashnum] = mscp; uha_reset_mscp(sc, mscp); } +/* + * Create a set of MSCPs and add them to the free list. + */ +int +uha_create_mscps(sc, mem, size) + struct uha_softc *sc; + void *mem; + size_t size; +{ + bus_dma_segment_t seg; + struct uha_mscp *mscp; + int rseg, error; + + if (sc->sc_nummscps >= UHA_MSCP_MAX) + return (0); + + if ((mscp = mem) != NULL) + goto have_mem; + + size = NBPG; + error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &seg, 1, &rseg, + BUS_DMA_NOWAIT); + if (error) + return (error); + + error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, + (caddr_t *)&mscp, BUS_DMA_NOWAIT|BUS_DMAMEM_NOSYNC); + if (error) { + bus_dmamem_free(sc->sc_dmat, &seg, rseg); + return (error); + } + + have_mem: + bzero(mscp, size); + while (size > sizeof(struct uha_mscp)) { + uha_init_mscp(sc, mscp); + sc->sc_nummscps++; + TAILQ_INSERT_TAIL(&sc->sc_free_mscp, mscp, chain); + (caddr_t)mscp += ALIGN(sizeof(struct uha_mscp)); + size -= ALIGN(sizeof(struct uha_mscp)); + if (sc->sc_nummscps >= UHA_MSCP_MAX) + break; + } + + return (0); +} + /* * Get a free mscp * @@ -222,16 +338,12 @@ uha_get_mscp(sc, flags) break; } if (sc->sc_nummscps < UHA_MSCP_MAX) { - mscp = (struct uha_mscp *) malloc(sizeof(struct uha_mscp), - M_TEMP, M_NOWAIT); - if (!mscp) { - printf("%s: can't malloc mscp\n", + if (uha_create_mscps(sc, NULL, 0)) { + printf("%s: can't allocate mscps\n", sc->sc_dev.dv_xname); goto out; } - uha_init_mscp(sc, mscp); - sc->sc_nummscps++; - break; + continue; } if ((flags & SCSI_NOSLEEP) != 0) goto out; @@ -273,10 +385,23 @@ uha_done(sc, mscp) struct uha_softc *sc; struct uha_mscp *mscp; { + bus_dma_tag_t dmat = sc->sc_dmat; struct scsi_sense_data *s1, *s2; struct scsi_xfer *xs = mscp->xs; SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n")); + + /* + * If we were a data transfer, unload the map that described + * the data buffer. + */ + if (xs->datalen) { + bus_dmamap_sync(dmat, mscp->dmamap_xfer, + (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD : + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(dmat, mscp->dmamap_xfer); + } + /* * Otherwise, put the results of the operation * into the xfer and call whoever started it @@ -326,8 +451,8 @@ uhaminphys(bp) struct buf *bp; { - if (bp->b_bcount > ((UHA_NSEG - 1) << PGSHIFT)) - bp->b_bcount = ((UHA_NSEG - 1) << PGSHIFT); + if (bp->b_bcount > UHA_MAXXFER) + bp->b_bcount = UHA_MAXXFER; minphys(bp); } @@ -341,12 +466,10 @@ uha_scsi_cmd(xs) { struct scsi_link *sc_link = xs->sc_link; struct uha_softc *sc = sc_link->adapter_softc; + bus_dma_tag_t dmat = sc->sc_dmat; struct uha_mscp *mscp; struct uha_dma_seg *sg; - int seg; /* scatter gather seg being worked on */ - u_long thiskv, thisphys, nextphys; - int bytes_this_seg, bytes_this_page, datalen, flags; - int s; + int error, seg, flags, s; SC_DEBUG(sc_link, SDEV_DB2, ("uha_scsi_cmd\n")); /* @@ -380,7 +503,8 @@ uha_scsi_cmd(xs) mscp->target = sc_link->target; mscp->lun = sc_link->lun; mscp->scsi_cmd_length = xs->cmdlen; - mscp->sense_ptr = KVTOPHYS(&mscp->mscp_sense); + mscp->sense_ptr = mscp->dmamap_self->dm_segs[0].ds_addr + + offsetof(struct uha_mscp, mscp_sense); mscp->req_sense_length = sizeof(mscp->mscp_sense); mscp->host_stat = 0x00; mscp->target_stat = 0x00; @@ -390,84 +514,49 @@ uha_scsi_cmd(xs) seg = 0; #ifdef TFS if (flags & SCSI_DATA_UIO) { - struct iovec *iovp; - iovp = ((struct uio *) xs->data)->uio_iov; - datalen = ((struct uio *) xs->data)->uio_iovcnt; - xs->datalen = 0; - while (datalen && seg < UHA_NSEG) { - sg->seg_addr = (physaddr)iovp->iov_base; - sg->seg_len = iovp->iov_len; - xs->datalen += iovp->iov_len; - SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)", - iovp->iov_len, iovp->iov_base)); - sg++; - iovp++; - seg++; - datalen--; - } + error = bus_dmamap_load_uio(dmat, + mscp->dmamap_xfer, (struct uio *)xs->data, + (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : + BUS_DMA_WAITOK); } else #endif /*TFS */ { - /* - * Set up the scatter gather block - */ - SC_DEBUG(sc_link, SDEV_DB4, - ("%d @0x%x:- ", xs->datalen, xs->data)); - datalen = xs->datalen; - thiskv = (int) xs->data; - thisphys = KVTOPHYS(thiskv); - - while (datalen && seg < UHA_NSEG) { - bytes_this_seg = 0; - - /* put in the base address */ - sg->seg_addr = thisphys; - - SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys)); - - /* do it at least once */ - nextphys = thisphys; - while (datalen && thisphys == nextphys) { - /* - * This page is contiguous (physically) - * with the the last, just extend the - * length - */ - /* how far to the end of the page */ - nextphys = (thisphys & ~PGOFSET) + NBPG; - bytes_this_page = nextphys - thisphys; - /**** or the data ****/ - bytes_this_page = min(bytes_this_page, - datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; - - /* get more ready for the next page */ - thiskv = (thiskv & ~PGOFSET) + NBPG; - if (datalen) - thisphys = KVTOPHYS(thiskv); - } - /* - * next page isn't contiguous, finish the seg - */ - SC_DEBUGN(sc_link, SDEV_DB4, - ("(0x%x)", bytes_this_seg)); - sg->seg_len = bytes_this_seg; - sg++; - seg++; - } + error = bus_dmamap_load(dmat, + mscp->dmamap_xfer, xs->data, xs->datalen, NULL, + (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : + BUS_DMA_WAITOK); } - /* end of iov/kv decision */ - SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); - if (datalen) { - /* - * there's still data, must have run out of segs! - */ - printf("%s: uha_scsi_cmd, more than %d dma segs\n", - sc->sc_dev.dv_xname, UHA_NSEG); + + if (error) { + if (error == EFBIG) { + printf("%s: uha_scsi_cmd, more than %d" + " dma segments\n", + sc->sc_dev.dv_xname, UHA_NSEG); + } else { + printf("%s: uha_scsi_cmd, error %d loading" + " dma map\n", + sc->sc_dev.dv_xname, error); + } goto bad; } - mscp->data_addr = KVTOPHYS(mscp->uha_dma); + + bus_dmamap_sync(dmat, mscp->dmamap_xfer, + (flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD : + BUS_DMASYNC_PREWRITE); + + /* + * Load the hardware scatter/gather map with the + * contents of the DMA map. + */ + for (seg = 0; seg < mscp->dmamap_xfer->dm_nsegs; seg++) { + mscp->uha_dma[seg].seg_addr = + mscp->dmamap_xfer->dm_segs[seg].ds_addr; + mscp->uha_dma[seg].seg_len = + mscp->dmamap_xfer->dm_segs[seg].ds_len; + } + + mscp->data_addr = mscp->dmamap_self->dm_segs[0].ds_addr + + offsetof(struct uha_mscp, uha_dma); mscp->data_length = xs->datalen; mscp->sgth = 0x01; mscp->sg_num = seg; diff --git a/sys/dev/ic/uhareg.h b/sys/dev/ic/uhareg.h index d115bea3b3bf..7e035d6d4ce4 100644 --- a/sys/dev/ic/uhareg.h +++ b/sys/dev/ic/uhareg.h @@ -1,4 +1,41 @@ -/* $NetBSD: uhareg.h,v 1.2 1996/09/01 00:54:41 mycroft Exp $ */ +/* $NetBSD: uhareg.h,v 1.3 1997/06/06 23:31:06 thorpej Exp $ */ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ /* * Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved. @@ -226,6 +263,24 @@ struct uha_mscp { #define MSCP_ALLOC 0x01 #define MSCP_ABORT 0x02 int timeout; + + /* + * DMA maps used by the MSCP. These maps are created + * in uha_init_mscp(). + */ + + /* + * This DMA map maps an individual MSCP. This map is + * permanently loaded in uha_init_mscp(). + */ + bus_dmamap_t dmamap_self; + + /* + * This DMA map maps the buffer involved in the transfer. + * It's contents are loaded into "uha_dma" above. + */ + bus_dmamap_t dmamap_xfer; + }; #pragma pack(4) diff --git a/sys/dev/ic/uhavar.h b/sys/dev/ic/uhavar.h index 0a266835e767..63188530b2ae 100644 --- a/sys/dev/ic/uhavar.h +++ b/sys/dev/ic/uhavar.h @@ -1,4 +1,4 @@ -/* $NetBSD: uhavar.h,v 1.4 1997/03/29 02:32:32 mycroft Exp $ */ +/* $NetBSD: uhavar.h,v 1.5 1997/06/06 23:31:07 thorpej Exp $ */ /* * Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved. @@ -39,8 +39,11 @@ struct uha_softc { bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; + bus_dma_tag_t sc_dmat; void *sc_ih; + int sc_dmaflags; /* bus-specific DMA map creation flags */ + void (*start_mbox) __P((struct uha_softc *, struct uha_mscp *)); int (*poll) __P((struct uha_softc *, struct scsi_xfer *, int)); void (*init) __P((struct uha_softc *));