-/* $OpenBSD: isa_machdep.c,v 1.12 1996/04/21 22:16:54 deraadt Exp $ */
+/* $OpenBSD: isa_machdep.c,v 1.13 1996/04/22 20:03:07 hannken Exp $ */
/* $NetBSD: isa_machdep.c,v 1.12 1996/04/11 22:11:32 cgd Exp $ */
/*-
static int bit_ptr = -1; /* last segment visited */
static int chunk_size = 0; /* size (bytes) of one low mem segment */
static int chunk_num = 0; /* actual number of low mem segments */
+#ifdef DIAGNOSTIC
+int bounce_alloc_cur = 0;
+int bounce_alloc_max = 0;
+#endif
vm_offset_t isaphysmem; /* base address of low mem arena */
int isaphysmempgs; /* number of pages of low mem arena */
/*
- * check if addr is from our low mem arena
+ * if addr is the physical address of an allocated bounce buffer return the
+ * corresponding virtual address, 0 otherwise
*/
-static int
-bounce_isbounced(addr)
+static caddr_t
+bounce_vaddr(addr)
vm_offset_t addr;
{
- return(addr >= vtophys(isaphysmem) &&
- addr < vtophys(isaphysmem)+isaphysmempgs*NBPG);
-}
+ int i;
-/*
- * return the virtual address of addr. addr must be from low mem arena
- */
+ if (addr < vtophys(isaphysmem) ||
+ addr >= vtophys(isaphysmem + chunk_num*chunk_size) ||
+ ((i = (int)(addr-vtophys(isaphysmem))) % chunk_size) != 0 ||
+ bit(i/chunk_size))
+ return(0);
-static caddr_t
-bounce_to_virt(addr)
- vm_offset_t addr;
-{
- return((caddr_t)(isaphysmem+(addr-vtophys(isaphysmem))));
+ return((caddr_t) (isaphysmem + (addr - vtophys(isaphysmem))));
}
/*
l = -1;
do{
if (bit(i) && l >= 0 && (i - l + 1) >= nunits){
- r = vtophys(isaphysmem+(i-nunits+1)*chunk_size);
- if (((r ^ (r+nbytes-1)) & pmask) == 0) {
+ r = vtophys(isaphysmem + (i - nunits + 1)*chunk_size);
+ if (((r ^ (r + nbytes - 1)) & pmask) == 0) {
for (l = i - nunits + 1; l <= i; l++)
clr(l);
bit_ptr = i;
+#ifdef DIAGNOSTIC
+ bounce_alloc_cur += nunits*chunk_size;
+ bounce_alloc_max = max(bounce_alloc_max,
+ bounce_alloc_cur);
+#endif
splx(opri);
return(r);
}
opri = splbio();
- vaddr = (vm_offset_t)bounce_to_virt(addr);
- if (vaddr < isaphysmem || vaddr >= isaphysmem+chunk_num*chunk_size ||
- ((i = (int)(vaddr-isaphysmem)) % chunk_size) != 0)
+ if ((vaddr = (vm_offset_t) bounce_vaddr(addr)) == 0)
panic("bounce_free: bad address");
- i /= chunk_size;
- j = i + (nbytes+chunk_size-1)/chunk_size;
+ i = (int) (vaddr - isaphysmem)/chunk_size;
+ j = i + (nbytes + chunk_size - 1)/chunk_size;
+
+#ifdef DIAGNOSTIC
+ bounce_alloc_cur -= (j - i)*chunk_size;
+#endif
while (i < j) {
if (bit(i))
i++;
}
- wakeup((caddr_t)&bit_ptr);
+ wakeup((caddr_t) &bit_ptr);
splx(opri);
}
/*
- * setup (addr,nbytes) for an ISA dma transfer.
+ * setup (addr, nbytes) for an ISA dma transfer.
* flags&ISADMA_MAP_WAITOK may wait
* flags&ISADMA_MAP_BOUNCE may use a bounce buffer if necessary
* flags&ISADMA_MAP_CONTIG result must be physically contiguous
int seg, waitok, i;
if (flags & ISADMA_MAP_8BIT)
- pmask = ~((64*1024)-1);
+ pmask = ~((64*1024) - 1);
else if (flags & ISADMA_MAP_16BIT)
- pmask = ~((128*1024)-1);
+ pmask = ~((128*1024) - 1);
else
pmask = 0;
waitok = (flags & ISADMA_MAP_WAITOK) != 0;
- thiskv = (vm_offset_t)addr;
+ thiskv = (vm_offset_t) addr;
datalen = nbytes;
thisphys = vtophys(thiskv);
seg = 0;
while (datalen > 0 && (seg == 0 || (flags & ISADMA_MAP_CONTIG) == 0)) {
- if (thisphys == 0)
- panic("isadma_map: no physical page present");
-
phys[seg].length = 0;
phys[seg].addr = thisphys;
nextphys = thisphys;
while (datalen > 0 && thisphys == nextphys) {
nextphys = trunc_page(thisphys) + NBPG;
- phys[seg].length += min(nextphys-thisphys, datalen);
- datalen -= min(nextphys-thisphys, datalen);
+ phys[seg].length += min(nextphys - thisphys, datalen);
+ datalen -= min(nextphys - thisphys, datalen);
thiskv = trunc_page(thiskv) + NBPG;
if (datalen)
thisphys = vtophys(thiskv);
}
- if (phys[seg].addr+phys[seg].length > 0xffffff) {
+ if (phys[seg].addr + phys[seg].length > 0xffffff) {
if (flags & ISADMA_MAP_CONTIG) {
phys[seg].length = nbytes;
datalen = 0;
if ((flags & ISADMA_MAP_BOUNCE) == 0)
phys[seg].addr = 0;
else
- phys[seg].addr =
- bounce_alloc(phys[seg].length, pmask,
- waitok);
+ phys[seg].addr = bounce_alloc(phys[seg].length,
+ pmask, waitok);
if (phys[seg].addr == 0) {
for (i = 0; i < seg; i++)
- if (bounce_isbounced(phys[i].addr))
+ if (bounce_vaddr(phys[i].addr))
bounce_free(phys[i].addr,
phys[i].length);
return 0;
/* check all constraints */
if (datalen ||
- ((phys[0].addr ^ (phys[0].addr+phys[0].length-1)) & pmask) != 0 ||
+ ((phys[0].addr ^ (phys[0].addr + phys[0].length - 1)) & pmask) != 0 ||
((phys[0].addr & 1) && (flags & ISADMA_MAP_16BIT))) {
if ((flags & ISADMA_MAP_BOUNCE) == 0)
return 0;
int i;
for (i = 0; i < nphys; i++)
- if (bounce_isbounced(phys[i].addr))
+ if (bounce_vaddr(phys[i].addr))
bounce_free(phys[i].addr, phys[i].length);
}
struct isadma_seg *phys;
{
int i;
+ caddr_t vaddr;
for (i = 0; i < nphys; i++) {
- if (bounce_isbounced(phys[i].addr)) {
- bcopy(bounce_to_virt(phys[i].addr), addr,
- phys[i].length);
- }
+ if (vaddr = bounce_vaddr(phys[i].addr))
+ bcopy(vaddr, addr, phys[i].length);
addr += phys[i].length;
}
}
struct isadma_seg *phys;
{
int i;
+ caddr_t vaddr;
for (i = 0; i < nphys; i++) {
- if (bounce_isbounced(phys[i].addr)) {
- bcopy(addr, bounce_to_virt(phys[i].addr),
- phys[i].length);
- }
+ if (vaddr = bounce_vaddr(phys[i].addr))
+ bcopy(addr, vaddr, phys[i].length);
addr += phys[i].length;
}
}
+/* $OpenBSD: aha.c,v 1.15 1996/04/22 20:03:02 hannken Exp $ */
/* $NetBSD: aha.c,v 1.7 1996/04/11 22:27:59 cgd Exp $ */
#define AHADIAG
#define Debugger() panic("should call debugger here (aha1542.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 aha_softc to fit on a single page..
struct aha_mbx_in *tmbi; /* Target Mail Box in */
};
-#define KVTOPHYS(x) vtophys(x)
-
struct aha_softc {
struct device sc_dev;
struct isadev sc_id;
sc->sc_iobase = ia->ia_iobase;
if (sc->sc_drq != DRQUNK)
- isa_dmacascade(sc->sc_drq);
+ isadma_cascade(sc->sc_drq);
aha_inquire_setup_information(sc);
aha_init(sc);
isa_establish(&sc->sc_id, &sc->sc_dev);
#endif
sc->sc_ih = isa_intr_establish(ia->ia_ic, sc->sc_irq, IST_EDGE,
- IPL_BIO, ahaintr, sc);
+ IPL_BIO, ahaintr, sc, sc->sc_dev.dv_xname);
/*
* ask the adapter what subunits are present
struct aha_softc *sc;
struct aha_ccb *ccb;
{
- int s;
+ int s, hashnum;
+ struct aha_ccb **hashccb;
s = splbio();
+ if (ccb->ccb_phys[0].addr)
+ isadma_unmap((caddr_t)ccb, CCB_PHYS_SIZE, 1, ccb->ccb_phys);
+
+ /* remove from hash table */
+
+ hashnum = CCB_HASH(ccb->ccb_phys[0].addr);
+ hashccb = &sc->sc_ccbhash[hashnum];
+
+ while (*hashccb) {
+ if ((*hashccb)->ccb_phys[0].addr == ccb->ccb_phys[0].addr) {
+ *hashccb = (*hashccb)->nexthash;
+ break;
+ }
+ hashccb = &(*hashccb)->nexthash;
+ }
+
aha_reset_ccb(sc, ccb);
TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, chain);
struct aha_softc *sc;
struct aha_ccb *ccb;
{
- int hashnum;
-
bzero(ccb, sizeof(struct aha_ccb));
- /*
- * put in the phystokv hash table
- * Never gets taken out.
- */
- ccb->hashkey = KVTOPHYS(ccb);
- hashnum = CCB_HASH(ccb->hashkey);
- ccb->nexthash = sc->sc_ccbhash[hashnum];
- sc->sc_ccbhash[hashnum] = ccb;
aha_reset_ccb(sc, ccb);
}
int flags;
{
struct aha_ccb *ccb;
- int s;
+ int hashnum, mflags, s;
s = splbio();
+ if (flags & SCSI_NOSLEEP)
+ mflags = ISADMA_MAP_BOUNCE;
+ else
+ mflags = ISADMA_MAP_BOUNCE | ISADMA_MAP_WAITOK;
+
/*
* If we can and have to, sleep waiting for one to come free
* but only if we can't allocate a new one.
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;
+ aha_free_ccb(sc, ccb);
+ ccb = 0;
+ }
+
out:
splx(s);
return (ccb);
struct aha_ccb *ccb = sc->sc_ccbhash[hashnum];
while (ccb) {
- if (ccb->hashkey == ccb_phys)
+ if (ccb->ccb_phys[0].addr == ccb_phys)
break;
ccb = ccb->nexthash;
}
#ifdef AHADIAG
ccb = aha_ccb_phys_kv(sc, phystol(wmbo->ccb_addr));
- ccb->flags &= ~CCB_SENDING;
+ if (!ccb) {
+ printf("%s: bad mbo ccb pointer; skipping\n",
+ sc->sc_dev.dv_xname);
+ } else
+ ccb->flags &= ~CCB_SENDING;
#endif
--sc->sc_mbofull;
#endif
/* Link ccb to mbo. */
- ltophys(KVTOPHYS(ccb), wmbo->ccb_addr);
+ ltophys(ccb->ccb_phys[0].addr, wmbo->ccb_addr);
if (ccb->flags & CCB_ABORT)
wmbo->cmd = AHA_MBO_ABORT;
else
} else
xs->resid = 0;
}
- aha_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);
+ }
+ aha_free_ccb(sc, ccb);
scsi_done(xs);
}
struct aha_devices devices;
struct aha_setup setup;
struct aha_mailbox mailbox;
+ struct isadma_seg mbx_phys[1];
int i;
/*
/* Initialize mail box. */
mailbox.cmd.opcode = AHA_MBX_INIT;
mailbox.cmd.nmbx = AHA_MBX_SIZE;
- ltophys(KVTOPHYS(wmbx), mailbox.cmd.addr);
+ if (isadma_map((caddr_t)(wmbx), sizeof(struct aha_mbx),
+ mbx_phys, ISADMA_MAP_CONTIG) != 1)
+ panic("aha_init: cannot map mail box");
+ ltophys(mbx_phys[0].addr, mailbox.cmd.addr);
aha_cmd(iobase, sc, sizeof(mailbox.cmd), (u_char *)&mailbox.cmd,
0, (u_char *)0);
}
struct aha_softc *sc = sc_link->adapter_softc;
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;
+ int seg, datalen, flags, mflags;
struct iovec *iovp;
int s;
* then we can't allow it to sleep
*/
flags = xs->flags;
+ if (flags & SCSI_NOSLEEP)
+ mflags = ISADMA_MAP_BOUNCE;
+ else
+ mflags = ISADMA_MAP_BOUNCE | ISADMA_MAP_WAITOK;
if ((ccb = aha_get_ccb(sc, flags)) == NULL) {
xs->error = XS_DRIVER_STUFFUP;
return TRY_AGAIN_LATER;
/*
* 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++;
+ 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: aha_scsi_cmd, more than %d dma segs\n",
- sc->sc_dev.dv_xname, AHA_NSEG);
+ if (ccb->data_nseg == 0) {
+ printf("%s: aha_scsi_cmd, cannot map\n",
+ sc->sc_dev.dv_xname);
goto bad;
- }
- ltophys(KVTOPHYS(ccb->scat_gath), ccb->data_addr);
- ltophys(seg * sizeof(struct aha_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 aha_ccb *)(ccb->ccb_phys[0].addr))->scat_gath,
+ ccb->data_addr);
+ ltophys(ccb->data_nseg * 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);
* 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, "ahawait", 0);
+ }
+ splx(s);
+ 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);
+ }
+ aha_free_ccb(sc, ccb);
+ scsi_done(xs);
+ return COMPLETE;
+ }
+
if ((flags & SCSI_POLL) == 0)
return SUCCESSFULLY_QUEUED;