diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1997-01-03 22:39:36 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1997-01-03 22:39:36 +0000 |
commit | 3f954a6d529cb6b63a5a0510f6c949cd6fab32ce (patch) | |
tree | ac69d006508f562ae27bc1d542c7a61643b3d89f /sys | |
parent | a07e8cc3030f8743a5d3b39bd97994fb54aa76fb (diff) |
make bounce buffer aware
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/isa/bt.c | 203 | ||||
-rw-r--r-- | sys/dev/isa/btreg.h | 4 |
2 files changed, 135 insertions, 72 deletions
diff --git a/sys/dev/isa/bt.c b/sys/dev/isa/bt.c index 222bdf4a446..8820f0eee8d 100644 --- a/sys/dev/isa/bt.c +++ b/sys/dev/isa/bt.c @@ -73,6 +73,18 @@ #define Debugger() panic("should call debugger here (bt742a.c)") #endif /* ! DDB */ +/* XXX fixme: + * on i386 at least, xfers to/from user memory + * cannot be serviced at interrupt time. + */ +#ifdef i386 +#define VOLATILE_XS(xs) \ + ((xs)->datalen > 0 && (xs)->bp == NULL && \ + ((xs)->flags & SCSI_POLL) == 0) +#else +#define VOLATILE_XS(xs) 0 +#endif + /* * Mail box defs etc. * these could be bigger but we need the bt_softc to fit on a single page.. @@ -115,8 +127,9 @@ struct bt_softc { int sc_iobase; int sc_irq, sc_drq; - char sc_model[7], - sc_firmware[6]; + char sc_model[7]; + char sc_firmware[6]; + char sc_version[2]; struct bt_mbx sc_mbx; /* all our mailboxes */ #define wmbx (&sc->sc_mbx) @@ -125,6 +138,7 @@ struct bt_softc { int sc_numccbs, sc_mbofull; int sc_scsi_dev; /* adapters scsi id */ struct scsi_link sc_link; /* prototype for devs */ + int sc_needbounce; }; #ifdef BTDEBUG @@ -474,6 +488,8 @@ AGAIN: } untimeout(bt_timeout, ccb); + isadma_copyfrombuf((caddr_t)ccb, CCB_PHYS_SIZE, + 1, ccb->ccb_phys); bt_done(sc, ccb); next: @@ -552,6 +568,9 @@ bt_free_ccb(sc, ccb) s = splbio(); + if (ccb->ccb_phys[0].addr) + isadma_unmap((caddr_t)ccb, CCB_PHYS_SIZE, 1, ccb->ccb_phys); + bt_reset_ccb(sc, ccb); TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, chain); @@ -596,10 +615,17 @@ bt_get_ccb(sc, flags) int flags; { struct bt_ccb *ccb; - int s; + int hashnum, mflags, s; s = splbio(); + if (sc->sc_needbounce) { + if (flags & SCSI_NOSLEEP) + mflags = ISADMA_MAP_BOUNCE; + else + mflags = ISADMA_MAP_BOUNCE | ISADMA_MAP_WAITOK; + } else + mflags = 0; /* * If we can and have to, sleep waiting for one to come free * but only if we can't allocate a new one. @@ -629,6 +655,17 @@ bt_get_ccb(sc, flags) ccb->flags |= CCB_ALLOC; + if (isadma_map((caddr_t)ccb, CCB_PHYS_SIZE, ccb->ccb_phys, + mflags | ISADMA_MAP_CONTIG) == 1) { + hashnum = CCB_HASH(ccb->ccb_phys[0].addr); + ccb->nexthash = sc->sc_ccbhash[hashnum]; + sc->sc_ccbhash[hashnum] = ccb; + } else { + ccb->ccb_phys[0].addr = 0; + bt_free_ccb(sc, ccb); + ccb = 0; + } + out: splx(s); return ccb; @@ -728,7 +765,9 @@ bt_start_ccbs(sc) #endif /* Link ccb to mbo. */ - ltophys(KVTOPHYS(ccb), wmbo->ccb_addr); + isadma_copytobuf((caddr_t)ccb, CCB_PHYS_SIZE, + 1, ccb->ccb_phys); + ltophys(ccb->ccb_phys[0].addr, wmbo->ccb_addr); if (ccb->flags & CCB_ABORT) wmbo->cmd = BT_MBO_ABORT; else @@ -809,8 +848,21 @@ bt_done(sc, ccb) } else xs->resid = 0; } - bt_free_ccb(sc, ccb); xs->flags |= ITSDONE; + + if (VOLATILE_XS(xs)) { + wakeup(ccb); + return; + } + + if (ccb->data_nseg) { + if (xs->flags & SCSI_DATA_IN) + isadma_copyfrombuf(xs->data, xs->datalen, + ccb->data_nseg, ccb->data_phys); + isadma_unmap(xs->data, xs->datalen, + ccb->data_nseg, ccb->data_phys); + } + bt_free_ccb(sc, ccb); scsi_done(xs); } @@ -865,6 +917,8 @@ bt_find(ia, sc) sizeof(inquire.reply), (u_char *)&inquire.reply); switch (inquire.reply.bus_type) { case BT_BUS_TYPE_24BIT: + sc->sc_needbounce = 1; + break; case BT_BUS_TYPE_32BIT: break; case BT_BUS_TYPE_MCA: @@ -977,6 +1031,7 @@ bt_init(sc) struct bt_setup setup; struct bt_mailbox mailbox; struct bt_period period; + struct isadma_seg mbx_phys[1]; int i; /* Enable round-robin scheme - appeared at firmware rev. 3.31. */ @@ -1038,9 +1093,18 @@ bt_init(sc) /* Initialize mail box. */ mailbox.cmd.opcode = BT_MBX_INIT_EXTENDED; mailbox.cmd.nmbx = BT_MBX_SIZE; - ltophys(KVTOPHYS(wmbx), mailbox.cmd.addr); + if (isadma_map((caddr_t)(wmbx), sizeof(struct bt_mbx), + mbx_phys, ISADMA_MAP_CONTIG) != 1) + panic("bt_init: cannot map mail box"); + ltophys(mbx_phys[0].addr, mailbox.cmd.addr); bt_cmd(iobase, sc, sizeof(mailbox.cmd), (u_char *)&mailbox.cmd, 0, (u_char *)0); + + /* deal with buggy boards */ + if ((sc->sc_model[0] == '4' && sc->sc_model[1] == '4' && + sc->sc_model[2] == '5' && sc->sc_model[3] == 'S') || + sc->sc_version[0] == '5') + sc->sc_needbounce = 1; } void @@ -1098,6 +1162,8 @@ bt_inquire_setup_information(sc) while (p > sc->sc_model && (p[-1] == ' ' || p[-1] == '\0')) p--; *p = '\0'; + bcopy(model.reply.version, sc->sc_version, + sizeof sc->sc_version); } else strcpy(sc->sc_model, "542B"); @@ -1127,8 +1193,7 @@ bt_scsi_cmd(xs) struct bt_ccb *ccb; struct bt_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; + int flags, mflags; #ifdef TFS struct iovec *iovp; #endif @@ -1141,6 +1206,13 @@ bt_scsi_cmd(xs) * then we can't allow it to sleep */ flags = xs->flags; + if (sc->sc_needbounce) { + if (flags & SCSI_NOSLEEP) + mflags = ISADMA_MAP_BOUNCE; + else + mflags = ISADMA_MAP_BOUNCE | ISADMA_MAP_WAITOK; + } else + mflags = 0; if ((ccb = bt_get_ccb(sc, flags)) == NULL) { xs->error = XS_DRIVER_STUFFUP; return TRY_AGAIN_LATER; @@ -1183,69 +1255,32 @@ bt_scsi_cmd(xs) } } 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 < BT_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++; - } + /* + * Set up the scatter-gather block. + */ + SC_DEBUG(sc_link, SDEV_DB4, + ("%d @0x%x:- ", xs->datalen, xs->data)); + + ccb->data_nseg = isadma_map(xs->data, xs->datalen, + ccb->data_phys, mflags); + for (seg = 0; seg < ccb->data_nseg; seg++) { + ltophys(ccb->data_phys[seg].addr, + sg[seg].seg_addr); + ltophys(ccb->data_phys[seg].length, + sg[seg].seg_len); } /* 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: bt_scsi_cmd, more than %d dma segs\n", - sc->sc_dev.dv_xname, BT_NSEG); + if (ccb->data_nseg == 0) { + printf("%s: bt_scsi_cmd, cannot map\n", + sc->sc_dev.dv_xname); goto bad; - } - ltophys(KVTOPHYS(ccb->scat_gath), ccb->data_addr); - ltophys(seg * sizeof(struct bt_scat_gath), ccb->data_length); + } else if (flags & SCSI_DATA_OUT) + isadma_copytobuf(xs->data, xs->datalen, + ccb->data_nseg, ccb->data_phys); + ltophys((unsigned)((struct bt_ccb *)(ccb->ccb_phys[0].addr))->scat_gath, + ccb->data_addr); + ltophys(ccb->data_nseg * sizeof(struct bt_scat_gath), + ccb->data_length); } else { /* No data xfer, use non S/G values */ ltophys(0, ccb->data_addr); ltophys(0, ccb->data_length); @@ -1264,12 +1299,30 @@ bt_scsi_cmd(xs) s = splbio(); bt_queue_ccb(sc, ccb); - splx(s); /* * Usually return SUCCESSFULLY QUEUED */ SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n")); + + if (VOLATILE_XS(xs)) { + while ((ccb->xs->flags & ITSDONE) == 0) { + tsleep(ccb, PRIBIO, "btwait", 0); + } + if (ccb->data_nseg) { + if (flags & SCSI_DATA_IN) + isadma_copyfrombuf(xs->data, xs->datalen, + ccb->data_nseg, ccb->data_phys); + isadma_unmap(xs->data, xs->datalen, + ccb->data_nseg, ccb->data_phys); + } + bt_free_ccb(sc, ccb); + scsi_done(xs); + splx(s); + return COMPLETE; + } + splx(s); + if ((flags & SCSI_POLL) == 0) return SUCCESSFULLY_QUEUED; @@ -1321,11 +1374,17 @@ bt_timeout(arg) void *arg; { struct bt_ccb *ccb = arg; - struct scsi_xfer *xs = ccb->xs; - struct scsi_link *sc_link = xs->sc_link; - struct bt_softc *sc = sc_link->adapter_softc; + struct scsi_xfer *xs; + struct scsi_link *sc_link; + struct bt_softc *sc; int s; + s = splbio(); + isadma_copyfrombuf((caddr_t)ccb, CCB_PHYS_SIZE, 1, ccb->ccb_phys); + xs = ccb->xs; + sc_link = xs->sc_link; + sc = sc_link->adapter_softc; + sc_print_addr(sc_link); printf("timed out"); diff --git a/sys/dev/isa/btreg.h b/sys/dev/isa/btreg.h index 5bb6c9b9d30..7b4c46e72f0 100644 --- a/sys/dev/isa/btreg.h +++ b/sys/dev/isa/btreg.h @@ -139,6 +139,7 @@ struct bt_ccb { /*------------------------------------longword boundary */ struct bt_scat_gath scat_gath[BT_NSEG]; /*------------------------------------longword boundary */ +#define CCB_PHYS_SIZE ((int)&((struct bt_ccb *)0)->chain) TAILQ_ENTRY(bt_ccb) chain; struct bt_ccb *nexthash; long hashkey; @@ -150,6 +151,9 @@ struct bt_ccb { #define CCB_SENDING 0x04 #endif int timeout; + struct isadma_seg ccb_phys[1]; /* phys segment of this ccb */ + struct isadma_seg data_phys[BT_NSEG]; /* phys segments of data */ + int data_nseg; /* number of phys segments of data */ }; /* |