diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-04-21 22:33:19 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-04-21 22:33:19 +0000 |
commit | 67d88b0a9910a68bb666b448d2dac29cb4d3d8c2 (patch) | |
tree | 967b89f6e07398a22bd8c76d30179b648776542d /sys/dev/isa/aic6360.c | |
parent | ba95d3c1d69cdb251d15a12ebf70f50b0ea2019b (diff) |
partial sync with netbsd 960418, more to come
Diffstat (limited to 'sys/dev/isa/aic6360.c')
-rw-r--r-- | sys/dev/isa/aic6360.c | 939 |
1 files changed, 504 insertions, 435 deletions
diff --git a/sys/dev/isa/aic6360.c b/sys/dev/isa/aic6360.c index c159feff414..f88a484ea62 100644 --- a/sys/dev/isa/aic6360.c +++ b/sys/dev/isa/aic6360.c @@ -1,4 +1,7 @@ -/* $NetBSD: aic6360.c,v 1.36.2.1 1995/10/18 21:40:12 pk Exp $ */ +/* $OpenBSD: aic6360.c,v 1.7 1996/04/21 22:22:39 deraadt Exp $ */ +/* $NetBSD: aic6360.c,v 1.44 1996/04/11 22:28:08 cgd Exp $ */ + +#define integrate static inline /* * Copyright (c) 1994, 1995 Charles Hannum. All rights reserved. @@ -13,7 +16,7 @@ * 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 Charles Hannum. + * This product includes software developed by Charles M. Hannum. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * @@ -105,6 +108,8 @@ */ #define AIC_DEBUG 1 +#define AIC_ABORT_TIMEOUT 2000 /* time to wait for abort */ + /* End of customizable parameters */ #if AIC_USE_EISA_DMA || AIC_USE_ISA_DMA @@ -136,45 +141,44 @@ */ /* AIC6360 definitions */ -#define IOBASE sc->sc_iobase -#define SCSISEQ (IOBASE + 0x00) /* SCSI sequence control */ -#define SXFRCTL0 (IOBASE + 0x01) /* SCSI transfer control 0 */ -#define SXFRCTL1 (IOBASE + 0x02) /* SCSI transfer control 1 */ -#define SCSISIG (IOBASE + 0x03) /* SCSI signal in/out */ -#define SCSIRATE (IOBASE + 0x04) /* SCSI rate control */ -#define SCSIID (IOBASE + 0x05) /* SCSI ID */ -#define SELID (IOBASE + 0x05) /* Selection/Reselection ID */ -#define SCSIDAT (IOBASE + 0x06) /* SCSI Latched Data */ -#define SCSIBUS (IOBASE + 0x07) /* SCSI Data Bus*/ -#define STCNT0 (IOBASE + 0x08) /* SCSI transfer count */ -#define STCNT1 (IOBASE + 0x09) -#define STCNT2 (IOBASE + 0x0a) -#define CLRSINT0 (IOBASE + 0x0b) /* Clear SCSI interrupts 0 */ -#define SSTAT0 (IOBASE + 0x0b) /* SCSI interrupt status 0 */ -#define CLRSINT1 (IOBASE + 0x0c) /* Clear SCSI interrupts 1 */ -#define SSTAT1 (IOBASE + 0x0c) /* SCSI status 1 */ -#define SSTAT2 (IOBASE + 0x0d) /* SCSI status 2 */ -#define SCSITEST (IOBASE + 0x0e) /* SCSI test control */ -#define SSTAT3 (IOBASE + 0x0e) /* SCSI status 3 */ -#define CLRSERR (IOBASE + 0x0f) /* Clear SCSI errors */ -#define SSTAT4 (IOBASE + 0x0f) /* SCSI status 4 */ -#define SIMODE0 (IOBASE + 0x10) /* SCSI interrupt mode 0 */ -#define SIMODE1 (IOBASE + 0x11) /* SCSI interrupt mode 1 */ -#define DMACNTRL0 (IOBASE + 0x12) /* DMA control 0 */ -#define DMACNTRL1 (IOBASE + 0x13) /* DMA control 1 */ -#define DMASTAT (IOBASE + 0x14) /* DMA status */ -#define FIFOSTAT (IOBASE + 0x15) /* FIFO status */ -#define DMADATA (IOBASE + 0x16) /* DMA data */ -#define DMADATAL (IOBASE + 0x16) /* DMA data low byte */ -#define DMADATAH (IOBASE + 0x17) /* DMA data high byte */ -#define BRSTCNTRL (IOBASE + 0x18) /* Burst Control */ -#define DMADATALONG (IOBASE + 0x18) -#define PORTA (IOBASE + 0x1a) /* Port A */ -#define PORTB (IOBASE + 0x1b) /* Port B */ -#define REV (IOBASE + 0x1c) /* Revision (001 for 6360) */ -#define STACK (IOBASE + 0x1d) /* Stack */ -#define TEST (IOBASE + 0x1e) /* Test register */ -#define ID (IOBASE + 0x1f) /* ID register */ +#define SCSISEQ 0x00 /* SCSI sequence control */ +#define SXFRCTL0 0x01 /* SCSI transfer control 0 */ +#define SXFRCTL1 0x02 /* SCSI transfer control 1 */ +#define SCSISIG 0x03 /* SCSI signal in/out */ +#define SCSIRATE 0x04 /* SCSI rate control */ +#define SCSIID 0x05 /* SCSI ID */ +#define SELID 0x05 /* Selection/Reselection ID */ +#define SCSIDAT 0x06 /* SCSI Latched Data */ +#define SCSIBUS 0x07 /* SCSI Data Bus*/ +#define STCNT0 0x08 /* SCSI transfer count */ +#define STCNT1 0x09 +#define STCNT2 0x0a +#define CLRSINT0 0x0b /* Clear SCSI interrupts 0 */ +#define SSTAT0 0x0b /* SCSI interrupt status 0 */ +#define CLRSINT1 0x0c /* Clear SCSI interrupts 1 */ +#define SSTAT1 0x0c /* SCSI status 1 */ +#define SSTAT2 0x0d /* SCSI status 2 */ +#define SCSITEST 0x0e /* SCSI test control */ +#define SSTAT3 0x0e /* SCSI status 3 */ +#define CLRSERR 0x0f /* Clear SCSI errors */ +#define SSTAT4 0x0f /* SCSI status 4 */ +#define SIMODE0 0x10 /* SCSI interrupt mode 0 */ +#define SIMODE1 0x11 /* SCSI interrupt mode 1 */ +#define DMACNTRL0 0x12 /* DMA control 0 */ +#define DMACNTRL1 0x13 /* DMA control 1 */ +#define DMASTAT 0x14 /* DMA status */ +#define FIFOSTAT 0x15 /* FIFO status */ +#define DMADATA 0x16 /* DMA data */ +#define DMADATAL 0x16 /* DMA data low byte */ +#define DMADATAH 0x17 /* DMA data high byte */ +#define BRSTCNTRL 0x18 /* Burst Control */ +#define DMADATALONG 0x18 +#define PORTA 0x1a /* Port A */ +#define PORTB 0x1b /* Port B */ +#define REV 0x1c /* Revision (001 for 6360) */ +#define STACK 0x1d /* Stack */ +#define TEST 0x1e /* Test register */ +#define ID 0x1f /* ID register */ #define IDSTRING "(C)1991ADAPTECAIC6360 " @@ -455,10 +459,12 @@ struct aic_acb { TAILQ_ENTRY(aic_acb) chain; struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */ int flags; -#define ACB_FREE 0 -#define ACB_ACTIVE 1 -#define ACB_CHKSENSE 2 -#define ACB_ABORTED 3 +#define ACB_ALLOC 0x01 +#define ACB_NEXUS 0x02 +#define ACB_SENSE 0x04 +#define ACB_ABORT 0x40 +#define ACB_RESET 0x80 + int timeout; }; /* @@ -506,13 +512,14 @@ struct aic_softc { u_char sc_phase; /* Current bus phase */ u_char sc_prevphase; /* Previous bus phase */ u_char sc_state; /* State applicable to the adapter */ -#define AIC_IDLE 0x01 -#define AIC_SELECTING 0x02 /* SCSI command is arbiting */ -#define AIC_RESELECTED 0x04 /* Has been reselected */ -#define AIC_CONNECTED 0x08 /* Actively using the SCSI bus */ -#define AIC_DISCONNECT 0x10 /* MSG_DISCONNECT received */ -#define AIC_CMDCOMPLETE 0x20 /* MSG_CMDCOMPLETE received */ -#define AIC_CLEANING 0x40 +#define AIC_INIT 0 +#define AIC_IDLE 1 +#define AIC_SELECTING 2 /* SCSI command is arbiting */ +#define AIC_RESELECTED 3 /* Has been reselected */ +#define AIC_CONNECTED 4 /* Actively using the SCSI bus */ +#define AIC_DISCONNECT 5 /* MSG_DISCONNECT received */ +#define AIC_CMDCOMPLETE 6 /* MSG_CMDCOMPLETE received */ +#define AIC_CLEANING 7 u_char sc_flags; #define AIC_DROP_MSGIN 0x01 /* Discard all msgs (parity err detected) */ #define AIC_ABORTING 0x02 /* Bailing out */ @@ -526,10 +533,10 @@ struct aic_softc { u_char sc_currmsg; /* Message currently ready to transmit */ #define SEND_DEV_RESET 0x01 #define SEND_PARITY_ERROR 0x02 -#define SEND_ABORT 0x04 +#define SEND_INIT_DET_ERR 0x04 #define SEND_REJECT 0x08 -#define SEND_INIT_DET_ERR 0x10 -#define SEND_IDENTIFY 0x20 +#define SEND_IDENTIFY 0x10 +#define SEND_ABORT 0x20 #define SEND_SDTR 0x40 #define SEND_WDTR 0x80 #define AIC_MAX_MSG_LEN 8 @@ -580,6 +587,8 @@ void aic_done __P((struct aic_softc *, struct aic_acb *)); void aic_dequeue __P((struct aic_softc *, struct aic_acb *)); int aic_scsi_cmd __P((struct scsi_xfer *)); int aic_poll __P((struct aic_softc *, struct scsi_xfer *, int)); +integrate void aic_sched_msgout __P((struct aic_softc *, u_char)); +integrate void aic_setsync __P((struct aic_softc *, struct aic_tinfo *)); void aic_select __P((struct aic_softc *, struct aic_acb *)); void aic_timeout __P((void *)); int aic_find __P((struct aic_softc *)); @@ -592,8 +601,12 @@ void aic_dump_driver(); void aic_dump6360(); #endif -struct cfdriver aiccd = { - NULL, "aic", aicprobe, aicattach, DV_DULL, sizeof(struct aic_softc) +struct cfattach aic_ca = { + sizeof(struct aic_softc), aicprobe, aicattach +}; + +struct cfdriver aic_cd = { + NULL, "aic", DV_DULL }; struct scsi_adapter aic_switch = { @@ -668,12 +681,13 @@ int aic_find(sc) struct aic_softc *sc; { + int iobase = sc->sc_iobase; char chip_id[sizeof(IDSTRING)]; /* For chips that support it */ char *start; int i; /* Remove aic6360 from possible powerdown mode */ - outb(DMACNTRL0, 0); + outb(iobase + DMACNTRL0, 0); /* Thanks to mark@aggregate.com for the new method for detecting * whether the chip is present or not. Bonus: may also work for @@ -687,13 +701,13 @@ aic_find(sc) */ /* Push the sequence 0,1,..,15 on the stack */ #define STSIZE 16 - outb(DMACNTRL1, 0); /* Reset stack pointer */ + outb(iobase + DMACNTRL1, 0); /* Reset stack pointer */ for (i = 0; i < STSIZE; i++) - outb(STACK, i); + outb(iobase + STACK, i); /* See if we can pull out the same sequence */ - outb(DMACNTRL1, 0); - for (i = 0; i < STSIZE && inb(STACK) == i; i++) + outb(iobase + DMACNTRL1, 0); + for (i = 0; i < STSIZE && inb(iobase + STACK) == i; i++) ; if (i != STSIZE) { AIC_START(("STACK futzed at %d.\n", i)); @@ -704,10 +718,10 @@ aic_find(sc) * now only used for informational purposes. */ bzero(chip_id, sizeof(chip_id)); - insb(ID, chip_id, sizeof(IDSTRING)-1); + insb(iobase + ID, chip_id, sizeof(IDSTRING)-1); AIC_START(("AIC found at 0x%x ", sc->sc_iobase)); AIC_START(("ID: %s ",chip_id)); - AIC_START(("chip revision %d\n",(int)inb(REV))); + AIC_START(("chip revision %d\n",(int)inb(iobase + REV))); sc->sc_initiator = 7; sc->sc_freq = 20; /* XXXX Assume 20 MHz. */ @@ -749,7 +763,7 @@ aicattach(parent, self, aux) struct aic_softc *sc = (void *)self; AIC_TRACE(("aicattach ")); - sc->sc_state = 0; + sc->sc_state = AIC_INIT; aic_init(sc); /* Init chip and driver */ /* @@ -766,8 +780,8 @@ aicattach(parent, self, aux) #ifdef NEWCONFIG isa_establish(&sc->sc_id, &sc->sc_dev); #endif - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_BIO, aicintr, - sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_BIO, aicintr, sc, sc->sc_dev.dv_xname); config_found(self, &sc->sc_link, aicprint); } @@ -782,32 +796,33 @@ void aic_reset(sc) struct aic_softc *sc; { + int iobase = sc->sc_iobase; - outb(SCSITEST, 0); /* Doc. recommends to clear these two */ - outb(TEST, 0); /* registers before operations commence */ + outb(iobase + SCSITEST, 0); /* Doc. recommends to clear these two */ + outb(iobase + TEST, 0); /* registers before operations commence */ /* Reset SCSI-FIFO and abort any transfers */ - outb(SXFRCTL0, CHEN|CLRCH|CLRSTCNT); + outb(iobase + SXFRCTL0, CHEN | CLRCH | CLRSTCNT); /* Reset DMA-FIFO */ - outb(DMACNTRL0, RSTFIFO); - outb(DMACNTRL1, 0); + outb(iobase + DMACNTRL0, RSTFIFO); + outb(iobase + DMACNTRL1, 0); - outb(SCSISEQ, 0); /* Disable all selection features */ - outb(SXFRCTL1, 0); + outb(iobase + SCSISEQ, 0); /* Disable all selection features */ + outb(iobase + SXFRCTL1, 0); - outb(SIMODE0, 0x00); /* Disable some interrupts */ - outb(CLRSINT0, 0x7f); /* Clear a slew of interrupts */ + outb(iobase + SIMODE0, 0x00); /* Disable some interrupts */ + outb(iobase + CLRSINT0, 0x7f); /* Clear a slew of interrupts */ - outb(SIMODE1, 0x00); /* Disable some more interrupts */ - outb(CLRSINT1, 0xef); /* Clear another slew of interrupts */ + outb(iobase + SIMODE1, 0x00); /* Disable some more interrupts */ + outb(iobase + CLRSINT1, 0xef); /* Clear another slew of interrupts */ - outb(SCSIRATE, 0); /* Disable synchronous transfers */ + outb(iobase + SCSIRATE, 0); /* Disable synchronous transfers */ - outb(CLRSERR, 0x07); /* Haven't seen ant errors (yet) */ + outb(iobase + CLRSERR, 0x07); /* Haven't seen ant errors (yet) */ - outb(SCSIID, sc->sc_initiator << OID_S); /* Set our SCSI-ID */ - outb(BRSTCNTRL, EISA_BRST_TIM); + outb(iobase + SCSIID, sc->sc_initiator << OID_S); /* Set our SCSI-ID */ + outb(iobase + BRSTCNTRL, EISA_BRST_TIM); } /* Pull the SCSI RST line for 500 us */ @@ -815,10 +830,11 @@ void aic_scsi_reset(sc) struct aic_softc *sc; { + int iobase = sc->sc_iobase; - outb(SCSISEQ, SCSIRSTO); + outb(iobase + SCSISEQ, SCSIRSTO); delay(500); - outb(SCSISEQ, 0); + outb(iobase + SCSISEQ, 0); delay(50); } @@ -829,6 +845,7 @@ void aic_init(sc) struct aic_softc *sc; { + int iobase = sc->sc_iobase; struct aic_acb *acb; int r; @@ -836,7 +853,7 @@ aic_init(sc) aic_scsi_reset(sc); aic_reset(sc); - if (sc->sc_state == 0) { + if (sc->sc_state == AIC_INIT) { /* First time through; initialize. */ TAILQ_INIT(&sc->ready_list); TAILQ_INIT(&sc->nexus_list); @@ -885,7 +902,7 @@ aic_init(sc) } sc->sc_state = AIC_IDLE; - outb(DMACNTRL0, INTEN); + outb(iobase + DMACNTRL0, INTEN); } void @@ -898,7 +915,7 @@ aic_free_acb(sc, acb, flags) s = splbio(); - acb->flags = ACB_FREE; + acb->flags = 0; TAILQ_INSERT_HEAD(&sc->free_list, acb, chain); /* @@ -926,7 +943,7 @@ aic_get_acb(sc, flags) tsleep(&sc->free_list, PRIBIO, "aicacb", 0); if (acb) { TAILQ_REMOVE(&sc->free_list, acb, chain); - acb->flags = ACB_ACTIVE; + acb->flags |= ACB_ALLOC; } splx(s); @@ -973,12 +990,6 @@ aic_scsi_cmd(xs) sc_link->target)); flags = xs->flags; - if ((flags & (ITSDONE|INUSE)) != INUSE) { - printf("%s: done or not in use?\n", sc->sc_dev.dv_xname); - xs->flags &= ~ITSDONE; - xs->flags |= INUSE; - } - if ((acb = aic_get_acb(sc, flags)) == NULL) { xs->error = XS_DRIVER_STUFFUP; return TRY_AGAIN_LATER; @@ -986,10 +997,18 @@ aic_scsi_cmd(xs) /* Initialize acb */ acb->xs = xs; - bcopy(xs->cmd, &acb->scsi_cmd, xs->cmdlen); - acb->scsi_cmd_length = xs->cmdlen; - acb->data_addr = xs->data; - acb->data_length = xs->datalen; + acb->timeout = xs->timeout; + + if (xs->flags & SCSI_RESET) { + acb->flags |= ACB_RESET; + acb->scsi_cmd_length = 0; + acb->data_length = 0; + } else { + bcopy(xs->cmd, &acb->scsi_cmd, xs->cmdlen); + acb->scsi_cmd_length = xs->cmdlen; + acb->data_addr = xs->data; + acb->data_length = xs->datalen; + } acb->target_stat = 0; s = splbio(); @@ -998,18 +1017,15 @@ aic_scsi_cmd(xs) if (sc->sc_state == AIC_IDLE) aic_sched(sc); - if ((flags & SCSI_POLL) == 0) { /* Almost done. Wait outside */ - timeout(aic_timeout, acb, (xs->timeout * hz) / 1000); - splx(s); - return SUCCESSFULLY_QUEUED; - } - splx(s); + if ((flags & SCSI_POLL) == 0) + return SUCCESSFULLY_QUEUED; + /* Not allowed to use interrupts, use polling instead */ - if (aic_poll(sc, xs, xs->timeout)) { + if (aic_poll(sc, xs, acb->timeout)) { aic_timeout(acb); - if (aic_poll(sc, xs, 2000)) + if (aic_poll(sc, xs, acb->timeout)) aic_timeout(acb); } return COMPLETE; @@ -1038,6 +1054,7 @@ aic_poll(sc, xs, count) struct scsi_xfer *xs; int count; { + int iobase = sc->sc_iobase; AIC_TRACE(("aic_poll ")); while (count) { @@ -1045,7 +1062,7 @@ aic_poll(sc, xs, count) * If we had interrupts enabled, would we * have got an interrupt? */ - if ((inb(DMASTAT) & INTSTAT) != 0) + if ((inb(iobase + DMASTAT) & INTSTAT) != 0) aicintr(sc); if ((xs->flags & ITSDONE) != 0) return 0; @@ -1059,32 +1076,36 @@ aic_poll(sc, xs, count) * LOW LEVEL SCSI UTILITIES */ -#define aic_sched_msgout(m) \ - do { \ - if (sc->sc_msgpriq == 0) \ - outb(SCSISIG, sc->sc_phase|ATNO); \ - sc->sc_msgpriq |= (m); \ - } while (0) +integrate void +aic_sched_msgout(sc, m) + struct aic_softc *sc; + u_char m; +{ + int iobase = sc->sc_iobase; + + if (sc->sc_msgpriq == 0) + outb(iobase + SCSISIG, sc->sc_phase | ATNO); + sc->sc_msgpriq |= m; +} -#if AIC_USE_SYNCHRONOUS /* * Set synchronous transfer offset and period. */ -static inline void +integrate void aic_setsync(sc, ti) struct aic_softc *sc; struct aic_tinfo *ti; { +#if AIC_USE_SYNCHRONOUS + int iobase = sc->sc_iobase; if (ti->offset != 0) - outb(SCSIRATE, + outb(iobase + SCSIRATE, ((ti->period * sc->sc_freq) / 250 - 2) << 4 | ti->offset); else - outb(SCSIRATE, 0); -} -#else -#define aic_setsync(sc, ti) + outb(iobase + SCSIRATE, 0); #endif +} /* * Start a selection. This is used by aic_sched() to select an idle target, @@ -1098,15 +1119,16 @@ aic_select(sc, acb) struct scsi_link *sc_link = acb->xs->sc_link; int target = sc_link->target; struct aic_tinfo *ti = &sc->sc_tinfo[target]; + int iobase = sc->sc_iobase; - outb(SCSIID, sc->sc_initiator << OID_S | target); + outb(iobase + SCSIID, sc->sc_initiator << OID_S | target); aic_setsync(sc, ti); - outb(SXFRCTL1, STIMO_256ms|ENSTIMER); + outb(iobase + SXFRCTL1, STIMO_256ms | ENSTIMER); /* Always enable reselections. */ - outb(SIMODE0, ENSELDI|ENSELDO); - outb(SIMODE1, ENSCSIRST|ENSELTIMO); - outb(SCSISEQ, ENRESELI|ENSELO|ENAUTOATNO); + outb(iobase + SIMODE0, ENSELDI | ENSELDO); + outb(iobase + SIMODE1, ENSCSIRST | ENSELTIMO); + outb(iobase + SCSISEQ, ENRESELI | ENSELO | ENAUTOATNO); sc->sc_state = AIC_SELECTING; } @@ -1162,6 +1184,11 @@ aic_reselect(sc, message) ti->lubusy |= (1 << lun); aic_setsync(sc, ti); + if (acb->flags & ACB_RESET) + aic_sched_msgout(sc, SEND_DEV_RESET); + else if (acb->flags & ACB_ABORT) + aic_sched_msgout(sc, SEND_ABORT); + /* Do an implicit RESTORE POINTERS. */ sc->sc_dp = acb->data_addr; sc->sc_dleft = acb->data_length; @@ -1171,13 +1198,11 @@ aic_reselect(sc, message) return (0); reset: - sc->sc_flags |= AIC_ABORTING; - aic_sched_msgout(SEND_DEV_RESET); + aic_sched_msgout(sc, SEND_DEV_RESET); return (1); abort: - sc->sc_flags |= AIC_ABORTING; - aic_sched_msgout(SEND_ABORT); + aic_sched_msgout(sc, SEND_ABORT); return (1); } @@ -1194,12 +1219,13 @@ aic_sched(sc) struct aic_acb *acb; struct scsi_link *sc_link; struct aic_tinfo *ti; + int iobase = sc->sc_iobase; /* * Find first acb in ready queue that is for a target/lunit pair that * is not busy. */ - outb(CLRSINT1, CLRSELTIMO|CLRBUSFREE|CLRSCSIPERR); + outb(iobase + CLRSINT1, CLRSELTIMO | CLRBUSFREE | CLRSCSIPERR); for (acb = sc->ready_list.tqh_first; acb != NULL; acb = acb->chain.tqe_next) { sc_link = acb->xs->sc_link; @@ -1217,11 +1243,44 @@ aic_sched(sc) } AIC_MISC(("idle ")); /* Nothing to start; just enable reselections and wait. */ - outb(SIMODE0, ENSELDI); - outb(SIMODE1, ENSCSIRST); - outb(SCSISEQ, ENRESELI); + outb(iobase + SIMODE0, ENSELDI); + outb(iobase + SIMODE1, ENSCSIRST); + outb(iobase + SCSISEQ, ENRESELI); } +void +aic_sense(sc, acb) + struct aic_softc *sc; + struct aic_acb *acb; +{ + struct scsi_xfer *xs = acb->xs; + struct scsi_link *sc_link = xs->sc_link; + struct aic_tinfo *ti = &sc->sc_tinfo[sc_link->target]; + struct scsi_sense *ss = (void *)&acb->scsi_cmd; + + AIC_MISC(("requesting sense ")); + /* Next, setup a request sense command block */ + bzero(ss, sizeof(*ss)); + ss->opcode = REQUEST_SENSE; + ss->byte2 = sc_link->lun << 5; + ss->length = sizeof(struct scsi_sense_data); + acb->scsi_cmd_length = sizeof(*ss); + acb->data_addr = (char *)&xs->sense; + acb->data_length = sizeof(struct scsi_sense_data); + acb->flags |= ACB_SENSE; + ti->senses++; + if (acb->flags & ACB_NEXUS) + ti->lubusy &= ~(1 << sc_link->lun); + if (acb == sc->sc_nexus) { + aic_select(sc, acb); + } else { + aic_dequeue(sc, acb); + TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain); + if (sc->sc_state == AIC_IDLE) + aic_sched(sc); + } +} + /* * POST PROCESSING OF SCSI_CMD (usually current) */ @@ -1245,33 +1304,15 @@ aic_done(sc, acb) * We don't support chk sense conditions for the request sense cmd. */ if (xs->error == XS_NOERROR) { - if (acb->flags == ACB_ABORTED) { + if (acb->flags & ACB_ABORT) { xs->error = XS_DRIVER_STUFFUP; - } else if (acb->flags == ACB_CHKSENSE) { + } else if (acb->flags & ACB_SENSE) { xs->error = XS_SENSE; } else if (acb->target_stat == SCSI_CHECK) { - struct scsi_sense *ss = (void *)&acb->scsi_cmd; - - AIC_MISC(("requesting sense ")); /* First, save the return values */ xs->resid = acb->data_length; xs->status = acb->target_stat; - /* Next, setup a request sense command block */ - bzero(ss, sizeof(*ss)); - ss->opcode = REQUEST_SENSE; - ss->byte2 = sc_link->lun << 5; - ss->length = sizeof(struct scsi_sense_data); - acb->scsi_cmd_length = sizeof(*ss); - acb->data_addr = (char *)&xs->sense; - acb->data_length = sizeof(struct scsi_sense_data); - acb->flags = ACB_CHKSENSE; - ti->senses++; - ti->lubusy &= ~(1<<sc_link->lun); - if (acb == sc->sc_nexus) { - aic_select(sc, acb); - } else { - TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain); - } + aic_sense(sc, acb); return; } else { xs->resid = acb->data_length; @@ -1292,16 +1333,13 @@ aic_done(sc, acb) #endif /* - * Remove the ACB from whatever queue it's on. We have to do a bit of - * a hack to figure out which queue it's on. Note that it is *not* - * necessary to cdr down the ready queue, but we must cdr down the - * nexus queue and see if it's there, so we can mark the unit as no - * longer busy. This code is sickening, but it works. + * Remove the ACB from whatever queue it happens to be on. */ - if (acb == sc->sc_nexus) { + if (acb->flags & ACB_NEXUS) ti->lubusy &= ~(1 << sc_link->lun); - sc->sc_state = AIC_IDLE; + if (acb == sc->sc_nexus) { sc->sc_nexus = NULL; + sc->sc_state = AIC_IDLE; aic_sched(sc); } else aic_dequeue(sc, acb); @@ -1316,28 +1354,11 @@ aic_dequeue(sc, acb) struct aic_softc *sc; struct aic_acb *acb; { - struct scsi_link *sc_link = acb->xs->sc_link; - struct aic_tinfo *ti = &sc->sc_tinfo[sc_link->target]; - if (sc->ready_list.tqh_last == &acb->chain.tqe_next) { - TAILQ_REMOVE(&sc->ready_list, acb, chain); + if (acb->flags & ACB_NEXUS) { + TAILQ_REMOVE(&sc->nexus_list, acb, chain); } else { - register struct aic_acb *acb2; - for (acb2 = sc->nexus_list.tqh_first; acb2 != NULL; - acb2 = acb2->chain.tqe_next) { - if (acb2 == acb) - break; - } - if (acb2 != NULL) { - TAILQ_REMOVE(&sc->nexus_list, acb, chain); - ti->lubusy &= ~(1 << sc_link->lun); - } else if (acb->chain.tqe_next) { - TAILQ_REMOVE(&sc->ready_list, acb, chain); - } else { - printf("%s: can't find matching acb\n", - sc->sc_dev.dv_xname); - Debugger(); - } + TAILQ_REMOVE(&sc->ready_list, acb, chain); } } @@ -1354,10 +1375,11 @@ aic_dequeue(sc, acb) * The SCSI bus is already in the MSGI phase and there is a message byte * on the bus, along with an asserted REQ signal. */ -int +void aic_msgin(sc) register struct aic_softc *sc; { + int iobase = sc->sc_iobase; u_char sstat1; int n; @@ -1384,34 +1406,34 @@ nextbyte: */ for (;;) { for (;;) { - sstat1 = inb(SSTAT1); - if ((sstat1 & (REQINIT|BUSFREE)) != 0) + sstat1 = inb(iobase + SSTAT1); + if ((sstat1 & (REQINIT | PHASECHG | BUSFREE)) != 0) break; /* Wait for REQINIT. XXX Need timeout. */ } - if ((sstat1 & (PHASECHG|BUSFREE)) != 0) { + if ((sstat1 & (PHASECHG | BUSFREE)) != 0) { /* * Target left MESSAGE IN, probably because it * a) noticed our ATN signal, or * b) ran out of messages. */ - return (1); + goto out; } /* If parity error, just dump everything on the floor. */ if ((sstat1 & SCSIPERR) != 0) { - aic_sched_msgout(SEND_PARITY_ERROR); sc->sc_flags |= AIC_DROP_MSGIN; + aic_sched_msgout(sc, SEND_PARITY_ERROR); } /* Gather incoming message bytes if needed. */ if ((sc->sc_flags & AIC_DROP_MSGIN) == 0) { if (n >= AIC_MAX_MSG_LEN) { - (void) inb(SCSIDAT); - aic_sched_msgout(SEND_REJECT); + (void) inb(iobase + SCSIDAT); sc->sc_flags |= AIC_DROP_MSGIN; + aic_sched_msgout(sc, SEND_REJECT); } else { - *sc->sc_imp++ = inb(SCSIDAT); + *sc->sc_imp++ = inb(iobase + SCSIDAT); n++; /* * This testing is suboptimal, but most @@ -1428,18 +1450,18 @@ nextbyte: break; } } else - (void) inb(SCSIDAT); + (void) inb(iobase + SCSIDAT); /* * If we reach this spot we're either: * a) in the middle of a multi-byte message, or * b) dropping bytes. */ - outb(SXFRCTL0, CHEN|SPIOEN); + outb(iobase + SXFRCTL0, CHEN | SPIOEN); /* Ack the last byte read. */ - (void) inb(SCSIDAT); - outb(SXFRCTL0, CHEN); - while ((inb(SCSISIG) & ACKI) != 0) + (void) inb(iobase + SCSIDAT); + outb(iobase + SXFRCTL0, CHEN); + while ((inb(iobase + SCSISIG) & ACKI) != 0) ; } @@ -1471,7 +1493,7 @@ nextbyte: case MSG_PARITY_ERROR: /* Resend the last message. */ - aic_sched_msgout(sc->sc_lastmsg); + aic_sched_msgout(sc, sc->sc_lastmsg); break; case MSG_MESSAGE_REJECT: @@ -1479,7 +1501,7 @@ nextbyte: switch (sc->sc_lastmsg) { #if AIC_USE_SYNCHRONOUS + AIC_USE_WIDE case SEND_IDENTIFY: - ti->flags &= ~(DO_SYNC|DO_WIDE); + ti->flags &= ~(DO_SYNC | DO_WIDE); ti->period = ti->offset = 0; aic_setsync(sc, ti); ti->width = 0; @@ -1499,8 +1521,7 @@ nextbyte: break; #endif case SEND_INIT_DET_ERR: - sc->sc_flags |= AIC_ABORTING; - aic_sched_msgout(SEND_ABORT); + aic_sched_msgout(sc, SEND_ABORT); break; } break; @@ -1539,7 +1560,7 @@ nextbyte: ti->period > sc->sc_maxsync || ti->offset > 8) { ti->period = ti->offset = 0; - aic_sched_msgout(SEND_SDTR); + aic_sched_msgout(sc, SEND_SDTR); } else { sc_print_addr(acb->xs->sc_link); printf("sync, offset %d, period %dnsec\n", @@ -1558,7 +1579,7 @@ nextbyte: if (ti->width == 0) { } else if (ti->width > AIC_MAX_WIDTH) { ti->width = 0; - aic_sched_msgout(SEND_WDTR); + aic_sched_msgout(sc, SEND_WDTR); } else { sc_print_addr(acb->xs->sc_link); printf("wide, width %d\n", @@ -1580,7 +1601,7 @@ nextbyte: sc->sc_dev.dv_xname); AIC_BREAK(); reject: - aic_sched_msgout(SEND_REJECT); + aic_sched_msgout(sc, SEND_REJECT); break; } break; @@ -1601,21 +1622,19 @@ nextbyte: sc->sc_dev.dv_xname); AIC_BREAK(); reset: - sc->sc_flags |= AIC_ABORTING; - aic_sched_msgout(SEND_DEV_RESET); + aic_sched_msgout(sc, SEND_DEV_RESET); break; abort: - sc->sc_flags |= AIC_ABORTING; - aic_sched_msgout(SEND_ABORT); + aic_sched_msgout(sc, SEND_ABORT); break; } - outb(SXFRCTL0, CHEN|SPIOEN); + outb(iobase + SXFRCTL0, CHEN | SPIOEN); /* Ack the last message byte. */ - (void) inb(SCSIDAT); - outb(SXFRCTL0, CHEN); - while ((inb(SCSISIG) & ACKI) != 0) + (void) inb(iobase + SCSIDAT); + outb(iobase + SXFRCTL0, CHEN); + while ((inb(iobase + SCSISIG) & ACKI) != 0) ; /* Go get the next message, if any. */ @@ -1623,7 +1642,6 @@ nextbyte: out: AIC_MISC(("n=%d imess=0x%02x ", n, sc->sc_imess[0])); - return (0); } /* @@ -1633,22 +1651,17 @@ void aic_msgout(sc) register struct aic_softc *sc; { - struct aic_acb *acb; + int iobase = sc->sc_iobase; struct aic_tinfo *ti; u_char sstat1; int n; AIC_TRACE(("aic_msgout ")); - /* - * Set ATN. If we're just sending a trivial 1-byte message, we'll - * clear ATN later on anyway. - */ - outb(SCSISIG, PH_MSGOUT|ATNO); /* Reset the FIFO. */ - outb(DMACNTRL0, RSTFIFO); + outb(iobase + DMACNTRL0, RSTFIFO); /* Enable REQ/ACK protocol. */ - outb(SXFRCTL0, CHEN|SPIOEN); + outb(iobase + SXFRCTL0, CHEN | SPIOEN); if (sc->sc_prevphase == PH_MSGOUT) { if (sc->sc_omp == sc->sc_omess) { @@ -1665,6 +1678,11 @@ aic_msgout(sc) */ AIC_MISC(("retransmitting ")); sc->sc_msgpriq |= sc->sc_msgoutq; + /* + * Set ATN. If we're just sending a trivial 1-byte + * message, we'll clear ATN later on anyway. + */ + outb(iobase + SCSISIG, PH_MSGOUT | ATNO); } else { /* This is a continuation of the previous message. */ n = sc->sc_omp - sc->sc_omess; @@ -1685,26 +1703,14 @@ nextmsg: /* Build the outgoing message data. */ switch (sc->sc_currmsg) { case SEND_IDENTIFY: - if (sc->sc_state != AIC_CONNECTED) { - printf("%s: SEND_IDENTIFY while not connected; sending NOOP\n", - sc->sc_dev.dv_xname); - AIC_BREAK(); - goto noop; - } AIC_ASSERT(sc->sc_nexus != NULL); - acb = sc->sc_nexus; - sc->sc_omess[0] = MSG_IDENTIFY(acb->xs->sc_link->lun, 1); + sc->sc_omess[0] = + MSG_IDENTIFY(sc->sc_nexus->xs->sc_link->lun, 1); n = 1; break; #if AIC_USE_SYNCHRONOUS case SEND_SDTR: - if (sc->sc_state != AIC_CONNECTED) { - printf("%s: SEND_SDTR while not connected; sending NOOP\n", - sc->sc_dev.dv_xname); - AIC_BREAK(); - goto noop; - } AIC_ASSERT(sc->sc_nexus != NULL); ti = &sc->sc_tinfo[sc->sc_nexus->xs->sc_link->target]; sc->sc_omess[4] = MSG_EXTENDED; @@ -1718,12 +1724,6 @@ nextmsg: #if AIC_USE_WIDE case SEND_WDTR: - if (sc->sc_state != AIC_CONNECTED) { - printf("%s: SEND_WDTR while not connected; sending NOOP\n", - sc->sc_dev.dv_xname); - AIC_BREAK(); - goto noop; - } AIC_ASSERT(sc->sc_nexus != NULL); ti = &sc->sc_tinfo[sc->sc_nexus->xs->sc_link->target]; sc->sc_omess[3] = MSG_EXTENDED; @@ -1735,6 +1735,7 @@ nextmsg: #endif case SEND_DEV_RESET: + sc->sc_flags |= AIC_ABORTING; sc->sc_omess[0] = MSG_BUS_DEV_RESET; n = 1; break; @@ -1755,26 +1756,18 @@ nextmsg: break; case SEND_ABORT: + sc->sc_flags |= AIC_ABORTING; sc->sc_omess[0] = MSG_ABORT; n = 1; break; - case 0: -#ifdef AIC_PICKY + default: printf("%s: unexpected MESSAGE OUT; sending NOOP\n", sc->sc_dev.dv_xname); AIC_BREAK(); -#endif - noop: sc->sc_omess[0] = MSG_NOOP; n = 1; break; - - default: - printf("%s: weird MESSAGE OUT; sending NOOP\n", - sc->sc_dev.dv_xname); - AIC_BREAK(); - goto noop; } sc->sc_omp = &sc->sc_omess[n]; @@ -1782,29 +1775,37 @@ nextbyte: /* Send message bytes. */ for (;;) { for (;;) { - sstat1 = inb(SSTAT1); - if ((sstat1 & (REQINIT|BUSFREE)) != 0) + sstat1 = inb(iobase + SSTAT1); + if ((sstat1 & (REQINIT | PHASECHG | BUSFREE)) != 0) break; /* Wait for REQINIT. XXX Need timeout. */ } - if ((sstat1 & (PHASECHG|BUSFREE)) != 0) { + if ((sstat1 & (PHASECHG | BUSFREE)) != 0) { /* * Target left MESSAGE OUT, possibly to reject * our message. + * + * If this is the last message being sent, then we + * deassert ATN, since either the target is going to + * ignore this message, or it's going to ask for a + * retransmission via MESSAGE PARITY ERROR (in which + * case we reassert ATN anyway). */ + if (sc->sc_msgpriq == 0) + outb(iobase + CLRSINT1, CLRATNO); goto out; } /* Clear ATN before last byte if this is the last message. */ if (n == 1 && sc->sc_msgpriq == 0) - outb(CLRSINT1, CLRATNO); + outb(iobase + CLRSINT1, CLRATNO); /* Send message byte. */ - outb(SCSIDAT, *--sc->sc_omp); + outb(iobase + SCSIDAT, *--sc->sc_omp); --n; /* Keep track of the last message we've sent any bytes of. */ sc->sc_lastmsg = sc->sc_currmsg; /* Wait for ACK to be negated. XXX Need timeout. */ - while ((inb(SCSISIG) & ACKI) != 0) + while ((inb(iobase + SCSISIG) & ACKI) != 0) ; if (n == 0) @@ -1827,7 +1828,7 @@ nextbyte: out: /* Disable REQ/ACK protocol. */ - outb(SXFRCTL0, CHEN); + outb(iobase + SXFRCTL0, CHEN); } /* aic_dataout_pio: perform a data transfer using the FIFO datapath in the aic6360 @@ -1842,87 +1843,102 @@ aic_dataout_pio(sc, p, n) u_char *p; int n; { + int iobase = sc->sc_iobase; register u_char dmastat; int out = 0; #define DOUTAMOUNT 128 /* Full FIFO */ /* Clear host FIFO and counter. */ - outb(DMACNTRL0, RSTFIFO|WRITE); + outb(iobase + DMACNTRL0, RSTFIFO | WRITE); /* Enable FIFOs. */ - outb(SXFRCTL0, SCSIEN|DMAEN|CHEN); - outb(DMACNTRL0, ENDMA|DWORDPIO|WRITE); + outb(iobase + SXFRCTL0, SCSIEN | DMAEN | CHEN); + outb(iobase + DMACNTRL0, ENDMA | DWORDPIO | WRITE); /* Turn off ENREQINIT for now. */ - outb(SIMODE1, ENSCSIRST|ENSCSIPERR|ENBUSFREE|ENPHASECHG); + outb(iobase + SIMODE1, + ENSCSIRST | ENSCSIPERR | ENBUSFREE | ENPHASECHG); /* I have tried to make the main loop as tight as possible. This * means that some of the code following the loop is a bit more * complex than otherwise. */ while (n > 0) { - int xfer; - for (;;) { - dmastat = inb(DMASTAT); - if ((dmastat & DFIFOEMP) != 0) + dmastat = inb(iobase + DMASTAT); + if ((dmastat & (DFIFOEMP | INTSTAT)) != 0) break; - if ((dmastat & INTSTAT) != 0) - goto phasechange; } - xfer = min(DOUTAMOUNT, n); + if ((dmastat & INTSTAT) != 0) + goto phasechange; + + if (n >= DOUTAMOUNT) { + n -= DOUTAMOUNT; + out += DOUTAMOUNT; + +#if AIC_USE_DWORDS + outsl(iobase + DMADATALONG, p, DOUTAMOUNT >> 2); +#else + outsw(iobase + DMADATA, p, DOUTAMOUNT >> 1); +#endif + + p += DOUTAMOUNT; + } else { + register int xfer; - AIC_MISC(("%d> ", xfer)); + xfer = n; + AIC_MISC(("%d> ", xfer)); - n -= xfer; - out += xfer; + n -= xfer; + out += xfer; #if AIC_USE_DWORDS - if (xfer >= 12) { - outsl(DMADATALONG, p, xfer>>2); - p += xfer & ~3; - xfer &= 3; - } + if (xfer >= 12) { + outsl(iobase + DMADATALONG, p, xfer >> 2); + p += xfer & ~3; + xfer &= 3; + } #else - if (xfer >= 8) { - outsw(DMADATA, p, xfer>>1); - p += xfer & ~1; - xfer &= 1; - } + if (xfer >= 8) { + outsw(iobase + DMADATA, p, xfer >> 1); + p += xfer & ~1; + xfer &= 1; + } #endif - if (xfer > 0) { - outb(DMACNTRL0, ENDMA|B8MODE|WRITE); - outsb(DMADATA, p, xfer); - p += xfer; - outb(DMACNTRL0, ENDMA|DWORDPIO|WRITE); + if (xfer > 0) { + outb(iobase + DMACNTRL0, ENDMA | B8MODE | WRITE); + outsb(iobase + DMADATA, p, xfer); + p += xfer; + outb(iobase + DMACNTRL0, ENDMA | DWORDPIO | WRITE); + } } } if (out == 0) { - outb(SXFRCTL1, BITBUCKET); + outb(iobase + SXFRCTL1, BITBUCKET); for (;;) { - if ((inb(DMASTAT) & INTSTAT) != 0) + if ((inb(iobase + DMASTAT) & INTSTAT) != 0) break; } - outb(SXFRCTL1, 0); + outb(iobase + SXFRCTL1, 0); AIC_MISC(("extra data ")); } else { /* See the bytes off chip */ for (;;) { - dmastat = inb(DMASTAT); - if ((dmastat & DFIFOEMP) != 0 && - (inb(SSTAT2) & SEMPTY) != 0) - break; + dmastat = inb(iobase + DMASTAT); if ((dmastat & INTSTAT) != 0) goto phasechange; + if ((dmastat & DFIFOEMP) != 0 && + (inb(iobase + SSTAT2) & SEMPTY) != 0) + break; } } phasechange: /* Stop the FIFO data path. */ - outb(SXFRCTL0, CHEN); - while ((inb(SXFRCTL0) & SCSIEN) != 0) + outb(iobase + SXFRCTL0, CHEN); + while ((inb(iobase + SXFRCTL0) & SCSIEN) != 0) ; if ((dmastat & INTSTAT) != 0) { @@ -1930,16 +1946,17 @@ phasechange: int amount; /* Stop transfers, do some accounting */ - amount = inb(FIFOSTAT) + (inb(SSTAT2) & 15); + amount = inb(iobase + FIFOSTAT) + (inb(iobase + SSTAT2) & 15); if (amount > 0) { out -= amount; - outb(SXFRCTL0, CHEN|CLRSTCNT|CLRCH); + outb(iobase + SXFRCTL0, CHEN | CLRSTCNT | CLRCH); AIC_MISC(("+%d ", amount)); } } /* Turn on ENREQINIT again. */ - outb(SIMODE1, ENSCSIRST|ENSCSIPERR|ENBUSFREE|ENREQINIT|ENPHASECHG); + outb(iobase + SIMODE1, + ENSCSIRST | ENSCSIPERR | ENBUSFREE | ENREQINIT | ENPHASECHG); return out; } @@ -1957,62 +1974,73 @@ aic_datain_pio(sc, p, n) u_char *p; int n; { + int iobase = sc->sc_iobase; register u_char dmastat; int in = 0; #define DINAMOUNT 128 /* Full FIFO */ /* Clear host FIFO and counter. */ - outb(DMACNTRL0, RSTFIFO); - /* Enable FIFOs */ - outb(SXFRCTL0, SCSIEN|DMAEN|CHEN); - outb(DMACNTRL0, ENDMA|DWORDPIO); + outb(iobase + DMACNTRL0, RSTFIFO); + /* Enable FIFOs. */ + outb(iobase + SXFRCTL0, SCSIEN | DMAEN | CHEN); + outb(iobase + DMACNTRL0, ENDMA | DWORDPIO); /* Turn off ENREQINIT for now. */ - outb(SIMODE1, ENSCSIRST|ENSCSIPERR|ENBUSFREE|ENPHASECHG); + outb(iobase + SIMODE1, + ENSCSIRST | ENSCSIPERR | ENBUSFREE | ENPHASECHG); /* We leave this loop if one or more of the following is true: * a) phase != PH_DATAIN && FIFOs are empty * b) SCSIRSTI is set (a reset has occurred) or busfree is detected. */ while (n > 0) { - int xfer; - /* Wait for fifo half full or phase mismatch */ for (;;) { - dmastat = inb(DMASTAT); - if ((dmastat & (DFIFOFULL|INTSTAT)) != 0) + dmastat = inb(iobase + DMASTAT); + if ((dmastat & (DFIFOFULL | INTSTAT)) != 0) break; } - if ((dmastat & DFIFOFULL) != 0) - xfer = min(DINAMOUNT, n); - else - xfer = min(inb(FIFOSTAT), n); + if ((dmastat & DFIFOFULL) != 0) { + n -= DINAMOUNT; + in += DINAMOUNT; + +#if AIC_USE_DWORDS + insl(iobase + DMADATALONG, p, DINAMOUNT >> 2); +#else + insw(iobase + DMADATA, p, DINAMOUNT >> 1); +#endif - AIC_MISC((">%d ", xfer)); + p += DINAMOUNT; + } else { + register int xfer; - n -= xfer; - in += xfer; + xfer = min(inb(iobase + FIFOSTAT), n); + AIC_MISC((">%d ", xfer)); + + n -= xfer; + in += xfer; #if AIC_USE_DWORDS - if (xfer >= 12) { - insl(DMADATALONG, p, xfer>>2); - p += xfer & ~3; - xfer &= 3; - } + if (xfer >= 12) { + insl(iobase + DMADATALONG, p, xfer >> 2); + p += xfer & ~3; + xfer &= 3; + } #else - if (xfer >= 8) { - insw(DMADATA, p, xfer>>1); - p += xfer & ~1; - xfer &= 1; - } + if (xfer >= 8) { + insw(iobase + DMADATA, p, xfer >> 1); + p += xfer & ~1; + xfer &= 1; + } #endif - if (xfer > 0) { - outb(DMACNTRL0, ENDMA|B8MODE); - insb(DMADATA, p, xfer); - p += xfer; - outb(DMACNTRL0, ENDMA|DWORDPIO); + if (xfer > 0) { + outb(iobase + DMACNTRL0, ENDMA | B8MODE); + insb(iobase + DMADATA, p, xfer); + p += xfer; + outb(iobase + DMACNTRL0, ENDMA | DWORDPIO); + } } if ((dmastat & INTSTAT) != 0) @@ -2026,23 +2054,24 @@ aic_datain_pio(sc, p, n) * FIFO is not empty, waste some bytes.... */ if (in == 0) { - outb(SXFRCTL1, BITBUCKET); + outb(iobase + SXFRCTL1, BITBUCKET); for (;;) { - if ((inb(DMASTAT) & INTSTAT) != 0) + if ((inb(iobase + DMASTAT) & INTSTAT) != 0) break; } - outb(SXFRCTL1, 0); + outb(iobase + SXFRCTL1, 0); AIC_MISC(("extra data ")); } phasechange: /* Stop the FIFO data path. */ - outb(SXFRCTL0, CHEN); - while ((inb(SXFRCTL0) & SCSIEN) != 0) + outb(iobase + SXFRCTL0, CHEN); + while ((inb(iobase + SXFRCTL0) & SCSIEN) != 0) ; /* Turn on ENREQINIT again. */ - outb(SIMODE1, ENSCSIRST|ENSCSIPERR|ENBUSFREE|ENREQINIT|ENPHASECHG); + outb(iobase + SIMODE1, + ENSCSIRST | ENSCSIPERR | ENBUSFREE | ENREQINIT | ENPHASECHG); return in; } @@ -2057,6 +2086,7 @@ aicintr(arg) void *arg; { register struct aic_softc *sc = arg; + int iobase = sc->sc_iobase; u_char sstat0, sstat1; register struct aic_acb *acb; register struct scsi_link *sc_link; @@ -2067,16 +2097,15 @@ aicintr(arg) * Clear INTEN. We enable it again before returning. This makes the * interrupt esssentially level-triggered. */ - outb(DMACNTRL0, 0); + outb(iobase + DMACNTRL0, 0); AIC_TRACE(("aicintr ")); loop: -gotintr: /* * First check for abnormal conditions, such as reset. */ - sstat1 = inb(SSTAT1); + sstat1 = inb(iobase + SSTAT1); AIC_MISC(("sstat1:0x%02x ", sstat1)); if ((sstat1 & SCSIRSTI) != 0) { @@ -2089,12 +2118,12 @@ gotintr: */ if ((sstat1 & SCSIPERR) != 0) { printf("%s: SCSI bus parity error\n", sc->sc_dev.dv_xname); - outb(CLRSINT1, CLRSCSIPERR); + outb(iobase + CLRSINT1, CLRSCSIPERR); if (sc->sc_prevphase == PH_MSGIN) { - aic_sched_msgout(SEND_PARITY_ERROR); sc->sc_flags |= AIC_DROP_MSGIN; + aic_sched_msgout(sc, SEND_PARITY_ERROR); } else - aic_sched_msgout(SEND_INIT_DET_ERR); + aic_sched_msgout(sc, SEND_INIT_DET_ERR); } /* @@ -2110,20 +2139,18 @@ gotintr: switch (sc->sc_state) { case AIC_IDLE: case AIC_SELECTING: - sstat0 = inb(SSTAT0); + sstat0 = inb(iobase + SSTAT0); AIC_MISC(("sstat0:0x%02x ", sstat0)); if ((sstat0 & TARGET) != 0) { /* * We don't currently support target mode. */ - printf("%s: target mode selected; going to bus free\n", + printf("%s: target mode selected; going to BUS FREE\n", sc->sc_dev.dv_xname); - outb(SCSISIG, 0); + outb(iobase + SCSISIG, 0); - sc->sc_state = AIC_IDLE; - aic_sched(sc); - goto out; + goto sched; } else if ((sstat0 & SELDI) != 0) { AIC_MISC(("reselected ")); @@ -2140,7 +2167,7 @@ gotintr: } /* Save reselection ID. */ - sc->sc_selid = inb(SELID); + sc->sc_selid = inb(iobase + SELID); sc->sc_state = AIC_RESELECTED; } else if ((sstat0 & SELDO) != 0) { @@ -2159,27 +2186,26 @@ gotintr: } AIC_ASSERT(sc->sc_nexus != NULL); acb = sc->sc_nexus; - sc_link = acb->xs->sc_link; ti = &sc->sc_tinfo[sc_link->target]; - if ((acb->xs->flags & SCSI_RESET) == 0) { - sc->sc_msgpriq = SEND_IDENTIFY; - if (acb->flags != ACB_ABORTED) { + + sc->sc_msgpriq = SEND_IDENTIFY; + if (acb->flags & ACB_RESET) + sc->sc_msgpriq |= SEND_DEV_RESET; + else if (acb->flags & ACB_ABORT) + sc->sc_msgpriq |= SEND_ABORT; + else { #if AIC_USE_SYNCHRONOUS - if ((ti->flags & DO_SYNC) != 0) - sc->sc_msgpriq |= SEND_SDTR; + if ((ti->flags & DO_SYNC) != 0) + sc->sc_msgpriq |= SEND_SDTR; #endif #if AIC_USE_WIDE - if ((ti->flags & DO_WIDE) != 0) - sc->sc_msgpriq |= SEND_WDTR; + if ((ti->flags & DO_WIDE) != 0) + sc->sc_msgpriq |= SEND_WDTR; #endif - } else { - sc->sc_flags |= AIC_ABORTING; - sc->sc_msgpriq |= SEND_ABORT; - } - } else - sc->sc_msgpriq = SEND_DEV_RESET; + } + acb->flags |= ACB_NEXUS; ti->lubusy |= (1 << sc_link->lun); /* Do an implicit RESTORE POINTERS. */ @@ -2188,6 +2214,10 @@ gotintr: sc->sc_cp = (u_char *)&acb->scsi_cmd; sc->sc_cleft = acb->scsi_cmd_length; + /* On our first connection, schedule a timeout. */ + if ((acb->xs->flags & SCSI_POLL) == 0) + timeout(aic_timeout, acb, (acb->timeout * hz) / 1000); + sc->sc_state = AIC_CONNECTED; } else if ((sstat1 & SELTO) != 0) { AIC_MISC(("selection timeout ")); @@ -2201,119 +2231,143 @@ gotintr: AIC_ASSERT(sc->sc_nexus != NULL); acb = sc->sc_nexus; - outb(SXFRCTL1, 0); - outb(SCSISEQ, ENRESELI); - outb(CLRSINT1, CLRSELTIMO); + outb(iobase + SXFRCTL1, 0); + outb(iobase + SCSISEQ, ENRESELI); + outb(iobase + CLRSINT1, CLRSELTIMO); + delay(250); acb->xs->error = XS_SELTIMEOUT; - untimeout(aic_timeout, acb); - delay(250); - aic_done(sc, acb); - goto out; + goto finish; } else { -#ifdef AIC_PICKY if (sc->sc_state != AIC_IDLE) { printf("%s: BUS FREE while not idle; state=%d\n", sc->sc_dev.dv_xname, sc->sc_state); AIC_BREAK(); goto out; } -#endif - aic_sched(sc); - goto out; + goto sched; } /* * Turn off selection stuff, and prepare to catch bus free * interrupts, parity errors, and phase changes. */ - outb(SXFRCTL1, 0); - outb(SCSISEQ, ENAUTOATNP); - outb(CLRSINT0, CLRSELDI|CLRSELDO); - outb(CLRSINT1, CLRBUSFREE|CLRPHASECHG); - outb(SIMODE0, 0); - outb(SIMODE1, ENSCSIRST|ENSCSIPERR|ENBUSFREE|ENREQINIT|ENPHASECHG); + outb(iobase + SXFRCTL0, CHEN | CLRSTCNT | CLRCH); + outb(iobase + SXFRCTL1, 0); + outb(iobase + SCSISEQ, ENAUTOATNP); + outb(iobase + CLRSINT0, CLRSELDI | CLRSELDO); + outb(iobase + CLRSINT1, CLRBUSFREE | CLRPHASECHG); + outb(iobase + SIMODE0, 0); + outb(iobase + SIMODE1, + ENSCSIRST | ENSCSIPERR | ENBUSFREE | ENREQINIT | ENPHASECHG); sc->sc_flags = 0; sc->sc_prevphase = PH_INVALID; goto dophase; } - outb(CLRSINT1, CLRPHASECHG); - if ((sstat1 & BUSFREE) != 0) { /* We've gone to BUS FREE phase. */ - outb(CLRSINT1, CLRBUSFREE); + outb(iobase + CLRSINT1, CLRBUSFREE | CLRPHASECHG); switch (sc->sc_state) { case AIC_RESELECTED: - sc->sc_state = AIC_IDLE; - aic_sched(sc); - break; + goto sched; case AIC_CONNECTED: + AIC_ASSERT(sc->sc_nexus != NULL); + acb = sc->sc_nexus; + +#if AIC_USE_SYNCHRONOUS + AIC_USE_WIDE + if (sc->sc_prevphase == PH_MSGOUT) { + /* + * If the target went to BUS FREE phase during + * or immediately after sending a SDTR or WDTR + * message, disable negotiation. + */ + sc_link = acb->xs->sc_link; + ti = &sc->sc_tinfo[sc_link->target]; + switch (sc->sc_lastmsg) { +#if AIC_USE_SYNCHRONOUS + case SEND_SDTR: + ti->flags &= ~DO_SYNC; + ti->period = ti->offset = 0; + break; +#endif +#if AIC_USE_WIDE + case SEND_WDTR: + ti->flags &= ~DO_WIDE; + ti->width = 0; + break; +#endif + } + } +#endif + if ((sc->sc_flags & AIC_ABORTING) == 0) { - printf("%s: unexpected BUS FREE; aborting\n", + /* + * Section 5.1.1 of the SCSI 2 spec suggests + * issuing a REQUEST SENSE following an + * unexpected disconnect. Some devices go into + * a contingent allegiance condition when + * disconnecting, and this is necessary to + * clean up their state. + */ + printf("%s: unexpected disconnect; sending REQUEST SENSE\n", sc->sc_dev.dv_xname); AIC_BREAK(); + aic_sense(sc, acb); + goto out; } - AIC_ASSERT(sc->sc_nexus != NULL); - acb = sc->sc_nexus; + acb->xs->error = XS_DRIVER_STUFFUP; goto finish; case AIC_DISCONNECT: AIC_ASSERT(sc->sc_nexus != NULL); acb = sc->sc_nexus; - sc->sc_state = AIC_IDLE; - sc->sc_nexus = NULL; TAILQ_INSERT_HEAD(&sc->nexus_list, acb, chain); - aic_sched(sc); - break; + sc->sc_nexus = NULL; + goto sched; case AIC_CMDCOMPLETE: AIC_ASSERT(sc->sc_nexus != NULL); acb = sc->sc_nexus; - finish: - untimeout(aic_timeout, acb); - aic_done(sc, acb); - break; + goto finish; } - goto out; } + outb(iobase + CLRSINT1, CLRPHASECHG); + dophase: if ((sstat1 & REQINIT) == 0) { /* Wait for REQINIT. */ goto out; } - sc->sc_phase = inb(SCSISIG) & PH_MASK; - outb(SCSISIG, sc->sc_phase); + sc->sc_phase = inb(iobase + SCSISIG) & PH_MASK; + outb(iobase + SCSISIG, sc->sc_phase); switch (sc->sc_phase) { case PH_MSGOUT: - /* If aborting, always handle MESSAGE OUT. */ - if ((sc->sc_state & AIC_CONNECTED) == 0 && - (sc->sc_flags & AIC_ABORTING) == 0) + if (sc->sc_state != AIC_CONNECTED && + sc->sc_state != AIC_RESELECTED) break; aic_msgout(sc); sc->sc_prevphase = PH_MSGOUT; goto loop; case PH_MSGIN: - if ((sc->sc_state & (AIC_CONNECTED|AIC_RESELECTED)) == 0) + if (sc->sc_state != AIC_CONNECTED && + sc->sc_state != AIC_RESELECTED) break; - if (aic_msgin(sc)) { - sc->sc_prevphase = PH_MSGIN; - goto gotintr; - } + aic_msgin(sc); sc->sc_prevphase = PH_MSGIN; goto loop; case PH_CMD: - if ((sc->sc_state & AIC_CONNECTED) == 0) + if (sc->sc_state != AIC_CONNECTED) break; #if AIC_DEBUG if ((aic_debug & AIC_SHOWMISC) != 0) { @@ -2330,7 +2384,7 @@ dophase: goto loop; case PH_DATAOUT: - if ((sc->sc_state & AIC_CONNECTED) == 0) + if (sc->sc_state != AIC_CONNECTED) break; AIC_MISC(("dataout dleft=%d ", sc->sc_dleft)); n = aic_dataout_pio(sc, sc->sc_dp, sc->sc_dleft); @@ -2340,7 +2394,7 @@ dophase: goto loop; case PH_DATAIN: - if ((sc->sc_state & AIC_CONNECTED) == 0) + if (sc->sc_state != AIC_CONNECTED) break; AIC_MISC(("datain ")); n = aic_datain_pio(sc, sc->sc_dp, sc->sc_dleft); @@ -2350,17 +2404,17 @@ dophase: goto loop; case PH_STAT: - if ((sc->sc_state & AIC_CONNECTED) == 0) + if (sc->sc_state != AIC_CONNECTED) break; AIC_ASSERT(sc->sc_nexus != NULL); acb = sc->sc_nexus; /* XXXX Don't clear FIFO. Wait for byte to come in. */ - outb(SXFRCTL0, CHEN|SPIOEN); - outb(DMACNTRL0, RSTFIFO); - acb->target_stat = inb(SCSIDAT); - outb(SXFRCTL0, CHEN); - outb(DMACNTRL0, RSTFIFO); - while ((inb(SXFRCTL0) & SCSIEN) != 0) + outb(iobase + SXFRCTL0, CHEN | SPIOEN); + outb(iobase + DMACNTRL0, RSTFIFO); + acb->target_stat = inb(iobase + SCSIDAT); + outb(iobase + SXFRCTL0, CHEN); + outb(iobase + DMACNTRL0, RSTFIFO); + while ((inb(iobase + SXFRCTL0) & SCSIEN) != 0) ; AIC_MISC(("target_stat=0x%02x ", acb->target_stat)); sc->sc_prevphase = PH_STAT; @@ -2373,8 +2427,18 @@ reset: aic_init(sc); return 1; +finish: + untimeout(aic_timeout, acb); + aic_done(sc, acb); + goto out; + +sched: + sc->sc_state = AIC_IDLE; + aic_sched(sc); + goto out; + out: - outb(DMACNTRL0, INTEN); + outb(iobase + DMACNTRL0, INTEN); return 1; } @@ -2384,11 +2448,17 @@ aic_abort(sc, acb) struct aic_acb *acb; { - if (sc->sc_nexus == acb) { - if (sc->sc_state == AIC_CONNECTED) { - sc->sc_flags |= AIC_ABORTING; - aic_sched_msgout(SEND_ABORT); - } + /* 2 secs for the abort */ + acb->timeout = AIC_ABORT_TIMEOUT; + acb->flags |= ACB_ABORT; + + if (acb == sc->sc_nexus) { + /* + * If we're still selecting, the message will be scheduled + * after selection is complete. + */ + if (sc->sc_state == AIC_CONNECTED) + aic_sched_msgout(sc, SEND_ABORT); } else { aic_dequeue(sc, acb); TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain); @@ -2412,20 +2482,15 @@ aic_timeout(arg) s = splbio(); - if (acb->flags == ACB_ABORTED) { + if (acb->flags & ACB_ABORT) { /* abort timed out */ printf(" AGAIN\n"); - acb->xs->retries = 0; - aic_done(sc, acb); + /* XXX Must reset! */ } else { /* abort the operation that has timed out */ printf("\n"); acb->xs->error = XS_TIMEOUT; - acb->flags = ACB_ABORTED; aic_abort(sc, acb); - /* 2 secs for the abort */ - if ((xs->flags & SCSI_POLL) == 0) - timeout(aic_timeout, acb, 2 * hz); } splx(s); @@ -2472,7 +2537,7 @@ void aic_print_active_acb() { struct aic_acb *acb; - struct aic_softc *sc = aiccd.cd_devs[0]; + struct aic_softc *sc = aic_cd.cd_devs[0]; printf("ready list:\n"); for (acb = sc->ready_list.tqh_first; acb != NULL; @@ -2491,16 +2556,20 @@ void aic_dump6360(sc) struct aic_softc *sc; { + int iobase = sc->sc_iobase; printf("aic6360: SCSISEQ=%x SXFRCTL0=%x SXFRCTL1=%x SCSISIG=%x\n", - inb(SCSISEQ), inb(SXFRCTL0), inb(SXFRCTL1), inb(SCSISIG)); + inb(iobase + SCSISEQ), inb(iobase + SXFRCTL0), + inb(iobase + SXFRCTL1), inb(iobase + SCSISIG)); printf(" SSTAT0=%x SSTAT1=%x SSTAT2=%x SSTAT3=%x SSTAT4=%x\n", - inb(SSTAT0), inb(SSTAT1), inb(SSTAT2), inb(SSTAT3), inb(SSTAT4)); + inb(iobase + SSTAT0), inb(iobase + SSTAT1), inb(iobase + SSTAT2), + inb(iobase + SSTAT3), inb(iobase + SSTAT4)); printf(" SIMODE0=%x SIMODE1=%x DMACNTRL0=%x DMACNTRL1=%x DMASTAT=%x\n", - inb(SIMODE0), inb(SIMODE1), inb(DMACNTRL0), inb(DMACNTRL1), - inb(DMASTAT)); + inb(iobase + SIMODE0), inb(iobase + SIMODE1), + inb(iobase + DMACNTRL0), inb(iobase + DMACNTRL1), + inb(iobase + DMASTAT)); printf(" FIFOSTAT=%d SCSIBUS=0x%x\n", - inb(FIFOSTAT), inb(SCSIBUS)); + inb(iobase + FIFOSTAT), inb(iobase + SCSIBUS)); } void |