ultra14f does not bounce properly yet.
/* $NetBSD: aha1542.c,v 1.53 1995/10/03 20:58:56 mycroft Exp $ */
-
/*
* Copyright (c) 1994 Charles Hannum. All rights reserved.
*
#include <sys/types.h>
#include <sys/param.h>
+#include <sys/syslog.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/errno.h>
#include <machine/pio.h>
#include <dev/isa/isavar.h>
+#include <dev/isa/isadmavar.h>
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#define Debugger() panic("should call debugger here (aha1542.c)")
#endif /* ! DDB */
+/* XXX fixme: */
+/* on i386 at least xfers from/to user memory */
+/* cannot be serviced at interrupt time. */
+#ifdef i386
+#include <machine/vmparam.h>
+#define VOLATILE_XS(xs) \
+ ((xs)->datalen > 0 && \
+ ((vm_offset_t)((xs)->data) < VM_MIN_KERNEL_ADDRESS) && \
+ ((xs)->flags & SCSI_POLL) == 0)
+#else
+#define VOLATILE_XS(xs) 0
+#endif
+
+#undef TUNE_1542 /* if bus speed check breaks the machine, undefine it */
+
/************************** board definitions *******************************/
/*
/* FOR OLD VERSIONS OF THE !%$@ this may have to be 16 (yuk) */
#define AHA_NSEG 17 /* Number of scatter gather segments <= 16 */
- /* allow 64 K i/o (min) */
+ /* allow 60 K i/o (min) */
struct aha_ccb {
u_char opcode;
u_char seg_len[3];
u_char seg_addr[3];
} scat_gath[AHA_NSEG];
+#define CCB_PHYS_SIZE ((int)&((struct aha_ccb *)0)->chain)
/*----------------------------------------------------------------*/
TAILQ_ENTRY(aha_ccb) chain;
struct aha_ccb *nexthash;
- long hashkey;
struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
int flags;
#define CCB_FREE 0
#define CCB_ACTIVE 1
#define CCB_ABORTED 2
struct aha_mbx_out *mbx; /* pointer to mail box */
+ struct isadma_seg ccb_phys[1]; /* phys segment of this ccb */
+ struct isadma_seg data_phys[AHA_NSEG]; /* phys segments of data */
+ int data_nseg;
};
/*
/*********************************** end of board definitions***************/
-#define KVTOPHYS(x) vtophys(x)
-
#ifdef AHADEBUG
int aha_debug = 1;
#endif /*AHADEBUG */
void *aux;
char *name;
{
- if (name != NULL)
+ if (name != NULL)
printf("%s: scsibus ", name);
return UNCONF;
}
struct aha_softc *aha = (void *)self;
if (ia->ia_drq != DRQUNK)
- isa_dmacascade(ia->ia_drq);
+ isadma_cascade(ia->ia_drq);
aha_init(aha);
TAILQ_INIT(&aha->free_ccb);
s = splbio();
+ if (ccb->ccb_phys[0].addr)
+ isadma_unmap((caddr_t)ccb, CCB_PHYS_SIZE, 1, ccb->ccb_phys);
+
ccb->flags = CCB_FREE;
TAILQ_INSERT_HEAD(&aha->free_ccb, ccb, chain);
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 = aha->ccbhash[hashnum];
- aha->ccbhash[hashnum] = ccb;
}
static inline void
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
aha_reset_ccb(aha, ccb);
ccb->flags = CCB_ACTIVE;
+ 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 = aha->ccbhash[hashnum];
+ aha->ccbhash[hashnum] = ccb;
+ } else {
+ ccb->ccb_phys[0].addr = 0;
+ aha_free_ccb(aha, ccb, flags);
+ ccb = 0;
+ }
+
out:
splx(s);
return (ccb);
u_long ccb_phys;
{
int hashnum = CCB_HASH(ccb_phys);
- struct aha_ccb *ccb = aha->ccbhash[hashnum];
+ struct aha_ccb *res, **ccb = &aha->ccbhash[hashnum];
- while (ccb) {
- if (ccb->hashkey == ccb_phys)
+ while (*ccb) {
+ if ((*ccb)->ccb_phys[0].addr == ccb_phys)
break;
- ccb = ccb->nexthash;
+ (*ccb) = (*ccb)->nexthash;
}
- return ccb;
+
+ if (res = *ccb)
+ *ccb = (*ccb)->nexthash;
+
+ return res;
}
/*
}
/* Link ccb to mbo. */
- lto3b(KVTOPHYS(ccb), wmbo->ccb_addr);
+ lto3b(ccb->ccb_phys[0].addr, wmbo->ccb_addr);
ccb->mbx = wmbo;
wmbo->cmd = cmd;
xs->resid = 0;
}
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(aha, ccb, xs->flags);
scsi_done(xs);
}
aha_find(aha)
struct aha_softc *aha;
{
- u_char ad[3];
volatile int i, sts;
struct aha_config conf;
struct aha_inquire inquire;
aha_cmd(aha, 1, 0, 0, 0, AHA_BUS_ON_TIME_SET, 7);
aha_cmd(aha, 1, 0, 0, 0, AHA_BUS_OFF_TIME_SET, 4);
-#ifdef TUNE_1542
-#error XXX Must deal with configuring the DRQ channel if we do this.
- /*
- * Initialize memory transfer speed
- * Not compiled in by default because it breaks some machines
- */
- if (!aha_set_bus_speed(aha))
- return EIO;
-#endif /* TUNE_1542 */
-
return 0;
}
struct aha_softc *aha;
{
u_char ad[3];
+ struct isadma_seg mbx_phys[1];
int i;
+#ifdef TUNE_1542
/*
- * Initialize mail box
+ * Initialize memory transfer speed
+ * Not compiled in by default because it breaks some machines
+ */
+ if (!aha_set_bus_speed(aha))
+ panic("aha_init: cannot set bus speed");
+#endif /* TUNE_1542 */
+
+ /*
+ * Initialize mail box. This mapping will never be undone.
*/
- lto3b(KVTOPHYS(&aha->aha_mbx), ad);
+ if (isadma_map((caddr_t)(&aha->aha_mbx), sizeof(struct aha_mbx),
+ mbx_phys, ISADMA_MAP_CONTIG) != 1)
+ panic("aha_init: cannot map mail box");
+ lto3b(mbx_phys[0].addr, ad);
aha_cmd(aha, 4, 0, 0, 0, AHA_MBX_INIT, AHA_MBX_SIZE,
ad[0], ad[1], ad[2]);
struct aha_softc *aha = sc_link->adapter_softc;
struct aha_ccb *ccb;
struct aha_scat_gath *sg;
- int seg; /* scatter gather seg being worked on */
- int thiskv;
- u_long thisphys, nextphys;
- int bytes_this_seg, bytes_this_page, datalen, flags;
+ int seg, datalen, flags, mflags;
struct iovec *iovp;
struct aha_mbx_out *mbo;
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 ((flags & (ITSDONE|INUSE)) != INUSE) {
printf("%s: done or not in use?\n", aha->sc_dev.dv_xname);
xs->flags &= ~ITSDONE;
ccb->req_sense_length = sizeof(ccb->scsi_sense);
ccb->host_stat = 0x00;
ccb->target_stat = 0x00;
+ ccb->data_nseg = 0;
if (xs->datalen && (flags & SCSI_RESET) == 0) {
- lto3b(KVTOPHYS(ccb->scat_gath), ccb->data_addr);
+ sg = ((struct aha_ccb *)(ccb->ccb_phys[0].addr))->scat_gath;
+ lto3b((vm_offset_t)sg, ccb->data_addr);
sg = ccb->scat_gath;
seg = 0;
#ifdef 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 < AHA_NSEG) {
- bytes_this_seg = 0;
-
- /* put in the base address */
- lto3b(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",
- aha->sc_dev.dv_xname);
- xs->error = XS_DRIVER_STUFFUP;
- aha_free_ccb(aha, ccb, flags);
- return COMPLETE;
- }
- /** 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));
- lto3b(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++) {
+ lto3b(ccb->data_phys[seg].addr,
+ sg[seg].seg_addr);
+ lto3b(ccb->data_phys[seg].length,
+ sg[seg].seg_len);
}
}
- lto3b(seg * sizeof(struct aha_scat_gath), ccb->data_length);
- 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",
- aha->sc_dev.dv_xname, AHA_NSEG);
+ lto3b(ccb->data_nseg * sizeof(struct aha_scat_gath), ccb->data_length);
+ if (ccb->data_nseg == 0) {
+ printf("%s: aha_scsi_cmd, cannot map\n",
+ aha->sc_dev.dv_xname);
xs->error = XS_DRIVER_STUFFUP;
aha_free_ccb(aha, ccb, flags);
return COMPLETE;
- }
+ } else if (flags & SCSI_DATA_OUT)
+ isadma_copytobuf(xs->data, xs->datalen,
+ ccb->data_nseg, ccb->data_phys);
} else { /* No data xfer, use non S/G values */
lto3b(0, ccb->data_addr);
lto3b(0, ccb->data_length);
s = splbio();
+ isadma_copytobuf((caddr_t)ccb, CCB_PHYS_SIZE, 1, ccb->ccb_phys);
+
if (aha_send_mbo(aha, AHA_MBO_START, ccb) == NULL) {
splx(s);
xs->error = XS_DRIVER_STUFFUP;
+ if (ccb->data_nseg)
+ isadma_unmap(xs->data, xs->datalen,
+ ccb->data_nseg, ccb->data_phys);
aha_free_ccb(aha, ccb, flags);
return TRY_AGAIN_LATER;
}
* Usually return SUCCESSFULLY QUEUED
*/
SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n"));
+
+ if (VOLATILE_XS(xs)) {
+ if (tsleep(ccb, PRIBIO, "ahawait", (xs->timeout * hz) / 1000)) {
+ aha_timeout(ccb);
+ tsleep(ccb, PRIBIO, "ahawait1", 2000);
+ }
+ 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(aha, ccb, xs->flags);
+ scsi_done(xs);
+ return COMPLETE;
+ }
+
if ((flags & SCSI_POLL) == 0) {
timeout(aha_timeout, ccb, (xs->timeout * hz) / 1000);
splx(s);
lastworking = speed;
}
if (lastworking == -1) {
- printf("no working bus speed\n");
+ printf(" no working bus speed");
return 0;
}
- printf("%d nsec ", aha_bus_speeds[lastworking].nsecs);
+ printf(", %d nsec ", aha_bus_speeds[lastworking].nsecs);
if (lastworking == 7) /* is slowest already */
- printf("marginal\n");
+ printf("marginal");
else {
lastworking++;
- printf("ok, using %d nsec\n",
- aha_bus_speeds[lastworking].nsecs);
+ printf("ok, using %d nsec", aha_bus_speeds[lastworking].nsecs);
}
if (!aha_bus_speed_check(aha, lastworking)) {
- printf("test retry failed.. aborting.\n");
+ printf("test retry failed.. aborting.");
return 0;
}
return 1;
int speed;
{
int numspeeds = sizeof(aha_bus_speeds) / sizeof(struct bus_speed);
- int loopcount;
+ int result, loopcount;
+ struct isadma_seg test_phys[1], scratch_phys[1];
u_char ad[3];
+ result = 1;
+
+ if (isadma_map(aha_scratch_buf, sizeof(aha_scratch_buf),
+ scratch_phys, ISADMA_MAP_CONTIG) != 1)
+ return 0;
+ if (isadma_map(aha_test_string, sizeof(aha_test_string),
+ test_phys, ISADMA_MAP_CONTIG) != 1) {
+ isadma_unmap(aha_scratch_buf, sizeof(aha_scratch_buf),
+ 1, scratch_phys);
+ return 0;
+ }
+ isadma_copytobuf(aha_test_string, sizeof(aha_test_string),
+ 1, test_phys);
+
/*
* Set the dma-speed
*/
* it's address. Read it onto the board
*/
for (loopcount = 100; loopcount; loopcount--) {
- lto3b(KVTOPHYS(aha_test_string), ad);
+ lto3b(test_phys[0].addr, ad);
aha_cmd(aha, 3, 0, 0, 0, AHA_WRITE_FIFO, ad[0], ad[1], ad[2]);
/*
* board.
*/
bzero(aha_scratch_buf, 54);
+ isadma_copytobuf(aha_scratch_buf, sizeof(aha_scratch_buf),
+ 1, scratch_phys);
- lto3b(KVTOPHYS(aha_scratch_buf), ad);
+ lto3b(scratch_phys[0].addr, ad);
aha_cmd(aha, 3, 0, 0, 0, AHA_READ_FIFO, ad[0], ad[1], ad[2]);
+ isadma_copyfrombuf(aha_scratch_buf, sizeof(aha_scratch_buf),
+ 1, scratch_phys);
/*
* Compare the original data and the final data and return the
* first 54 bytes, because that's all the board copies during
* WRITE_FIFO and READ_FIFO.
*/
- if (bcmp(aha_test_string, aha_scratch_buf, 54))
- return 0; /* failed test */
+ if (bcmp(aha_test_string, aha_scratch_buf, 54)) {
+ result = 0; /* failed test */
+ break;
+ }
}
+ isadma_unmap(aha_scratch_buf, sizeof(aha_scratch_buf),
+ 1, scratch_phys);
+ isadma_unmap(aha_test_string, sizeof(aha_test_string),
+ 1, test_phys);
+
/* copy succeeded; assume speed ok */
- return 1;
+ return result;
}
#endif /* TUNE_1542 */
/* $NetBSD: aha1542.c,v 1.53 1995/10/03 20:58:56 mycroft Exp $ */
-
/*
* Copyright (c) 1994 Charles Hannum. All rights reserved.
*
#include <sys/types.h>
#include <sys/param.h>
+#include <sys/syslog.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/errno.h>
#include <machine/pio.h>
#include <dev/isa/isavar.h>
+#include <dev/isa/isadmavar.h>
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#define Debugger() panic("should call debugger here (aha1542.c)")
#endif /* ! DDB */
+/* XXX fixme: */
+/* on i386 at least xfers from/to user memory */
+/* cannot be serviced at interrupt time. */
+#ifdef i386
+#include <machine/vmparam.h>
+#define VOLATILE_XS(xs) \
+ ((xs)->datalen > 0 && \
+ ((vm_offset_t)((xs)->data) < VM_MIN_KERNEL_ADDRESS) && \
+ ((xs)->flags & SCSI_POLL) == 0)
+#else
+#define VOLATILE_XS(xs) 0
+#endif
+
+#undef TUNE_1542 /* if bus speed check breaks the machine, undefine it */
+
/************************** board definitions *******************************/
/*
/* FOR OLD VERSIONS OF THE !%$@ this may have to be 16 (yuk) */
#define AHA_NSEG 17 /* Number of scatter gather segments <= 16 */
- /* allow 64 K i/o (min) */
+ /* allow 60 K i/o (min) */
struct aha_ccb {
u_char opcode;
u_char seg_len[3];
u_char seg_addr[3];
} scat_gath[AHA_NSEG];
+#define CCB_PHYS_SIZE ((int)&((struct aha_ccb *)0)->chain)
/*----------------------------------------------------------------*/
TAILQ_ENTRY(aha_ccb) chain;
struct aha_ccb *nexthash;
- long hashkey;
struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
int flags;
#define CCB_FREE 0
#define CCB_ACTIVE 1
#define CCB_ABORTED 2
struct aha_mbx_out *mbx; /* pointer to mail box */
+ struct isadma_seg ccb_phys[1]; /* phys segment of this ccb */
+ struct isadma_seg data_phys[AHA_NSEG]; /* phys segments of data */
+ int data_nseg;
};
/*
/*********************************** end of board definitions***************/
-#define KVTOPHYS(x) vtophys(x)
-
#ifdef AHADEBUG
int aha_debug = 1;
#endif /*AHADEBUG */
void *aux;
char *name;
{
- if (name != NULL)
+ if (name != NULL)
printf("%s: scsibus ", name);
return UNCONF;
}
struct aha_softc *aha = (void *)self;
if (ia->ia_drq != DRQUNK)
- isa_dmacascade(ia->ia_drq);
+ isadma_cascade(ia->ia_drq);
aha_init(aha);
TAILQ_INIT(&aha->free_ccb);
s = splbio();
+ if (ccb->ccb_phys[0].addr)
+ isadma_unmap((caddr_t)ccb, CCB_PHYS_SIZE, 1, ccb->ccb_phys);
+
ccb->flags = CCB_FREE;
TAILQ_INSERT_HEAD(&aha->free_ccb, ccb, chain);
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 = aha->ccbhash[hashnum];
- aha->ccbhash[hashnum] = ccb;
}
static inline void
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
aha_reset_ccb(aha, ccb);
ccb->flags = CCB_ACTIVE;
+ 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 = aha->ccbhash[hashnum];
+ aha->ccbhash[hashnum] = ccb;
+ } else {
+ ccb->ccb_phys[0].addr = 0;
+ aha_free_ccb(aha, ccb, flags);
+ ccb = 0;
+ }
+
out:
splx(s);
return (ccb);
u_long ccb_phys;
{
int hashnum = CCB_HASH(ccb_phys);
- struct aha_ccb *ccb = aha->ccbhash[hashnum];
+ struct aha_ccb *res, **ccb = &aha->ccbhash[hashnum];
- while (ccb) {
- if (ccb->hashkey == ccb_phys)
+ while (*ccb) {
+ if ((*ccb)->ccb_phys[0].addr == ccb_phys)
break;
- ccb = ccb->nexthash;
+ (*ccb) = (*ccb)->nexthash;
}
- return ccb;
+
+ if (res = *ccb)
+ *ccb = (*ccb)->nexthash;
+
+ return res;
}
/*
}
/* Link ccb to mbo. */
- lto3b(KVTOPHYS(ccb), wmbo->ccb_addr);
+ lto3b(ccb->ccb_phys[0].addr, wmbo->ccb_addr);
ccb->mbx = wmbo;
wmbo->cmd = cmd;
xs->resid = 0;
}
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(aha, ccb, xs->flags);
scsi_done(xs);
}
aha_find(aha)
struct aha_softc *aha;
{
- u_char ad[3];
volatile int i, sts;
struct aha_config conf;
struct aha_inquire inquire;
aha_cmd(aha, 1, 0, 0, 0, AHA_BUS_ON_TIME_SET, 7);
aha_cmd(aha, 1, 0, 0, 0, AHA_BUS_OFF_TIME_SET, 4);
-#ifdef TUNE_1542
-#error XXX Must deal with configuring the DRQ channel if we do this.
- /*
- * Initialize memory transfer speed
- * Not compiled in by default because it breaks some machines
- */
- if (!aha_set_bus_speed(aha))
- return EIO;
-#endif /* TUNE_1542 */
-
return 0;
}
struct aha_softc *aha;
{
u_char ad[3];
+ struct isadma_seg mbx_phys[1];
int i;
+#ifdef TUNE_1542
/*
- * Initialize mail box
+ * Initialize memory transfer speed
+ * Not compiled in by default because it breaks some machines
+ */
+ if (!aha_set_bus_speed(aha))
+ panic("aha_init: cannot set bus speed");
+#endif /* TUNE_1542 */
+
+ /*
+ * Initialize mail box. This mapping will never be undone.
*/
- lto3b(KVTOPHYS(&aha->aha_mbx), ad);
+ if (isadma_map((caddr_t)(&aha->aha_mbx), sizeof(struct aha_mbx),
+ mbx_phys, ISADMA_MAP_CONTIG) != 1)
+ panic("aha_init: cannot map mail box");
+ lto3b(mbx_phys[0].addr, ad);
aha_cmd(aha, 4, 0, 0, 0, AHA_MBX_INIT, AHA_MBX_SIZE,
ad[0], ad[1], ad[2]);
struct aha_softc *aha = sc_link->adapter_softc;
struct aha_ccb *ccb;
struct aha_scat_gath *sg;
- int seg; /* scatter gather seg being worked on */
- int thiskv;
- u_long thisphys, nextphys;
- int bytes_this_seg, bytes_this_page, datalen, flags;
+ int seg, datalen, flags, mflags;
struct iovec *iovp;
struct aha_mbx_out *mbo;
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 ((flags & (ITSDONE|INUSE)) != INUSE) {
printf("%s: done or not in use?\n", aha->sc_dev.dv_xname);
xs->flags &= ~ITSDONE;
ccb->req_sense_length = sizeof(ccb->scsi_sense);
ccb->host_stat = 0x00;
ccb->target_stat = 0x00;
+ ccb->data_nseg = 0;
if (xs->datalen && (flags & SCSI_RESET) == 0) {
- lto3b(KVTOPHYS(ccb->scat_gath), ccb->data_addr);
+ sg = ((struct aha_ccb *)(ccb->ccb_phys[0].addr))->scat_gath;
+ lto3b((vm_offset_t)sg, ccb->data_addr);
sg = ccb->scat_gath;
seg = 0;
#ifdef 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 < AHA_NSEG) {
- bytes_this_seg = 0;
-
- /* put in the base address */
- lto3b(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",
- aha->sc_dev.dv_xname);
- xs->error = XS_DRIVER_STUFFUP;
- aha_free_ccb(aha, ccb, flags);
- return COMPLETE;
- }
- /** 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));
- lto3b(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++) {
+ lto3b(ccb->data_phys[seg].addr,
+ sg[seg].seg_addr);
+ lto3b(ccb->data_phys[seg].length,
+ sg[seg].seg_len);
}
}
- lto3b(seg * sizeof(struct aha_scat_gath), ccb->data_length);
- 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",
- aha->sc_dev.dv_xname, AHA_NSEG);
+ lto3b(ccb->data_nseg * sizeof(struct aha_scat_gath), ccb->data_length);
+ if (ccb->data_nseg == 0) {
+ printf("%s: aha_scsi_cmd, cannot map\n",
+ aha->sc_dev.dv_xname);
xs->error = XS_DRIVER_STUFFUP;
aha_free_ccb(aha, ccb, flags);
return COMPLETE;
- }
+ } else if (flags & SCSI_DATA_OUT)
+ isadma_copytobuf(xs->data, xs->datalen,
+ ccb->data_nseg, ccb->data_phys);
} else { /* No data xfer, use non S/G values */
lto3b(0, ccb->data_addr);
lto3b(0, ccb->data_length);
s = splbio();
+ isadma_copytobuf((caddr_t)ccb, CCB_PHYS_SIZE, 1, ccb->ccb_phys);
+
if (aha_send_mbo(aha, AHA_MBO_START, ccb) == NULL) {
splx(s);
xs->error = XS_DRIVER_STUFFUP;
+ if (ccb->data_nseg)
+ isadma_unmap(xs->data, xs->datalen,
+ ccb->data_nseg, ccb->data_phys);
aha_free_ccb(aha, ccb, flags);
return TRY_AGAIN_LATER;
}
* Usually return SUCCESSFULLY QUEUED
*/
SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n"));
+
+ if (VOLATILE_XS(xs)) {
+ if (tsleep(ccb, PRIBIO, "ahawait", (xs->timeout * hz) / 1000)) {
+ aha_timeout(ccb);
+ tsleep(ccb, PRIBIO, "ahawait1", 2000);
+ }
+ 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(aha, ccb, xs->flags);
+ scsi_done(xs);
+ return COMPLETE;
+ }
+
if ((flags & SCSI_POLL) == 0) {
timeout(aha_timeout, ccb, (xs->timeout * hz) / 1000);
splx(s);
lastworking = speed;
}
if (lastworking == -1) {
- printf("no working bus speed\n");
+ printf(" no working bus speed");
return 0;
}
- printf("%d nsec ", aha_bus_speeds[lastworking].nsecs);
+ printf(", %d nsec ", aha_bus_speeds[lastworking].nsecs);
if (lastworking == 7) /* is slowest already */
- printf("marginal\n");
+ printf("marginal");
else {
lastworking++;
- printf("ok, using %d nsec\n",
- aha_bus_speeds[lastworking].nsecs);
+ printf("ok, using %d nsec", aha_bus_speeds[lastworking].nsecs);
}
if (!aha_bus_speed_check(aha, lastworking)) {
- printf("test retry failed.. aborting.\n");
+ printf("test retry failed.. aborting.");
return 0;
}
return 1;
int speed;
{
int numspeeds = sizeof(aha_bus_speeds) / sizeof(struct bus_speed);
- int loopcount;
+ int result, loopcount;
+ struct isadma_seg test_phys[1], scratch_phys[1];
u_char ad[3];
+ result = 1;
+
+ if (isadma_map(aha_scratch_buf, sizeof(aha_scratch_buf),
+ scratch_phys, ISADMA_MAP_CONTIG) != 1)
+ return 0;
+ if (isadma_map(aha_test_string, sizeof(aha_test_string),
+ test_phys, ISADMA_MAP_CONTIG) != 1) {
+ isadma_unmap(aha_scratch_buf, sizeof(aha_scratch_buf),
+ 1, scratch_phys);
+ return 0;
+ }
+ isadma_copytobuf(aha_test_string, sizeof(aha_test_string),
+ 1, test_phys);
+
/*
* Set the dma-speed
*/
* it's address. Read it onto the board
*/
for (loopcount = 100; loopcount; loopcount--) {
- lto3b(KVTOPHYS(aha_test_string), ad);
+ lto3b(test_phys[0].addr, ad);
aha_cmd(aha, 3, 0, 0, 0, AHA_WRITE_FIFO, ad[0], ad[1], ad[2]);
/*
* board.
*/
bzero(aha_scratch_buf, 54);
+ isadma_copytobuf(aha_scratch_buf, sizeof(aha_scratch_buf),
+ 1, scratch_phys);
- lto3b(KVTOPHYS(aha_scratch_buf), ad);
+ lto3b(scratch_phys[0].addr, ad);
aha_cmd(aha, 3, 0, 0, 0, AHA_READ_FIFO, ad[0], ad[1], ad[2]);
+ isadma_copyfrombuf(aha_scratch_buf, sizeof(aha_scratch_buf),
+ 1, scratch_phys);
/*
* Compare the original data and the final data and return the
* first 54 bytes, because that's all the board copies during
* WRITE_FIFO and READ_FIFO.
*/
- if (bcmp(aha_test_string, aha_scratch_buf, 54))
- return 0; /* failed test */
+ if (bcmp(aha_test_string, aha_scratch_buf, 54)) {
+ result = 0; /* failed test */
+ break;
+ }
}
+ isadma_unmap(aha_scratch_buf, sizeof(aha_scratch_buf),
+ 1, scratch_phys);
+ isadma_unmap(aha_test_string, sizeof(aha_test_string),
+ 1, test_phys);
+
/* copy succeeded; assume speed ok */
- return 1;
+ return result;
}
#endif /* TUNE_1542 */
#include <dev/isa/isadmavar.h>
#include <dev/isa/isadmareg.h>
-/* region of physical memory known to be contiguous */
-vm_offset_t isaphysmem;
-static caddr_t dma_bounce[8]; /* XXX */
-static char bounced[8]; /* XXX */
-#define MAXDMASZ 512 /* XXX */
+struct dma_info {
+ int flags;
+ caddr_t addr;
+ vm_size_t nbytes;
+ struct isadma_seg phys[1];
+};
+
+static struct dma_info dma_info[8];
/* high byte of address is stored in this port for i-th dma channel */
static int dmapageport[8] =
{ 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
/*
- * isa_dmacascade(): program 8237 DMA controller channel to accept
+ * isadma_cascade(): program 8237 DMA controller channel to accept
* external dma control by a board.
*/
void
-isa_dmacascade(chan)
+isadma_cascade(chan)
int chan;
{
#ifdef DIAGNOSTIC
if (chan < 0 || chan > 7)
- panic("isa_dmacascade: impossible request");
+ panic("isadma_cascade: impossible request");
#endif
/* set dma channel mode, and set dma channel mode */
}
/*
- * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
+ * isadma_start(): program 8237 DMA controller channel, avoid page alignment
* problems by using a bounce buffer.
*/
void
-isa_dmastart(flags, addr, nbytes, chan)
- int flags;
+isadma_start(addr, nbytes, chan, flags)
caddr_t addr;
vm_size_t nbytes;
int chan;
+ int flags;
{
- vm_offset_t phys;
+ struct dma_info *di;
int waport;
- caddr_t newaddr;
+ int mflags;
+ vm_size_t size;
#ifdef DIAGNOSTIC
if (chan < 0 || chan > 7 ||
+ ((flags & ISADMA_START_READ) == 0) == ((flags & ISADMA_START_WRITE) == 0) ||
((chan & 4) ? (nbytes >= (1<<17) || nbytes & 1 || (u_int)addr & 1) :
(nbytes >= (1<<16))))
- panic("isa_dmastart: impossible request");
+ panic("isadma_start: impossible request");
#endif
- if (isa_dmarangecheck(addr, nbytes, chan)) {
- if (dma_bounce[chan] == 0)
- dma_bounce[chan] =
- /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/
- (caddr_t) isaphysmem + NBPG*chan;
- bounced[chan] = 1;
- newaddr = dma_bounce[chan];
- *(int *) newaddr = 0; /* XXX */
- /* copy bounce buffer on write */
- if ((flags & B_READ) == 0)
- bcopy(addr, newaddr, nbytes);
- addr = newaddr;
+ di = dma_info+chan;
+ if (di->flags != 0) {
+ log(LOG_ERR,"isadma_start: old request active on %d\n",chan);
+ isadma_abort(chan);
}
- /* translate to physical */
- phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
+ di->flags = flags;
+ di->addr = addr;
+ di->nbytes = nbytes;
+
+ mflags = ISADMA_MAP_WAITOK | ISADMA_MAP_BOUNCE | ISADMA_MAP_CONTIG;
+ mflags |= (chan & 4) ? ISADMA_MAP_16BIT : ISADMA_MAP_8BIT;
+
+ if (isadma_map(addr, nbytes, di->phys, mflags) != 1)
+ panic("isadma_start: cannot map");
+
+ if ((flags & ISADMA_START_READ) == 0)
+ isadma_copytobuf(addr, nbytes, 1, di->phys);
if ((chan & 4) == 0) {
/*
* byte mode channels.
*/
/* set dma channel mode, and reset address ff */
- if (flags & B_READ)
+ if (flags & ISADMA_START_READ)
outb(DMA1_MODE, chan | DMA37MD_SINGLE | DMA37MD_WRITE);
else
outb(DMA1_MODE, chan | DMA37MD_SINGLE | DMA37MD_READ);
/* send start address */
waport = DMA1_CHN(chan);
- outb(waport, phys);
- outb(waport, phys>>8);
- outb(dmapageport[chan], phys>>16);
+ outb(waport, di->phys[0].addr);
+ outb(waport, di->phys[0].addr>>8);
+ outb(dmapageport[chan], di->phys[0].addr>>16);
/* send count */
outb(waport + 1, --nbytes);
* word mode channels.
*/
/* set dma channel mode, and reset address ff */
- if (flags & B_READ)
+ if (flags & ISADMA_START_READ)
outb(DMA2_MODE, (chan & 3) | DMA37MD_SINGLE | DMA37MD_WRITE);
else
outb(DMA2_MODE, (chan & 3) | DMA37MD_SINGLE | DMA37MD_READ);
/* send start address */
waport = DMA2_CHN(chan & 3);
- outb(waport, phys>>1);
- outb(waport, phys>>9);
- outb(dmapageport[chan], phys>>16);
+ outb(waport, di->phys[0].addr>>1);
+ outb(waport, di->phys[0].addr>>9);
+ outb(dmapageport[chan], di->phys[0].addr>>16);
/* send count */
nbytes >>= 1;
}
void
-isa_dmaabort(chan)
+isadma_abort(chan)
int chan;
{
+ struct dma_info *di;
#ifdef DIAGNOSTIC
if (chan < 0 || chan > 7)
- panic("isa_dmaabort: impossible request");
+ panic("isadma_abort: impossible request");
#endif
- bounced[chan] = 0;
+ di = dma_info+chan;
+ if (di->flags == 0) {
+ log(LOG_ERR,"isadma_abort: no request active on %d\n",chan);
+ return;
+ }
/* mask channel */
if ((chan & 4) == 0)
outb(DMA1_SMSK, DMA37SM_SET | chan);
else
outb(DMA2_SMSK, DMA37SM_SET | (chan & 3));
+
+ isadma_unmap(di->addr, di->nbytes, 1, di->phys);
+ di->flags = 0;
}
void
-isa_dmadone(flags, addr, nbytes, chan)
- int flags;
- caddr_t addr;
- vm_size_t nbytes;
+isadma_done(chan)
int chan;
{
+ struct dma_info *di;
u_char tc;
#ifdef DIAGNOSTIC
if (chan < 0 || chan > 7)
- panic("isa_dmadone: impossible request");
+ panic("isadma_done: impossible request");
#endif
+ di = dma_info+chan;
+ if (di->flags == 0) {
+ log(LOG_ERR,"isadma_done: no request active on %d\n",chan);
+ return;
+ }
+
/* check that the terminal count was reached */
if ((chan & 4) == 0)
tc = inb(DMA1_SR) & (1 << chan);
else
outb(DMA2_SMSK, DMA37SM_SET | (chan & 3));
- /* copy bounce buffer on read */
- if (bounced[chan]) {
- bcopy(dma_bounce[chan], addr, nbytes);
- bounced[chan] = 0;
- }
-}
+ if (di->flags & ISADMA_START_READ)
+ isadma_copyfrombuf(di->addr, di->nbytes, 1, di->phys);
-/*
- * Check for problems with the address range of a DMA transfer
- * (non-contiguous physical pages, outside of bus address space,
- * crossing DMA page boundaries).
- * Return true if special handling needed.
- */
-int
-isa_dmarangecheck(va, length, chan)
- vm_offset_t va;
- u_long length;
- int chan;
-{
- vm_offset_t phys, priorpage = 0, endva;
- u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1);
-
- endva = round_page(va + length);
- for (; va < endva ; va += NBPG) {
- phys = trunc_page(pmap_extract(pmap_kernel(), va));
- if (phys == 0)
- panic("isa_dmacheck: no physical page present");
- if (phys >= (1<<24))
- return 1;
- if (priorpage) {
- if (priorpage + NBPG != phys)
- return 1;
- /* check if crossing a DMA page boundary */
- if ((priorpage ^ phys) & dma_pgmsk)
- return 1;
- }
- priorpage = phys;
- }
- return 0;
-}
-
-/* head of queue waiting for physmem to become available */
-struct buf isa_physmemq;
-
-/* blocked waiting for resource to become free for exclusive use */
-static isaphysmemflag;
-/* if waited for and call requested when free (B_CALL) */
-static void (*isaphysmemunblock)(); /* needs to be a list */
-
-/*
- * Allocate contiguous physical memory for transfer, returning
- * a *virtual* address to region. May block waiting for resource.
- * (assumed to be called at splbio())
- */
-caddr_t
-isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) {
-
- isaphysmemunblock = func;
- while (isaphysmemflag & B_BUSY) {
- isaphysmemflag |= B_WANTED;
- sleep((caddr_t)&isaphysmemflag, PRIBIO);
- }
- isaphysmemflag |= B_BUSY;
-
- return((caddr_t)isaphysmem);
-}
-
-/*
- * Free contiguous physical memory used for transfer.
- * (assumed to be called at splbio())
- */
-void
-isa_freephysmem(caddr_t va, unsigned length) {
-
- isaphysmemflag &= ~B_BUSY;
- if (isaphysmemflag & B_WANTED) {
- isaphysmemflag &= B_WANTED;
- wakeup((caddr_t)&isaphysmemflag);
- if (isaphysmemunblock)
- (*isaphysmemunblock)();
- }
+ isadma_unmap(di->addr, di->nbytes, 1, di->phys);
+ di->flags = 0;
}
/* $NetBSD: isadmavar.h,v 1.2 1994/10/27 04:17:09 cgd Exp $ */
-void isa_dmacascade __P((int));
-void isa_dmastart __P((int, caddr_t, vm_size_t, int));
-void isa_dmaabort __P((int));
-void isa_dmadone __P((int, caddr_t, vm_size_t, int));
+#define ISADMA_START_READ 0x0001 /* read from device */
+#define ISADMA_START_WRITE 0x0002 /* write to device */
+
+#define ISADMA_MAP_WAITOK 0x0001 /* OK for isadma_map to sleep */
+#define ISADMA_MAP_BOUNCE 0x0002 /* use bounce buffer if necessary */
+#define ISADMA_MAP_CONTIG 0x0004 /* must be physically contiguous */
+#define ISADMA_MAP_8BIT 0x0008 /* must not cross 64k boundary */
+#define ISADMA_MAP_16BIT 0x0010 /* must not cross 128k boundary */
+
+struct isadma_seg { /* a physical contiguous segment */
+ vm_offset_t addr; /* address of this segment */
+ vm_size_t length; /* length of this segment (bytes) */
+};
+
+int isadma_map __P((caddr_t, vm_size_t, struct isadma_seg *, int));
+void isadma_unmap __P((caddr_t, vm_size_t, int, struct isadma_seg *));
+void isadma_copytobuf __P((caddr_t, vm_size_t, int, struct isadma_seg *));
+void isadma_copyfrombuf __P((caddr_t, vm_size_t, int, struct isadma_seg *));
+
+void isadma_cascade __P((int));
+void isadma_start __P((caddr_t, vm_size_t, int, int));
+void isadma_abort __P((int));
+void isadma_done __P((int));
+
+/*
+ * XXX these are needed until all drivers have been cleaned up
+ */
+#define isa_dmacascade(c) isadma_cascade((c))
+#define isa_dmastart(f, a, s, c) \
+ isadma_start((a), (s), (c), (f)&B_READ?ISADMA_START_READ:ISADMA_START_WRITE)
+#define isa_dmaabort(c) isadma_abort((c))
+#define isa_dmadone(a, s, c, f) isadma_abort((c))
#include <machine/pio.h>
#include <dev/isa/isavar.h>
+#include <dev/isa/isadmavar.h>
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#include <machine/pio.h>
#include <dev/isa/isavar.h>
+#include <dev/isa/isadmavar.h>
#include <dev/isa/wdreg.h>
#define WAITTIME (4 * hz) /* time to wait for a completion */
#include <machine/cpu.h>
#include <machine/pio.h>
+#include <dev/isa/isadmavar.h>
#include <i386/isa/isa_device.h> /* XXX BROKEN */
extern int delaycount; /* from clock setup code */