diff options
author | 1996-04-21 22:14:33 +0000 | |
---|---|---|
committer | 1996-04-21 22:14:33 +0000 | |
commit | d724e01ae4dac35949585b9083e28ff2ba35b0b5 (patch) | |
tree | 37282f1ae947a4e9508b73ff86cad13f75eb9860 /sys/dev/isa | |
parent | no need to remove limits.h; another workaround exists (diff) | |
download | wireguard-openbsd-d724e01ae4dac35949585b9083e28ff2ba35b0b5.tar.xz wireguard-openbsd-d724e01ae4dac35949585b9083e28ff2ba35b0b5.zip |
partial sync with netbsd 960418, more to come
Diffstat (limited to 'sys/dev/isa')
39 files changed, 4859 insertions, 6581 deletions
diff --git a/sys/dev/isa/aha.c b/sys/dev/isa/aha.c index 4a0bb77f998..d8a95ec3f85 100644 --- a/sys/dev/isa/aha.c +++ b/sys/dev/isa/aha.c @@ -1,8 +1,10 @@ -/* $OpenBSD: aha.c,v 1.13 1996/03/20 01:00:35 mickey Exp $ */ -/* $NetBSD: aha1542.c,v 1.55 1995/12/24 02:31:06 mycroft Exp $ */ +/* $NetBSD: aha.c,v 1.7 1996/04/11 22:27:59 cgd Exp $ */ + +#define AHADIAG +#define integrate /* - * Copyright (c) 1994 Charles Hannum. All rights reserved. + * Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,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. * @@ -45,13 +47,8 @@ * functioning of this software in any circumstances. */ -/* - * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 - */ - #include <sys/types.h> #include <sys/param.h> -#include <sys/syslog.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/errno.h> @@ -64,99 +61,25 @@ #include <machine/pio.h> -#include <dev/isa/isavar.h> -#include <dev/isa/isadmavar.h> #include <scsi/scsi_all.h> #include <scsi/scsiconf.h> +#include <dev/isa/isavar.h> +#include <dev/isa/isadmavar.h> +#include <dev/isa/ahareg.h> + #ifndef DDB #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 - -#undef TUNE_1542 /* if bus speed check breaks the machine, undefine it */ - -/************************** board definitions *******************************/ - -/* - * I/O Port Interface - */ -#define AHA_BASE aha->sc_iobase -#define AHA_CTRL_STAT_PORT (AHA_BASE + 0x0) /* control & status */ -#define AHA_CMD_DATA_PORT (AHA_BASE + 0x1) /* cmds and datas */ -#define AHA_INTR_PORT (AHA_BASE + 0x2) /* Intr. stat */ - -/* - * AHA_CTRL_STAT bits (write) - */ -#define AHA_HRST 0x80 /* Hardware reset */ -#define AHA_SRST 0x40 /* Software reset */ -#define AHA_IRST 0x20 /* Interrupt reset */ -#define AHA_SCRST 0x10 /* SCSI bus reset */ - -/* - * AHA_CTRL_STAT bits (read) - */ -#define AHA_STST 0x80 /* Self test in Progress */ -#define AHA_DIAGF 0x40 /* Diagnostic Failure */ -#define AHA_INIT 0x20 /* Mbx Init required */ -#define AHA_IDLE 0x10 /* Host Adapter Idle */ -#define AHA_CDF 0x08 /* cmd/data out port full */ -#define AHA_DF 0x04 /* Data in port full */ -#define AHA_INVDCMD 0x01 /* Invalid command */ - /* - * AHA_CMD_DATA bits (write) - */ -#define AHA_NOP 0x00 /* No operation */ -#define AHA_MBX_INIT 0x01 /* Mbx initialization */ -#define AHA_START_SCSI 0x02 /* start scsi command */ -#define AHA_START_BIOS 0x03 /* start bios command */ -#define AHA_INQUIRE 0x04 /* Adapter Inquiry */ -#define AHA_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */ -#define AHA_SEL_TIMEOUT_SET 0x06 /* set selection time-out */ -#define AHA_BUS_ON_TIME_SET 0x07 /* set bus-on time */ -#define AHA_BUS_OFF_TIME_SET 0x08 /* set bus-off time */ -#define AHA_SPEED_SET 0x09 /* set transfer speed */ -#define AHA_DEV_GET 0x0a /* return installed devices */ -#define AHA_CONF_GET 0x0b /* return configuration data */ -#define AHA_TARGET_EN 0x0c /* enable target mode */ -#define AHA_SETUP_GET 0x0d /* return setup data */ -#define AHA_WRITE_CH2 0x1a /* write channel 2 buffer */ -#define AHA_READ_CH2 0x1b /* read channel 2 buffer */ -#define AHA_WRITE_FIFO 0x1c /* write fifo buffer */ -#define AHA_READ_FIFO 0x1d /* read fifo buffer */ -#define AHA_ECHO 0x1e /* Echo command data */ -#define AHA_EXT_BIOS 0x28 /* return extended bios info */ -#define AHA_MBX_ENABLE 0x29 /* enable mail box interface */ - -/* - * AHA_INTR_PORT bits (read) - */ -#define AHA_ANY_INTR 0x80 /* Any interrupt */ -#define AHA_SCRD 0x08 /* SCSI reset detected */ -#define AHA_HACC 0x04 /* Command complete */ -#define AHA_MBOA 0x02 /* MBX out empty */ -#define AHA_MBIF 0x01 /* MBX in full */ - -/* - * Mail box defs + * Mail box defs etc. + * these could be bigger but we need the aha_softc to fit on a single page.. */ #define AHA_MBX_SIZE 16 /* mail box size */ -#define AHA_CCB_MAX 32 /* store up to 32 CCBs at one time */ -#define CCB_HASH_SIZE 32 /* hash table size for phystokv */ +#define AHA_CCB_MAX 16 /* store up to 32 CCBs at one time */ +#define CCB_HASH_SIZE 16 /* hash table size for phystokv */ #define CCB_HASH_SHIFT 9 #define CCB_HASH(x) ((((long)(x))>>CCB_HASH_SHIFT) & (CCB_HASH_SIZE - 1)) @@ -166,165 +89,15 @@ else \ (wmb)++; -struct aha_mbx_out { - u_char cmd; - u_char ccb_addr[3]; -}; - -struct aha_mbx_in { - u_char stat; - u_char ccb_addr[3]; -}; - struct aha_mbx { struct aha_mbx_out mbo[AHA_MBX_SIZE]; struct aha_mbx_in mbi[AHA_MBX_SIZE]; + struct aha_mbx_out *cmbo; /* Collection Mail Box out */ struct aha_mbx_out *tmbo; /* Target Mail Box out */ struct aha_mbx_in *tmbi; /* Target Mail Box in */ }; -/* - * mbo.cmd values - */ -#define AHA_MBO_FREE 0x0 /* MBO entry is free */ -#define AHA_MBO_START 0x1 /* MBO activate entry */ -#define AHA_MBO_ABORT 0x2 /* MBO abort entry */ - -/* - * mbi.stat values - */ -#define AHA_MBI_FREE 0x0 /* MBI entry is free */ -#define AHA_MBI_OK 0x1 /* completed without error */ -#define AHA_MBI_ABORT 0x2 /* aborted ccb */ -#define AHA_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */ -#define AHA_MBI_ERROR 0x4 /* Completed with error */ - -/* FOR OLD VERSIONS OF THE !%$@ this may have to be 16 (yuk) */ -#define AHA_NSEG 17 /* Number of scatter gather segments <= 16 */ - /* allow 60 K i/o (min) */ - -struct aha_ccb { - u_char opcode; - u_char lun:3; - u_char data_in:1; /* must be 0 */ - u_char data_out:1; /* must be 0 */ - u_char target:3; - u_char scsi_cmd_length; - u_char req_sense_length; - u_char data_length[3]; - u_char data_addr[3]; - u_char link_addr[3]; - u_char link_id; - u_char host_stat; - u_char target_stat; - u_char reserved[2]; - struct scsi_generic scsi_cmd; - struct scsi_sense_data scsi_sense; - struct aha_scat_gath { - 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; - 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; /* number of phys segments of data */ -}; - -/* - * opcode fields - */ -#define AHA_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */ -#define AHA_TARGET_CCB 0x01 /* SCSI Target CCB */ -#define AHA_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scatter gather */ -#define AHA_RESET_CCB 0x81 /* SCSI Bus reset */ - -/* - * aha_ccb.host_stat values - */ -#define AHA_OK 0x00 /* cmd ok */ -#define AHA_LINK_OK 0x0a /* Link cmd ok */ -#define AHA_LINK_IT 0x0b /* Link cmd ok + int */ -#define AHA_SEL_TIMEOUT 0x11 /* Selection time out */ -#define AHA_OVER_UNDER 0x12 /* Data over/under run */ -#define AHA_BUS_FREE 0x13 /* Bus dropped at unexpected time */ -#define AHA_INV_BUS 0x14 /* Invalid bus phase/sequence */ -#define AHA_BAD_MBO 0x15 /* Incorrect MBO cmd */ -#define AHA_BAD_CCB 0x16 /* Incorrect ccb opcode */ -#define AHA_BAD_LINK 0x17 /* Not same values of LUN for links */ -#define AHA_INV_TARGET 0x18 /* Invalid target direction */ -#define AHA_CCB_DUP 0x19 /* Duplicate CCB received */ -#define AHA_INV_CCB 0x1a /* Invalid CCB or segment list */ -#define AHA_ABORTED 42 - -struct aha_setup { - u_char sync_neg:1; - u_char parity:1; - u_char:6; - u_char speed; - u_char bus_on; - u_char bus_off; - u_char num_mbx; - u_char mbx[3]; - struct { - u_char offset:4; - u_char period:3; - u_char valid:1; - } sync[8]; - u_char disc_sts; -}; - -struct aha_config { - u_char chan; - u_char intr; - u_char scsi_dev:3; - u_char:5; -}; - -struct aha_inquire { - u_char boardid; /* type of board */ - /* 0x31 = AHA-1540 */ - /* 0x41 = AHA-1540A/1542A/1542B */ - /* 0x42 = AHA-1640 */ - /* 0x43 = AHA-1542C */ - /* 0x44 = AHA-1542CF */ - /* 0x45 = AHA-1542CF, BIOS v2.01 */ - u_char spec_opts; /* special options ID */ - /* 0x41 = Board is standard model */ - u_char revision_1; /* firmware revision [0-9A-Z] */ - u_char revision_2; /* firmware revision [0-9A-Z] */ -}; - -struct aha_extbios { - u_char flags; /* Bit 3 == 1 extended bios enabled */ - u_char mailboxlock; /* mail box lock code to unlock it */ -}; - -#define INT9 0x01 -#define INT10 0x02 -#define INT11 0x04 -#define INT12 0x08 -#define INT14 0x20 -#define INT15 0x40 - -#define CHAN0 0x01 -#define CHAN5 0x20 -#define CHAN6 0x40 -#define CHAN7 0x80 - -/*********************************** end of board definitions***************/ - -#ifdef AHADEBUG -int aha_debug = 1; -#endif /*AHADEBUG */ +#define KVTOPHYS(x) vtophys(x) struct aha_softc { struct device sc_dev; @@ -334,28 +107,40 @@ struct aha_softc { int sc_iobase; int sc_irq, sc_drq; - struct aha_mbx aha_mbx; /* all the mailboxes */ - struct aha_ccb *ccbhash[CCB_HASH_SIZE]; - TAILQ_HEAD(, aha_ccb) free_ccb; - int numccbs; - int aha_scsi_dev; /* our scsi id */ + char sc_model[18], + sc_firmware[4]; + + struct aha_mbx sc_mbx; /* all the mailboxes */ +#define wmbx (&sc->sc_mbx) + struct aha_ccb *sc_ccbhash[CCB_HASH_SIZE]; + TAILQ_HEAD(, aha_ccb) sc_free_ccb, sc_waiting_ccb; + int sc_numccbs, sc_mbofull; + int sc_scsi_dev; /* our scsi id */ struct scsi_link sc_link; }; -int aha_cmd(); /* XXX must be varargs to prototype */ +#ifdef AHADEBUG +int aha_debug = 1; +#endif /* AHADEBUG */ + +int aha_cmd __P((int, struct aha_softc *, int, u_char *, int, u_char *)); +integrate void aha_finish_ccbs __P((struct aha_softc *)); int ahaintr __P((void *)); -void aha_free_ccb __P((struct aha_softc *, struct aha_ccb *, int)); +integrate void aha_reset_ccb __P((struct aha_softc *, struct aha_ccb *)); +void aha_free_ccb __P((struct aha_softc *, struct aha_ccb *)); +integrate void aha_init_ccb __P((struct aha_softc *, struct aha_ccb *)); struct aha_ccb *aha_get_ccb __P((struct aha_softc *, int)); struct aha_ccb *aha_ccb_phys_kv __P((struct aha_softc *, u_long)); -struct aha_mbx_out *aha_send_mbo __P((struct aha_softc *, int, struct aha_ccb *)); +void aha_queue_ccb __P((struct aha_softc *, struct aha_ccb *)); +void aha_collect_mbo __P((struct aha_softc *)); +void aha_start_ccbs __P((struct aha_softc *)); void aha_done __P((struct aha_softc *, struct aha_ccb *)); -int aha_find __P((struct aha_softc *)); +int aha_find __P((struct isa_attach_args *, struct aha_softc *)); void aha_init __P((struct aha_softc *)); +void aha_inquire_setup_information __P((struct aha_softc *)); void ahaminphys __P((struct buf *)); int aha_scsi_cmd __P((struct scsi_xfer *)); int aha_poll __P((struct aha_softc *, struct scsi_xfer *, int)); -int aha_set_bus_speed __P((struct aha_softc *)); -int aha_bus_speed_check __P((struct aha_softc *, int)); void aha_timeout __P((void *arg)); struct scsi_adapter aha_switch = { @@ -377,64 +162,75 @@ int ahaprobe __P((struct device *, void *, void *)); void ahaattach __P((struct device *, struct device *, void *)); int ahaprint __P((void *, char *)); -struct cfdriver ahacd = { - NULL, "aha", ahaprobe, ahaattach, DV_DULL, sizeof(struct aha_softc) +struct cfattach aha_ca = { + sizeof(struct aha_softc), ahaprobe, ahaattach +}; + +struct cfdriver aha_cd = { + NULL, "aha", DV_DULL }; #define AHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */ +#define AHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */ /* - * aha_cmd(aha,icnt, ocnt,wait, retval, opcode, args) + * aha_cmd(iobase, sc, icnt, ibuf, ocnt, obuf) + * * Activate Adapter command - * icnt: number of args (outbound bytes written after opcode) + * icnt: number of args (outbound bytes including opcode) + * ibuf: argument buffer * ocnt: number of expected returned bytes + * obuf: result buffer * wait: number of seconds to wait for response - * retval: buffer where to place returned bytes - * opcode: opcode AHA_NOP, AHA_MBX_INIT, AHA_START_SCSI ... - * args: parameters * - * Performs an adapter command through the ports. Not to be confused - * with a scsi command, which is read in via the dma. One of the adapter - * commands tells it to read in a scsi command but that one is done - * separately. This is only called during set-up. + * Performs an adapter command through the ports. Not to be confused with a + * scsi command, which is read in via the dma; one of the adapter commands + * tells it to read in a scsi command. */ int -aha_cmd(aha, icnt, ocnt, wait, retval, opcode, args) - struct aha_softc *aha; - int icnt, ocnt, wait; - u_char *retval; - unsigned opcode; - u_char args; +aha_cmd(iobase, sc, icnt, ibuf, ocnt, obuf) + int iobase; + struct aha_softc *sc; + int icnt, ocnt; + u_char *ibuf, *obuf; { - unsigned *ic = &opcode; - u_char oc; - register i; - int sts; + const char *name; + register int i; + int wait; + u_char sts; + u_char opcode = ibuf[0]; + + if (sc == NULL) + name = sc->sc_dev.dv_xname; + else + name = "(probe)"; /* - * multiply the wait argument by a big constant - * zero defaults to 1 sec.. - * all wait loops are in 50uSec cycles + * Calculate a reasonable timeout for the command. */ - if (wait) - wait *= 20000; - else - wait = 20000; + switch (opcode) { + case AHA_INQUIRE_DEVICES: + wait = 15 * 20000; + break; + default: + wait = 1 * 20000; + break; + } + /* * Wait for the adapter to go idle, unless it's one of * the commands which don't need this */ - if (opcode != AHA_MBX_INIT && opcode != AHA_START_SCSI) { - i = 20000; /*do this for upto about a second */ - while (--i) { - sts = inb(AHA_CTRL_STAT_PORT); - if (sts & AHA_IDLE) + if (opcode != AHA_MBO_INTR_EN) { + for (i = 20000; i; i--) { /* 1 sec? */ + sts = inb(iobase + AHA_STAT_PORT); + if (sts & AHA_STAT_IDLE) break; delay(50); } if (!i) { printf("%s: aha_cmd, host not idle(0x%x)\n", - aha->sc_dev.dv_xname, sts); + name, sts); return ENXIO; } } @@ -443,71 +239,68 @@ aha_cmd(aha, icnt, ocnt, wait, retval, opcode, args) * queue feeding to us. */ if (ocnt) { - while ((inb(AHA_CTRL_STAT_PORT)) & AHA_DF) - inb(AHA_CMD_DATA_PORT); + while ((inb(iobase + AHA_STAT_PORT)) & AHA_STAT_DF) + inb(iobase + AHA_DATA_PORT); } /* * Output the command and the number of arguments given * for each byte, first check the port is empty. */ - icnt++; - /* include the command */ while (icnt--) { - sts = inb(AHA_CTRL_STAT_PORT); for (i = wait; i; i--) { - sts = inb(AHA_CTRL_STAT_PORT); - if (!(sts & AHA_CDF)) + sts = inb(iobase + AHA_STAT_PORT); + if (!(sts & AHA_STAT_CDF)) break; delay(50); } if (!i) { - if (opcode != AHA_INQUIRE) - printf("%s: aha_cmd, cmd/data port full\n", - aha->sc_dev.dv_xname); - outb(AHA_CTRL_STAT_PORT, AHA_SRST); + if (opcode != AHA_INQUIRE_REVISION) + printf("%s: aha_cmd, cmd/data port full\n", name); + outb(iobase + AHA_CTRL_PORT, AHA_CTRL_SRST); return ENXIO; } - outb(AHA_CMD_DATA_PORT, (u_char) (*ic++)); + outb(iobase + AHA_CMD_PORT, *ibuf++); } /* * If we expect input, loop that many times, each time, * looking for the data register to have valid data */ while (ocnt--) { - sts = inb(AHA_CTRL_STAT_PORT); for (i = wait; i; i--) { - sts = inb(AHA_CTRL_STAT_PORT); - if (sts & AHA_DF) + sts = inb(iobase + AHA_STAT_PORT); + if (sts & AHA_STAT_DF) break; delay(50); } if (!i) { - if (opcode != AHA_INQUIRE) + if (opcode != AHA_INQUIRE_REVISION) printf("%s: aha_cmd, cmd/data port empty %d\n", - aha->sc_dev.dv_xname, ocnt); - outb(AHA_CTRL_STAT_PORT, AHA_SRST); + name, ocnt); + outb(iobase + AHA_CTRL_PORT, AHA_CTRL_SRST); return ENXIO; } - oc = inb(AHA_CMD_DATA_PORT); - if (retval) - *retval++ = oc; + *obuf++ = inb(iobase + AHA_DATA_PORT); } /* - * Wait for the board to report a finised instruction + * Wait for the board to report a finished instruction. + * We may get an extra interrupt for the HACC signal, but this is + * unimportant. */ - i = 20000; - while (--i) { - sts = inb(AHA_INTR_PORT); - if (sts & AHA_HACC) - break; - delay(50); - } - if (!i) { - printf("%s: aha_cmd, host not finished(0x%x)\n", - aha->sc_dev.dv_xname, sts); - return ENXIO; + if (opcode != AHA_MBO_INTR_EN) { + for (i = 20000; i; i--) { /* 1 sec? */ + sts = inb(iobase + AHA_INTR_PORT); + /* XXX Need to save this in the interrupt handler? */ + if (sts & AHA_INTR_HACC) + break; + delay(50); + } + if (!i) { + printf("%s: aha_cmd, host not finished(0x%x)\n", + name, sts); + return ENXIO; + } } - outb(AHA_CTRL_STAT_PORT, AHA_IRST); + outb(iobase + AHA_CTRL_PORT, AHA_CTRL_IRST); return 0; } @@ -522,43 +315,20 @@ ahaprobe(parent, match, aux) struct device *parent; void *match, *aux; { - struct aha_softc *aha = match; - struct isa_attach_args *ia = aux; + register struct isa_attach_args *ia = aux; #ifdef NEWCONFIG if (ia->ia_iobase == IOBASEUNK) return 0; #endif - aha->sc_iobase = ia->ia_iobase; - - /* - * Try initialise a unit at this location - * sets up dma and bus speed, loads aha->sc_irq - */ - if (aha_find(aha) != 0) + /* See if there is a unit at this location. */ + if (aha_find(ia, NULL) != 0) return 0; - if (ia->ia_irq != IRQUNK) { - if (ia->ia_irq != aha->sc_irq) { - printf("%s: irq mismatch; kernel configured %d != board configured %d\n", - aha->sc_dev.dv_xname, ia->ia_irq, aha->sc_irq); - return 0; - } - } else - ia->ia_irq = aha->sc_irq; - - if (ia->ia_drq != DRQUNK) { - if (ia->ia_drq != aha->sc_drq) { - printf("%s: drq mismatch; kernel configured %d != board configured %d\n", - aha->sc_dev.dv_xname, ia->ia_drq, aha->sc_drq); - return 0; - } - } else - ia->ia_drq = aha->sc_drq; - ia->ia_msize = 0; ia->ia_iosize = 4; + /* IRQ and DRQ set by aha_find(). */ return 1; } @@ -567,6 +337,7 @@ ahaprint(aux, name) void *aux; char *name; { + if (name != NULL) printf("%s: scsibus ", name); return UNCONF; @@ -581,274 +352,272 @@ ahaattach(parent, self, aux) void *aux; { struct isa_attach_args *ia = aux; - struct aha_softc *aha = (void *)self; + struct aha_softc *sc = (void *)self; - if (ia->ia_drq != DRQUNK) - isadma_cascade(ia->ia_drq); + if (aha_find(ia, sc) != 0) + panic("ahaattach: aha_find of %s failed", self->dv_xname); + sc->sc_iobase = ia->ia_iobase; - aha_init(aha); - TAILQ_INIT(&aha->free_ccb); + if (sc->sc_drq != DRQUNK) + isa_dmacascade(sc->sc_drq); + + aha_inquire_setup_information(sc); + aha_init(sc); + TAILQ_INIT(&sc->sc_free_ccb); + TAILQ_INIT(&sc->sc_waiting_ccb); /* * fill in the prototype scsi_link. */ - aha->sc_link.adapter_softc = aha; - aha->sc_link.adapter_target = aha->aha_scsi_dev; - aha->sc_link.adapter = &aha_switch; - aha->sc_link.device = &aha_dev; - aha->sc_link.openings = 2; - - printf("\n"); + sc->sc_link.adapter_softc = sc; + sc->sc_link.adapter_target = sc->sc_scsi_dev; + sc->sc_link.adapter = &aha_switch; + sc->sc_link.device = &aha_dev; + sc->sc_link.openings = 2; #ifdef NEWCONFIG - isa_establish(&aha->sc_id, &aha->sc_dev); + isa_establish(&sc->sc_id, &sc->sc_dev); #endif - aha->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_BIO, ahaintr, - aha, aha->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, sc->sc_irq, IST_EDGE, + IPL_BIO, ahaintr, sc); /* * ask the adapter what subunits are present */ - config_found(self, &aha->sc_link, ahaprint); + config_found(self, &sc->sc_link, ahaprint); } -/* - * Catch an interrupt from the adaptor - */ -int -ahaintr(arg) - void *arg; +integrate void +aha_finish_ccbs(sc) + struct aha_softc *sc; { - struct aha_softc *aha = arg; struct aha_mbx_in *wmbi; - struct aha_mbx *wmbx; struct aha_ccb *ccb; - u_char stat; int i; - int found = 0; -#ifdef AHADEBUG - printf("%s: ahaintr ", aha->sc_dev.dv_xname); -#endif /*AHADEBUG */ - - /* - * First acknowlege the interrupt, Then if it's not telling about - * a completed operation just return. - */ - stat = inb(AHA_INTR_PORT); - if ((stat & (AHA_MBOA | AHA_MBIF)) == 0) { - outb(AHA_CTRL_STAT_PORT, AHA_IRST); - return -1; /* XXX */ - } + wmbi = wmbx->tmbi; - /* Mail box out empty? */ - if (stat & AHA_MBOA) { - /* Disable MBO available interrupt. */ - outb(AHA_CMD_DATA_PORT, AHA_MBO_INTR_EN); - for (i = 100000; i; i--) { - if (!(inb(AHA_CTRL_STAT_PORT) & AHA_CDF)) - break; - delay(10); - } - if (!i) { - printf("%s: ahaintr, cmd/data port full\n", - aha->sc_dev.dv_xname); - outb(AHA_CTRL_STAT_PORT, AHA_SRST); - return 1; + if (wmbi->stat == AHA_MBI_FREE) { + for (i = 0; i < AHA_MBX_SIZE; i++) { + if (wmbi->stat != AHA_MBI_FREE) { + printf("%s: mbi not in round-robin order\n", + sc->sc_dev.dv_xname); + goto AGAIN; + } + aha_nextmbx(wmbi, wmbx, mbi); } - outb(AHA_CMD_DATA_PORT, 0x00); /* Disable */ - wakeup(&aha->aha_mbx); +#ifdef AHADIAGnot + printf("%s: mbi interrupt with no full mailboxes\n", + sc->sc_dev.dv_xname); +#endif + return; } - /* Mail box in full? */ - if ((stat & AHA_MBIF) == 0) - return 1; - wmbx = &aha->aha_mbx; - wmbi = wmbx->tmbi; AGAIN: - while (wmbi->stat != AHA_MBI_FREE) { - ccb = aha_ccb_phys_kv(aha, _3btol(wmbi->ccb_addr)); + do { + ccb = aha_ccb_phys_kv(sc, phystol(wmbi->ccb_addr)); if (!ccb) { - wmbi->stat = AHA_MBI_FREE; - printf("%s: BAD CCB ADDR!\n", aha->sc_dev.dv_xname); - continue; + printf("%s: bad mbi ccb pointer; skipping\n", + sc->sc_dev.dv_xname); + goto next; } - found++; + +#ifdef AHADEBUG + if (aha_debug) { + u_char *cp = &ccb->scsi_cmd; + printf("op=%x %x %x %x %x %x\n", + cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); + printf("stat %x for mbi addr = 0x%08x, ", + wmbi->stat, wmbi); + printf("ccb addr = 0x%x\n", ccb); + } +#endif /* AHADEBUG */ + switch (wmbi->stat) { case AHA_MBI_OK: case AHA_MBI_ERROR: + if ((ccb->flags & CCB_ABORT) != 0) { + /* + * If we already started an abort, wait for it + * to complete before clearing the CCB. We + * could instead just clear CCB_SENDING, but + * what if the mailbox was already received? + * The worst that happens here is that we clear + * the CCB a bit later than we need to. BFD. + */ + goto next; + } break; case AHA_MBI_ABORT: - ccb->host_stat = AHA_ABORTED; - break; - case AHA_MBI_UNKNOWN: - ccb = 0; + /* + * Even if the CCB wasn't found, we clear it anyway. + * See preceeding comment. + */ break; default: - panic("Impossible mbxi status"); - } -#ifdef AHADEBUG - if (aha_debug && ccb) { - u_char *cp = &ccb->scsi_cmd; - printf("op=%x %x %x %x %x %x\n", - cp[0], cp[1], cp[2], - cp[3], cp[4], cp[5]); - printf("stat %x for mbi addr = 0x%08x, ", - wmbi->stat, wmbi); - printf("ccb addr = 0x%x\n", ccb); + printf("%s: bad mbi status %02x; skipping\n", + sc->sc_dev.dv_xname, wmbi->stat); + goto next; } -#endif /* AHADEBUG */ + + untimeout(aha_timeout, ccb); + aha_done(sc, ccb); + + next: wmbi->stat = AHA_MBI_FREE; - if (ccb) { - untimeout(aha_timeout, ccb); - aha_done(aha, ccb); - } aha_nextmbx(wmbi, wmbx, mbi); - } - if (!found) { - for (i = 0; i < AHA_MBX_SIZE; i++) { - if (wmbi->stat != AHA_MBI_FREE) { - found++; - break; - } - aha_nextmbx(wmbi, wmbx, mbi); - } - if (!found) { -#if 0 - printf("%s: mbi interrupt with no full mailboxes\n", - aha->sc_dev.dv_xname); + } while (wmbi->stat != AHA_MBI_FREE); + + wmbx->tmbi = wmbi; +} + +/* + * Catch an interrupt from the adaptor + */ +int +ahaintr(arg) + void *arg; +{ + struct aha_softc *sc = arg; + int iobase = sc->sc_iobase; + u_char sts; + +#ifdef AHADEBUG + printf("%s: ahaintr ", sc->sc_dev.dv_xname); +#endif /*AHADEBUG */ + + /* + * First acknowlege the interrupt, Then if it's not telling about + * a completed operation just return. + */ + sts = inb(iobase + AHA_INTR_PORT); + if ((sts & AHA_INTR_ANYINTR) == 0) + return 0; + outb(iobase + AHA_CTRL_PORT, AHA_CTRL_IRST); + +#ifdef AHADIAG + /* Make sure we clear CCB_SENDING before finishing a CCB. */ + aha_collect_mbo(sc); #endif - } else { - found = 0; - goto AGAIN; - } + + /* Mail box out empty? */ + if (sts & AHA_INTR_MBOA) { + struct aha_toggle toggle; + + toggle.cmd.opcode = AHA_MBO_INTR_EN; + toggle.cmd.enable = 0; + aha_cmd(iobase, sc, sizeof(toggle.cmd), (u_char *)&toggle.cmd, 0, + (u_char *)0); + aha_start_ccbs(sc); } - wmbx->tmbi = wmbi; - outb(AHA_CTRL_STAT_PORT, AHA_IRST); + + /* Mail box in full? */ + if (sts & AHA_INTR_MBIF) + aha_finish_ccbs(sc); + return 1; } +integrate void +aha_reset_ccb(sc, ccb) + struct aha_softc *sc; + struct aha_ccb *ccb; +{ + + ccb->flags = 0; +} + /* - * A ccb (and hence a mbx-out is put onto the - * free list. + * A ccb is put onto the free list. */ void -aha_free_ccb(aha, ccb, flags) - struct aha_softc *aha; +aha_free_ccb(sc, ccb) + struct aha_softc *sc; struct aha_ccb *ccb; - int flags; { - int s, hashnum; - struct aha_ccb **hashccb; + int s; 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 = &aha->ccbhash[hashnum]; - - while (*hashccb) { - if ((*hashccb)->ccb_phys[0].addr == ccb->ccb_phys[0].addr) { - *hashccb = (*hashccb)->nexthash; - break; - } - hashccb = &(*hashccb)->nexthash; - } - - ccb->flags = CCB_FREE; - TAILQ_INSERT_HEAD(&aha->free_ccb, ccb, chain); + aha_reset_ccb(sc, ccb); + TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, chain); /* * If there were none, wake anybody waiting for one to come free, * starting with queued entries. */ if (ccb->chain.tqe_next == 0) - wakeup(&aha->free_ccb); + wakeup(&sc->sc_free_ccb); splx(s); } -static inline void -aha_init_ccb(aha, ccb) - struct aha_softc *aha; - struct aha_ccb *ccb; -{ - bzero(ccb, sizeof(struct aha_ccb)); -} - -static inline void -aha_reset_ccb(aha, ccb) - struct aha_softc *aha; +integrate void +aha_init_ccb(sc, ccb) + 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); } /* * Get a free ccb + * + * If there are none, see if we can allocate a new one. If so, put it in + * the hash table too otherwise either return an error or sleep. */ struct aha_ccb * -aha_get_ccb(aha, flags) - struct aha_softc *aha; +aha_get_ccb(sc, flags) + struct aha_softc *sc; int flags; { struct aha_ccb *ccb; - int hashnum, mflags, s; + int 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 + * If we can and have to, sleep waiting for one to come free + * but only if we can't allocate a new one. */ for (;;) { - ccb = aha->free_ccb.tqh_first; + ccb = sc->sc_free_ccb.tqh_first; if (ccb) { - TAILQ_REMOVE(&aha->free_ccb, ccb, chain); + TAILQ_REMOVE(&sc->sc_free_ccb, ccb, chain); break; } - if (aha->numccbs < AHA_CCB_MAX) { - if (ccb = (struct aha_ccb *) malloc(sizeof(struct aha_ccb), - M_TEMP, M_NOWAIT)) { - aha_init_ccb(aha, ccb); - aha->numccbs++; - } else { + if (sc->sc_numccbs < AHA_CCB_MAX) { + ccb = (struct aha_ccb *) malloc(sizeof(struct aha_ccb), + M_TEMP, M_NOWAIT); + if (!ccb) { printf("%s: can't malloc ccb\n", - aha->sc_dev.dv_xname); + sc->sc_dev.dv_xname); goto out; } + aha_init_ccb(sc, ccb); + sc->sc_numccbs++; break; } if ((flags & SCSI_NOSLEEP) != 0) goto out; - tsleep(&aha->free_ccb, PRIBIO, "ahaccb", 0); + tsleep(&sc->sc_free_ccb, PRIBIO, "ahaccb", 0); } - 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; - } + ccb->flags |= CCB_ALLOC; out: splx(s); @@ -856,74 +625,116 @@ out: } /* - * given a physical address, find the ccb that it corresponds to. + * Given a physical address, find the ccb that it corresponds to. */ struct aha_ccb * -aha_ccb_phys_kv(aha, ccb_phys) - struct aha_softc *aha; +aha_ccb_phys_kv(sc, ccb_phys) + struct aha_softc *sc; u_long ccb_phys; { int hashnum = CCB_HASH(ccb_phys); - struct aha_ccb *res = aha->ccbhash[hashnum]; + struct aha_ccb *ccb = sc->sc_ccbhash[hashnum]; - while (res) { - if (res->ccb_phys[0].addr == ccb_phys) + while (ccb) { + if (ccb->hashkey == ccb_phys) break; - res = res->nexthash; + ccb = ccb->nexthash; } + return ccb; +} - return res; +/* + * Queue a CCB to be sent to the controller, and send it if possible. + */ +void +aha_queue_ccb(sc, ccb) + struct aha_softc *sc; + struct aha_ccb *ccb; +{ + + TAILQ_INSERT_TAIL(&sc->sc_waiting_ccb, ccb, chain); + aha_start_ccbs(sc); } /* - * Get a mbo and send the ccb. + * Garbage collect mailboxes that are no longer in use. */ -struct aha_mbx_out * -aha_send_mbo(aha, cmd, ccb) - struct aha_softc *aha; - int cmd; +void +aha_collect_mbo(sc) + struct aha_softc *sc; +{ + struct aha_mbx_out *wmbo; /* Mail Box Out pointer */ struct aha_ccb *ccb; + + wmbo = wmbx->cmbo; + + while (sc->sc_mbofull > 0) { + if (wmbo->cmd != AHA_MBO_FREE) + break; + +#ifdef AHADIAG + ccb = aha_ccb_phys_kv(sc, phystol(wmbo->ccb_addr)); + ccb->flags &= ~CCB_SENDING; +#endif + + --sc->sc_mbofull; + aha_nextmbx(wmbo, wmbx, mbo); + } + + wmbx->cmbo = wmbo; +} + +/* + * Send as many CCBs as we have empty mailboxes for. + */ +void +aha_start_ccbs(sc) + struct aha_softc *sc; { + int iobase = sc->sc_iobase; struct aha_mbx_out *wmbo; /* Mail Box Out pointer */ - struct aha_mbx *wmbx; /* Mail Box pointer specified unit */ + struct aha_ccb *ccb; int i; - /* Get the target out mail box pointer and increment. */ - wmbx = &aha->aha_mbx; wmbo = wmbx->tmbo; - aha_nextmbx(wmbx->tmbo, wmbx, mbo); - /* - * Check the outmail box is free or not. - * Note: Under the normal operation, it shuld NOT happen to wait. - */ - while (wmbo->cmd != AHA_MBO_FREE) { - /* Enable mbo available interrupt. */ - outb(AHA_CMD_DATA_PORT, AHA_MBO_INTR_EN); - for (i = 100000; i; i--) { - if (!(inb(AHA_CTRL_STAT_PORT) & AHA_CDF)) + while (ccb = sc->sc_waiting_ccb.tqh_first) { + if (sc->sc_mbofull >= AHA_MBX_SIZE) { + aha_collect_mbo(sc); + if (sc->sc_mbofull >= AHA_MBX_SIZE) { + struct aha_toggle toggle; + + toggle.cmd.opcode = AHA_MBO_INTR_EN; + toggle.cmd.enable = 1; + aha_cmd(iobase, sc, sizeof(toggle.cmd), + (u_char *)&toggle.cmd, 0, (u_char *)0); break; - delay(10); - } - if (!i) { - printf("%s: aha_send_mbo, cmd/data port full\n", - aha->sc_dev.dv_xname); - outb(AHA_CTRL_STAT_PORT, AHA_SRST); - return NULL; + } } - outb(AHA_CMD_DATA_PORT, 0x01); /* Enable */ - tsleep(wmbx, PRIBIO, "ahasnd", 0);/*XXX can't do this */ - } - /* Link ccb to mbo. */ - lto3b(ccb->ccb_phys[0].addr, wmbo->ccb_addr); - ccb->mbx = wmbo; - wmbo->cmd = cmd; + TAILQ_REMOVE(&sc->sc_waiting_ccb, ccb, chain); +#ifdef AHADIAG + ccb->flags |= CCB_SENDING; +#endif + + /* Link ccb to mbo. */ + ltophys(KVTOPHYS(ccb), wmbo->ccb_addr); + if (ccb->flags & CCB_ABORT) + wmbo->cmd = AHA_MBO_ABORT; + else + wmbo->cmd = AHA_MBO_START; - /* Sent it! */ - outb(AHA_CMD_DATA_PORT, AHA_START_SCSI); + /* Tell the card to poll immediately. */ + outb(iobase + AHA_CMD_PORT, AHA_START_SCSI); - return wmbo; + if ((ccb->xs->flags & SCSI_POLL) == 0) + timeout(aha_timeout, ccb, (ccb->timeout * hz) / 1000); + + ++sc->sc_mbofull; + aha_nextmbx(wmbo, wmbx, mbo); + } + + wmbx->tmbo = wmbo; } /* @@ -932,8 +743,8 @@ aha_send_mbo(aha, cmd, ccb) * went. Wake up the owner if waiting */ void -aha_done(aha, ccb) - struct aha_softc *aha; +aha_done(sc, ccb) + struct aha_softc *sc; struct aha_ccb *ccb; { struct scsi_sense_data *s1, *s2; @@ -944,23 +755,29 @@ aha_done(aha, ccb) * Otherwise, put the results of the operation * into the xfer and call whoever started it */ - if ((xs->flags & INUSE) == 0) { - printf("%s: exiting but not in use!\n", aha->sc_dev.dv_xname); +#ifdef AHADIAG + if (ccb->flags & CCB_SENDING) { + printf("%s: exiting ccb still in transit!\n", sc->sc_dev.dv_xname); + Debugger(); + return; + } +#endif + if ((ccb->flags & CCB_ALLOC) == 0) { + printf("%s: exiting ccb not allocated!\n", sc->sc_dev.dv_xname); Debugger(); + return; } if (xs->error == XS_NOERROR) { if (ccb->host_stat != AHA_OK) { switch (ccb->host_stat) { - case AHA_ABORTED: - xs->error = XS_DRIVER_STUFFUP; - break; case AHA_SEL_TIMEOUT: /* No response */ xs->error = XS_SELTIMEOUT; break; default: /* Other scsi protocol messes */ printf("%s: host_stat %x\n", - aha->sc_dev.dv_xname, ccb->host_stat); + sc->sc_dev.dv_xname, ccb->host_stat); xs->error = XS_DRIVER_STUFFUP; + break; } } else if (ccb->target_stat != SCSI_OK) { switch (ccb->target_stat) { @@ -976,27 +793,15 @@ aha_done(aha, ccb) break; default: printf("%s: target_stat %x\n", - aha->sc_dev.dv_xname, ccb->target_stat); + sc->sc_dev.dv_xname, ccb->target_stat); xs->error = XS_DRIVER_STUFFUP; + break; } } 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(aha, ccb, xs->flags); scsi_done(xs); } @@ -1004,147 +809,108 @@ aha_done(aha, ccb) * Find the board and find its irq/drq */ int -aha_find(aha) - struct aha_softc *aha; +aha_find(ia, sc) + struct isa_attach_args *ia; + struct aha_softc *sc; { - volatile int i, sts; - struct aha_config conf; - struct aha_inquire inquire; - struct aha_extbios extbios; + int iobase = ia->ia_iobase; + int i; + u_char sts; + struct aha_config config; + int irq, drq; /* * reset board, If it doesn't respond, assume * that it's not there.. good for the probe */ - outb(AHA_CTRL_STAT_PORT, AHA_HRST | AHA_SRST); + outb(iobase + AHA_CTRL_PORT, AHA_CTRL_HRST | AHA_CTRL_SRST); + delay(100); for (i = AHA_RESET_TIMEOUT; i; i--) { - sts = inb(AHA_CTRL_STAT_PORT); - if (sts == (AHA_IDLE | AHA_INIT)) + sts = inb(iobase + AHA_STAT_PORT); + if (sts == (AHA_STAT_IDLE | AHA_STAT_INIT)) break; delay(1000); /* calibrated in msec */ } if (!i) { -#ifdef AHADEBUG +#ifdef AHADEBUG if (aha_debug) printf("aha_find: No answer from adaptec board\n"); -#endif /*AHADEBUG */ - return ENXIO; - } - - /* - * Assume we have a board at this stage, do an adapter inquire - * to find out what type of controller it is. If the command - * fails, we assume it's either a crusty board or an old 1542 - * clone, and skip the board-specific stuff. - */ - if (aha_cmd(aha, 0, sizeof(inquire), 1, &inquire, AHA_INQUIRE)) { - /* - * aha_cmd() already started the reset. It's not clear we - * even need to bother here. - */ - for (i = AHA_RESET_TIMEOUT; i; i--) { - sts = inb(AHA_CTRL_STAT_PORT); - if (sts == (AHA_IDLE | AHA_INIT)) - break; - delay(1000); - } - if (!i) { -#ifdef AHADEBUG - printf("aha_init: soft reset failed\n"); -#endif /* AHADEBUG */ - return ENXIO; - } -#ifdef AHADEBUG - printf("aha_init: inquire command failed\n"); #endif /* AHADEBUG */ - goto noinquire; - } -#ifdef AHADEBUG - printf("%s: inquire %x, %x, %x, %x\n", - aha->sc_dev.dv_xname, - inquire.boardid, inquire.spec_opts, - inquire.revision_1, inquire.revision_2); -#endif /* AHADEBUG */ - /* - * If we are a 1542C or 1542CF disable the extended bios so that the - * mailbox interface is unlocked. - * No need to check the extended bios flags as some of the - * extensions that cause us problems are not flagged in that byte. - */ - if (inquire.boardid == 0x43 || inquire.boardid == 0x44 || - inquire.boardid == 0x45) { - aha_cmd(aha, 0, sizeof(extbios), 0, &extbios, AHA_EXT_BIOS); -#ifdef AHADEBUG - printf("%s: extended bios flags %x\n", aha->sc_dev.dv_xname, - extbios.flags); -#endif /* AHADEBUG */ - printf("%s: 1542C/CF detected, unlocking mailbox\n", - aha->sc_dev.dv_xname); - aha_cmd(aha, 2, 0, 0, 0, AHA_MBX_ENABLE, - 0, extbios.mailboxlock); + return 1; } -noinquire: /* * setup dma channel from jumpers and save int * level */ delay(1000); /* for Bustek 545 */ - aha_cmd(aha, 0, sizeof(conf), 0, &conf, AHA_CONF_GET); - switch (conf.chan) { + config.cmd.opcode = AHA_INQUIRE_CONFIG; + aha_cmd(iobase, sc, sizeof(config.cmd), (u_char *)&config.cmd, + sizeof(config.reply), (u_char *)&config.reply); + switch (config.reply.chan) { + case EISADMA: + drq = DRQUNK; /* for EISA/VLB/PCI clones */ + break; case CHAN0: - aha->sc_drq = 0; + drq = 0; break; case CHAN5: - aha->sc_drq = 5; + drq = 5; break; case CHAN6: - aha->sc_drq = 6; + drq = 6; break; case CHAN7: - aha->sc_drq = 7; + drq = 7; break; default: - printf("%s: illegal drq setting %x\n", aha->sc_dev.dv_xname, - conf.chan); - return EIO; + printf("aha_find: illegal drq setting %x\n", config.reply.chan); + return 1; } - switch (conf.intr) { + switch (config.reply.intr) { case INT9: - aha->sc_irq = 9; + irq = 9; break; case INT10: - aha->sc_irq = 10; + irq = 10; break; case INT11: - aha->sc_irq = 11; + irq = 11; break; case INT12: - aha->sc_irq = 12; + irq = 12; break; case INT14: - aha->sc_irq = 14; + irq = 14; break; case INT15: - aha->sc_irq = 15; + irq = 15; break; default: - printf("%s: illegal irq setting %x\n", aha->sc_dev.dv_xname, - conf.intr); + printf("aha_find: illegal irq setting %x\n", config.reply.intr); return EIO; } - /* who are we on the scsi bus? */ - aha->aha_scsi_dev = conf.scsi_dev; + if (sc != NULL) { + /* who are we on the scsi bus? */ + sc->sc_scsi_dev = config.reply.scsi_dev; - /* - * Change the bus on/off times to not clash with other dma users. - */ - 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); + sc->sc_iobase = iobase; + sc->sc_irq = irq; + sc->sc_drq = drq; + } else { + if (ia->ia_irq == IRQUNK) + ia->ia_irq = irq; + else if (ia->ia_irq != irq) + return 1; + if (ia->ia_drq == DRQUNK) + ia->ia_drq = drq; + else if (ia->ia_drq != drq) + return 1; + } return 0; } @@ -1153,43 +919,176 @@ noinquire: * Start the board, ready for normal operation */ void -aha_init(aha) - struct aha_softc *aha; +aha_init(sc) + struct aha_softc *sc; { - u_char ad[3]; - struct isadma_seg mbx_phys[1]; + int iobase = sc->sc_iobase; + struct aha_devices devices; + struct aha_setup setup; + struct aha_mailbox mailbox; int i; -#ifdef TUNE_1542 /* - * Initialize memory transfer speed - * Not compiled in by default because it breaks some machines + * XXX + * If we are a 1542C or later, disable the extended BIOS so that the + * mailbox interface is unlocked. + * No need to check the extended BIOS flags as some of the + * extensions that cause us problems are not flagged in that byte. */ - if (!aha_set_bus_speed(aha)) - panic("aha_init: cannot set bus speed"); -#endif /* TUNE_1542 */ + if (!strncmp(sc->sc_model, "1542C", 5)) { + struct aha_extbios extbios; + struct aha_unlock unlock; + + printf("%s: unlocking mailbox interface\n", sc->sc_dev.dv_xname); + extbios.cmd.opcode = AHA_EXT_BIOS; + aha_cmd(iobase, sc, sizeof(extbios.cmd), (u_char *)&extbios.cmd, + sizeof(extbios.reply), (u_char *)&extbios.reply); + +#ifdef AHADEBUG + printf("%s: flags=%02x, mailboxlock=%02x\n", + sc->sc_dev.dv_xname, + extbios.reply.flags, extbios.reply.mailboxlock); +#endif /* AHADEBUG */ + unlock.cmd.opcode = AHA_MBX_ENABLE; + unlock.cmd.junk = 0; + unlock.cmd.magic = extbios.reply.mailboxlock; + aha_cmd(iobase, sc, sizeof(unlock.cmd), (u_char *)&unlock.cmd, + 0, (u_char *)0); + } + +#if 0 /* - * Initialize mail box. This mapping will never be undone. + * Change the bus on/off times to not clash with other dma users. */ - 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(sc, 1, 0, 0, 0, AHA_BUS_ON_TIME_SET, 7); + aha_cmd(sc, 1, 0, 0, 0, AHA_BUS_OFF_TIME_SET, 4); +#endif - aha_cmd(aha, 4, 0, 0, 0, AHA_MBX_INIT, AHA_MBX_SIZE, - ad[0], ad[1], ad[2]); + /* Inquire Installed Devices (to force synchronous negotiation). */ + devices.cmd.opcode = AHA_INQUIRE_DEVICES; + aha_cmd(iobase, sc, sizeof(devices.cmd), (u_char *)&devices.cmd, + sizeof(devices.reply), (u_char *)&devices.reply); + + /* Obtain setup information from. */ + setup.cmd.opcode = AHA_INQUIRE_SETUP; + setup.cmd.len = sizeof(setup.reply); + aha_cmd(iobase, sc, sizeof(setup.cmd), (u_char *)&setup.cmd, + sizeof(setup.reply), (u_char *)&setup.reply); + + printf("%s: %s, %s\n", + sc->sc_dev.dv_xname, + setup.reply.sync_neg ? "sync" : "async", + setup.reply.parity ? "parity" : "no parity"); + + for (i = 0; i < 8; i++) { + if (!setup.reply.sync[i].valid || + (!setup.reply.sync[i].offset && !setup.reply.sync[i].period)) + continue; + printf("%s targ %d: sync, offset %d, period %dnsec\n", + sc->sc_dev.dv_xname, i, + setup.reply.sync[i].offset, setup.reply.sync[i].period * 50 + 200); + } + /* + * Set up initial mail box for round-robin operation. + */ for (i = 0; i < AHA_MBX_SIZE; i++) { - aha->aha_mbx.mbo[i].cmd = AHA_MBO_FREE; - aha->aha_mbx.mbi[i].stat = AHA_MBO_FREE; + wmbx->mbo[i].cmd = AHA_MBO_FREE; + wmbx->mbi[i].stat = AHA_MBO_FREE; } + wmbx->cmbo = wmbx->tmbo = &wmbx->mbo[0]; + wmbx->tmbi = &wmbx->mbi[0]; + sc->sc_mbofull = 0; + + /* Initialize mail box. */ + mailbox.cmd.opcode = AHA_MBX_INIT; + mailbox.cmd.nmbx = AHA_MBX_SIZE; + ltophys(KVTOPHYS(wmbx), mailbox.cmd.addr); + aha_cmd(iobase, sc, sizeof(mailbox.cmd), (u_char *)&mailbox.cmd, + 0, (u_char *)0); +} + +void +aha_inquire_setup_information(sc) + struct aha_softc *sc; +{ + int iobase = sc->sc_iobase; + struct aha_revision revision; + u_char sts; + int i; + char *p; + + strcpy(sc->sc_model, "unknown"); /* - * Set up initial mail box for round-robin operation. + * Assume we have a board at this stage, do an adapter inquire + * to find out what type of controller it is. If the command + * fails, we assume it's either a crusty board or an old 1542 + * clone, and skip the board-specific stuff. */ - aha->aha_mbx.tmbo = &aha->aha_mbx.mbo[0]; - aha->aha_mbx.tmbi = &aha->aha_mbx.mbi[0]; + revision.cmd.opcode = AHA_INQUIRE_REVISION; + if (aha_cmd(iobase, sc, sizeof(revision.cmd), (u_char *)&revision.cmd, + sizeof(revision.reply), (u_char *)&revision.reply)) { + /* + * aha_cmd() already started the reset. It's not clear we + * even need to bother here. + */ + for (i = AHA_RESET_TIMEOUT; i; i--) { + sts = inb(iobase + AHA_STAT_PORT); + if (sts == (AHA_STAT_IDLE | AHA_STAT_INIT)) + break; + delay(1000); + } + if (!i) { +#ifdef AHADEBUG + printf("aha_init: soft reset failed\n"); +#endif /* AHADEBUG */ + return; + } +#ifdef AHADEBUG + printf("aha_init: inquire command failed\n"); +#endif /* AHADEBUG */ + goto noinquire; + } + +#ifdef AHADEBUG + printf("%s: inquire %x, %x, %x, %x\n", + sc->sc_dev.dv_xname, + revision.reply.boardid, revision.reply.spec_opts, + revision.reply.revision_1, revision.reply.revision_2); +#endif /* AHADEBUG */ + + switch (revision.reply.boardid) { + case 0x31: + strcpy(sc->sc_model, "1540"); + break; + case 0x41: + strcpy(sc->sc_model, "1540A/1542A/1542B"); + break; + case 0x42: + strcpy(sc->sc_model, "1640"); + break; + case 0x43: + strcpy(sc->sc_model, "1542C"); + break; + case 0x44: + case 0x45: + strcpy(sc->sc_model, "1542CF"); + break; + case 0x46: + strcpy(sc->sc_model, "1542CP"); + break; + } + + p = sc->sc_firmware; + *p++ = revision.reply.revision_1; + *p++ = '.'; + *p++ = revision.reply.revision_2; + *p = '\0'; + +noinquire: + printf(": model AHA-%s, firmware %s\n", sc->sc_model, sc->sc_firmware); } void @@ -1211,12 +1110,13 @@ aha_scsi_cmd(xs) struct scsi_xfer *xs; { struct scsi_link *sc_link = xs->sc_link; - struct aha_softc *aha = sc_link->adapter_softc; + struct aha_softc *sc = sc_link->adapter_softc; struct aha_ccb *ccb; struct aha_scat_gath *sg; - int seg, datalen, flags, mflags; + int seg; /* scatter gather seg being worked on */ + u_long thiskv, thisphys, nextphys; + int bytes_this_seg, bytes_this_page, datalen, flags; struct iovec *iovp; - struct aha_mbx_out *mbo; int s; SC_DEBUG(sc_link, SDEV_DB2, ("aha_scsi_cmd\n")); @@ -1226,44 +1126,28 @@ aha_scsi_cmd(xs) * 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; - xs->flags |= INUSE; - } - if ((ccb = aha_get_ccb(aha, flags)) == NULL) { + if ((ccb = aha_get_ccb(sc, flags)) == NULL) { xs->error = XS_DRIVER_STUFFUP; return TRY_AGAIN_LATER; } ccb->xs = xs; + ccb->timeout = xs->timeout; /* * Put all the arguments for the xfer in the ccb */ if (flags & SCSI_RESET) { ccb->opcode = AHA_RESET_CCB; + ccb->scsi_cmd_length = 0; } else { /* can't use S/G if zero length */ ccb->opcode = (xs->datalen ? AHA_INIT_SCAT_GATH_CCB : AHA_INITIATOR_CCB); + bcopy(xs->cmd, &ccb->scsi_cmd, + ccb->scsi_cmd_length = xs->cmdlen); } - ccb->data_out = 0; - ccb->data_in = 0; - ccb->target = sc_link->target; - ccb->lun = sc_link->lun; - ccb->scsi_cmd_length = xs->cmdlen; - 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) { - sg = ((struct aha_ccb *)(ccb->ccb_phys[0].addr))->scat_gath; - lto3b((vm_offset_t)sg, ccb->data_addr); + if (xs->datalen) { sg = ccb->scat_gath; seg = 0; #ifdef TFS @@ -1272,8 +1156,8 @@ aha_scsi_cmd(xs) datalen = ((struct uio *)xs->data)->uio_iovcnt; xs->datalen = 0; while (datalen && seg < AHA_NSEG) { - lto3b(iovp->iov_base, sg->seg_addr); - lto3b(iovp->iov_len, sg->seg_len); + ltophys(iovp->iov_base, sg->seg_addr); + ltophys(iovp->iov_len, sg->seg_len); xs->datalen += iovp->iov_len; SC_DEBUGN(sc_link, SDEV_DB4, ("UIO(0x%x@0x%x)", iovp->iov_len, iovp->iov_base)); @@ -1283,109 +1167,129 @@ aha_scsi_cmd(xs) datalen--; } } else -#endif /*TFS_ONLY */ +#endif /* TFS */ { /* - * Set up the scatter gather block + * 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); - 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); + 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++; } } - 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); + /* 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); + goto bad; + } + ltophys(KVTOPHYS(ccb->scat_gath), ccb->data_addr); + ltophys(seg * sizeof(struct aha_scat_gath), ccb->data_length); } else { /* No data xfer, use non S/G values */ - lto3b(0, ccb->data_addr); - lto3b(0, ccb->data_length); + ltophys(0, ccb->data_addr); + ltophys(0, ccb->data_length); } - ccb->link_id = 0; - lto3b(0, ccb->link_addr); - /* - * Put the scsi command in the ccb and start it - */ - if ((flags & SCSI_RESET) == 0) - bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmd_length); + ccb->data_out = 0; + ccb->data_in = 0; + ccb->target = sc_link->target; + ccb->lun = sc_link->lun; + ccb->req_sense_length = sizeof(ccb->scsi_sense); + ccb->host_stat = 0x00; + ccb->target_stat = 0x00; + ccb->link_id = 0; + ltophys(0, ccb->link_addr); 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; - } + aha_queue_ccb(sc, ccb); + splx(s); /* * Usually return SUCCESSFULLY QUEUED */ SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n")); - - if (VOLATILE_XS(xs)) { - timeout(aha_timeout, ccb, (xs->timeout * hz) / 1000); - 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(aha, ccb, xs->flags); - scsi_done(xs); - return COMPLETE; - } - - if ((flags & SCSI_POLL) == 0) { - timeout(aha_timeout, ccb, (xs->timeout * hz) / 1000); - splx(s); + if ((flags & SCSI_POLL) == 0) return SUCCESSFULLY_QUEUED; - } - - splx(s); /* * If we can't use interrupts, poll on completion */ - if (aha_poll(aha, xs, xs->timeout)) { + if (aha_poll(sc, xs, ccb->timeout)) { aha_timeout(ccb); - if (aha_poll(aha, xs, 2000)) + if (aha_poll(sc, xs, ccb->timeout)) aha_timeout(ccb); } return COMPLETE; + +bad: + xs->error = XS_DRIVER_STUFFUP; + aha_free_ccb(sc, ccb); + return COMPLETE; } /* * Poll a particular unit, looking for a particular xs */ int -aha_poll(aha, xs, count) - struct aha_softc *aha; +aha_poll(sc, xs, count) + struct aha_softc *sc; struct scsi_xfer *xs; int count; { + int iobase = sc->sc_iobase; /* timeouts are in msec, so we loop in 1000 usec cycles */ while (count) { @@ -1393,8 +1297,8 @@ aha_poll(aha, xs, count) * If we had interrupts enabled, would we * have got an interrupt? */ - if (inb(AHA_INTR_PORT) & AHA_ANY_INTR) - ahaintr(aha); + if (inb(iobase + AHA_INTR_PORT) & AHA_INTR_ANYINTR) + ahaintr(sc); if (xs->flags & ITSDONE) return 0; delay(1000); /* only happens in boot so ok */ @@ -1403,141 +1307,6 @@ aha_poll(aha, xs, count) return 1; } -#ifdef TUNE_1542 -/* - * Try all the speeds from slowest to fastest.. if it finds a - * speed that fails, back off one notch from the last working - * speed (unless there is no other notch). - * Returns the nSEC value of the time used - * or 0 if it could get a working speed (or the NEXT speed - * failed) - */ -static struct bus_speed { - u_char arg; - int nsecs; -} aha_bus_speeds[] = { - {0x88, 100}, - {0x99, 150}, - {0xaa, 200}, - {0xbb, 250}, - {0xcc, 300}, - {0xdd, 350}, - {0xee, 400}, - {0xff, 450} -}; - -int -aha_set_bus_speed(aha) - struct aha_softc *aha; -{ - int speed; - int lastworking; - - lastworking = -1; - for (speed = 7; speed >= 0; speed--) { - if (!aha_bus_speed_check(aha, speed)) - break; - lastworking = speed; - } - if (lastworking == -1) { - printf(" no working bus speed"); - return 0; - } - printf(", %d nsec ", aha_bus_speeds[lastworking].nsecs); - if (lastworking == 7) /* is slowest already */ - printf("marginal"); - else { - lastworking++; - printf("ok, using %d nsec", aha_bus_speeds[lastworking].nsecs); - } - if (!aha_bus_speed_check(aha, lastworking)) { - printf("test retry failed.. aborting."); - return 0; - } - return 1; -} - -/* - * Set the DMA speed to the Nth speed and try an xfer. If it - * fails return 0, if it succeeds return the nSec value selected - * If there is no such speed return COMPLETE. - */ -char aha_scratch_buf[256]; -char aha_test_string[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz!@"; - -int -aha_bus_speed_check(aha, speed) - struct aha_softc *aha; - int speed; -{ - int numspeeds = sizeof(aha_bus_speeds) / sizeof(struct bus_speed); - 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 - */ - aha_cmd(aha, 1, 0, 0, 0, AHA_SPEED_SET, aha_bus_speeds[speed].arg); - - /* - * put the test data into the buffer and calculate - * it's address. Read it onto the board - */ - for (loopcount = 100; loopcount; loopcount--) { - lto3b(test_phys[0].addr, ad); - aha_cmd(aha, 3, 0, 0, 0, AHA_WRITE_FIFO, ad[0], ad[1], ad[2]); - - /* - * Clear the buffer then copy the contents back from the - * board. - */ - bzero(aha_scratch_buf, 54); - isadma_copytobuf(aha_scratch_buf, sizeof(aha_scratch_buf), - 1, scratch_phys); - - 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 - * correct value depending upon the result. We only check 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)) { - 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 result; -} -#endif /* TUNE_1542 */ - void aha_timeout(arg) void *arg; @@ -1545,7 +1314,7 @@ aha_timeout(arg) struct aha_ccb *ccb = arg; struct scsi_xfer *xs = ccb->xs; struct scsi_link *sc_link = xs->sc_link; - struct aha_softc *aha = sc_link->adapter_softc; + struct aha_softc *sc = sc_link->adapter_softc; int s; sc_print_addr(sc_link); @@ -1553,34 +1322,33 @@ aha_timeout(arg) s = splbio(); +#ifdef AHADIAG /* * If The ccb's mbx is not free, then the board has gone south? */ - if (aha_ccb_phys_kv(aha, _3btol(ccb->mbx->ccb_addr)) == ccb && - ccb->mbx->cmd != AHA_MBO_FREE) { - printf("%s: not taking commands!\n", aha->sc_dev.dv_xname); + aha_collect_mbo(sc); + if (ccb->flags & CCB_SENDING) { + printf("%s: not taking commands!\n", sc->sc_dev.dv_xname); Debugger(); } +#endif /* * If it has been through before, then * a previous abort has failed, don't * try abort again */ - if (ccb->flags == CCB_ABORTED) { + if (ccb->flags & CCB_ABORT) { /* abort timed out */ printf(" AGAIN\n"); - ccb->xs->retries = 0; - aha_done(aha, ccb); + /* XXX Must reset! */ } else { /* abort the operation that has timed out */ printf("\n"); ccb->xs->error = XS_TIMEOUT; - ccb->flags = CCB_ABORTED; - aha_send_mbo(aha, AHA_MBO_ABORT, ccb); - /* 2 secs for the abort */ - if ((xs->flags & SCSI_POLL) == 0) - timeout(aha_timeout, ccb, 2 * hz); + ccb->timeout = AHA_ABORT_TIMEOUT; + ccb->flags |= CCB_ABORT; + aha_queue_ccb(sc, ccb); } splx(s); diff --git a/sys/dev/isa/aha1542.c b/sys/dev/isa/aha1542.c deleted file mode 100644 index a1c559ad646..00000000000 --- a/sys/dev/isa/aha1542.c +++ /dev/null @@ -1,1587 +0,0 @@ -/* $OpenBSD: aha1542.c,v 1.13 1996/03/20 01:00:35 mickey Exp $ */ -/* $NetBSD: aha1542.c,v 1.55 1995/12/24 02:31:06 mycroft Exp $ */ - -/* - * Copyright (c) 1994 Charles Hannum. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Charles 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Originally written by Julian Elischer (julian@tfs.com) - * for TRW Financial Systems for use under the MACH(2.5) operating system. - * - * TRW Financial Systems, in accordance with their agreement with Carnegie - * Mellon University, makes this software available to CMU to distribute - * or use in any manner that they see fit as long as this message is kept with - * the software. For this reason TFS also grants any other persons or - * organisations permission to use or modify this software. - * - * TFS supplies this software to be publicly redistributed - * on the understanding that TFS is not responsible for the correct - * functioning of this software in any circumstances. - */ - -/* - * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 - */ - -#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 <sys/ioctl.h> -#include <sys/device.h> -#include <sys/malloc.h> -#include <sys/buf.h> -#include <sys/proc.h> -#include <sys/user.h> - -#include <machine/pio.h> - -#include <dev/isa/isavar.h> -#include <dev/isa/isadmavar.h> -#include <scsi/scsi_all.h> -#include <scsi/scsiconf.h> - -#ifndef DDB -#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 - -#undef TUNE_1542 /* if bus speed check breaks the machine, undefine it */ - -/************************** board definitions *******************************/ - -/* - * I/O Port Interface - */ -#define AHA_BASE aha->sc_iobase -#define AHA_CTRL_STAT_PORT (AHA_BASE + 0x0) /* control & status */ -#define AHA_CMD_DATA_PORT (AHA_BASE + 0x1) /* cmds and datas */ -#define AHA_INTR_PORT (AHA_BASE + 0x2) /* Intr. stat */ - -/* - * AHA_CTRL_STAT bits (write) - */ -#define AHA_HRST 0x80 /* Hardware reset */ -#define AHA_SRST 0x40 /* Software reset */ -#define AHA_IRST 0x20 /* Interrupt reset */ -#define AHA_SCRST 0x10 /* SCSI bus reset */ - -/* - * AHA_CTRL_STAT bits (read) - */ -#define AHA_STST 0x80 /* Self test in Progress */ -#define AHA_DIAGF 0x40 /* Diagnostic Failure */ -#define AHA_INIT 0x20 /* Mbx Init required */ -#define AHA_IDLE 0x10 /* Host Adapter Idle */ -#define AHA_CDF 0x08 /* cmd/data out port full */ -#define AHA_DF 0x04 /* Data in port full */ -#define AHA_INVDCMD 0x01 /* Invalid command */ - -/* - * AHA_CMD_DATA bits (write) - */ -#define AHA_NOP 0x00 /* No operation */ -#define AHA_MBX_INIT 0x01 /* Mbx initialization */ -#define AHA_START_SCSI 0x02 /* start scsi command */ -#define AHA_START_BIOS 0x03 /* start bios command */ -#define AHA_INQUIRE 0x04 /* Adapter Inquiry */ -#define AHA_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */ -#define AHA_SEL_TIMEOUT_SET 0x06 /* set selection time-out */ -#define AHA_BUS_ON_TIME_SET 0x07 /* set bus-on time */ -#define AHA_BUS_OFF_TIME_SET 0x08 /* set bus-off time */ -#define AHA_SPEED_SET 0x09 /* set transfer speed */ -#define AHA_DEV_GET 0x0a /* return installed devices */ -#define AHA_CONF_GET 0x0b /* return configuration data */ -#define AHA_TARGET_EN 0x0c /* enable target mode */ -#define AHA_SETUP_GET 0x0d /* return setup data */ -#define AHA_WRITE_CH2 0x1a /* write channel 2 buffer */ -#define AHA_READ_CH2 0x1b /* read channel 2 buffer */ -#define AHA_WRITE_FIFO 0x1c /* write fifo buffer */ -#define AHA_READ_FIFO 0x1d /* read fifo buffer */ -#define AHA_ECHO 0x1e /* Echo command data */ -#define AHA_EXT_BIOS 0x28 /* return extended bios info */ -#define AHA_MBX_ENABLE 0x29 /* enable mail box interface */ - -/* - * AHA_INTR_PORT bits (read) - */ -#define AHA_ANY_INTR 0x80 /* Any interrupt */ -#define AHA_SCRD 0x08 /* SCSI reset detected */ -#define AHA_HACC 0x04 /* Command complete */ -#define AHA_MBOA 0x02 /* MBX out empty */ -#define AHA_MBIF 0x01 /* MBX in full */ - -/* - * Mail box defs - */ -#define AHA_MBX_SIZE 16 /* mail box size */ - -#define AHA_CCB_MAX 32 /* store up to 32 CCBs at one time */ -#define CCB_HASH_SIZE 32 /* hash table size for phystokv */ -#define CCB_HASH_SHIFT 9 -#define CCB_HASH(x) ((((long)(x))>>CCB_HASH_SHIFT) & (CCB_HASH_SIZE - 1)) - -#define aha_nextmbx(wmb, mbx, mbio) \ - if ((wmb) == &(mbx)->mbio[AHA_MBX_SIZE - 1]) \ - (wmb) = &(mbx)->mbio[0]; \ - else \ - (wmb)++; - -struct aha_mbx_out { - u_char cmd; - u_char ccb_addr[3]; -}; - -struct aha_mbx_in { - u_char stat; - u_char ccb_addr[3]; -}; - -struct aha_mbx { - struct aha_mbx_out mbo[AHA_MBX_SIZE]; - struct aha_mbx_in mbi[AHA_MBX_SIZE]; - struct aha_mbx_out *tmbo; /* Target Mail Box out */ - struct aha_mbx_in *tmbi; /* Target Mail Box in */ -}; - -/* - * mbo.cmd values - */ -#define AHA_MBO_FREE 0x0 /* MBO entry is free */ -#define AHA_MBO_START 0x1 /* MBO activate entry */ -#define AHA_MBO_ABORT 0x2 /* MBO abort entry */ - -/* - * mbi.stat values - */ -#define AHA_MBI_FREE 0x0 /* MBI entry is free */ -#define AHA_MBI_OK 0x1 /* completed without error */ -#define AHA_MBI_ABORT 0x2 /* aborted ccb */ -#define AHA_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */ -#define AHA_MBI_ERROR 0x4 /* Completed with error */ - -/* FOR OLD VERSIONS OF THE !%$@ this may have to be 16 (yuk) */ -#define AHA_NSEG 17 /* Number of scatter gather segments <= 16 */ - /* allow 60 K i/o (min) */ - -struct aha_ccb { - u_char opcode; - u_char lun:3; - u_char data_in:1; /* must be 0 */ - u_char data_out:1; /* must be 0 */ - u_char target:3; - u_char scsi_cmd_length; - u_char req_sense_length; - u_char data_length[3]; - u_char data_addr[3]; - u_char link_addr[3]; - u_char link_id; - u_char host_stat; - u_char target_stat; - u_char reserved[2]; - struct scsi_generic scsi_cmd; - struct scsi_sense_data scsi_sense; - struct aha_scat_gath { - 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; - 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; /* number of phys segments of data */ -}; - -/* - * opcode fields - */ -#define AHA_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */ -#define AHA_TARGET_CCB 0x01 /* SCSI Target CCB */ -#define AHA_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scatter gather */ -#define AHA_RESET_CCB 0x81 /* SCSI Bus reset */ - -/* - * aha_ccb.host_stat values - */ -#define AHA_OK 0x00 /* cmd ok */ -#define AHA_LINK_OK 0x0a /* Link cmd ok */ -#define AHA_LINK_IT 0x0b /* Link cmd ok + int */ -#define AHA_SEL_TIMEOUT 0x11 /* Selection time out */ -#define AHA_OVER_UNDER 0x12 /* Data over/under run */ -#define AHA_BUS_FREE 0x13 /* Bus dropped at unexpected time */ -#define AHA_INV_BUS 0x14 /* Invalid bus phase/sequence */ -#define AHA_BAD_MBO 0x15 /* Incorrect MBO cmd */ -#define AHA_BAD_CCB 0x16 /* Incorrect ccb opcode */ -#define AHA_BAD_LINK 0x17 /* Not same values of LUN for links */ -#define AHA_INV_TARGET 0x18 /* Invalid target direction */ -#define AHA_CCB_DUP 0x19 /* Duplicate CCB received */ -#define AHA_INV_CCB 0x1a /* Invalid CCB or segment list */ -#define AHA_ABORTED 42 - -struct aha_setup { - u_char sync_neg:1; - u_char parity:1; - u_char:6; - u_char speed; - u_char bus_on; - u_char bus_off; - u_char num_mbx; - u_char mbx[3]; - struct { - u_char offset:4; - u_char period:3; - u_char valid:1; - } sync[8]; - u_char disc_sts; -}; - -struct aha_config { - u_char chan; - u_char intr; - u_char scsi_dev:3; - u_char:5; -}; - -struct aha_inquire { - u_char boardid; /* type of board */ - /* 0x31 = AHA-1540 */ - /* 0x41 = AHA-1540A/1542A/1542B */ - /* 0x42 = AHA-1640 */ - /* 0x43 = AHA-1542C */ - /* 0x44 = AHA-1542CF */ - /* 0x45 = AHA-1542CF, BIOS v2.01 */ - u_char spec_opts; /* special options ID */ - /* 0x41 = Board is standard model */ - u_char revision_1; /* firmware revision [0-9A-Z] */ - u_char revision_2; /* firmware revision [0-9A-Z] */ -}; - -struct aha_extbios { - u_char flags; /* Bit 3 == 1 extended bios enabled */ - u_char mailboxlock; /* mail box lock code to unlock it */ -}; - -#define INT9 0x01 -#define INT10 0x02 -#define INT11 0x04 -#define INT12 0x08 -#define INT14 0x20 -#define INT15 0x40 - -#define CHAN0 0x01 -#define CHAN5 0x20 -#define CHAN6 0x40 -#define CHAN7 0x80 - -/*********************************** end of board definitions***************/ - -#ifdef AHADEBUG -int aha_debug = 1; -#endif /*AHADEBUG */ - -struct aha_softc { - struct device sc_dev; - struct isadev sc_id; - void *sc_ih; - - int sc_iobase; - int sc_irq, sc_drq; - - struct aha_mbx aha_mbx; /* all the mailboxes */ - struct aha_ccb *ccbhash[CCB_HASH_SIZE]; - TAILQ_HEAD(, aha_ccb) free_ccb; - int numccbs; - int aha_scsi_dev; /* our scsi id */ - struct scsi_link sc_link; -}; - -int aha_cmd(); /* XXX must be varargs to prototype */ -int ahaintr __P((void *)); -void aha_free_ccb __P((struct aha_softc *, struct aha_ccb *, int)); -struct aha_ccb *aha_get_ccb __P((struct aha_softc *, int)); -struct aha_ccb *aha_ccb_phys_kv __P((struct aha_softc *, u_long)); -struct aha_mbx_out *aha_send_mbo __P((struct aha_softc *, int, struct aha_ccb *)); -void aha_done __P((struct aha_softc *, struct aha_ccb *)); -int aha_find __P((struct aha_softc *)); -void aha_init __P((struct aha_softc *)); -void ahaminphys __P((struct buf *)); -int aha_scsi_cmd __P((struct scsi_xfer *)); -int aha_poll __P((struct aha_softc *, struct scsi_xfer *, int)); -int aha_set_bus_speed __P((struct aha_softc *)); -int aha_bus_speed_check __P((struct aha_softc *, int)); -void aha_timeout __P((void *arg)); - -struct scsi_adapter aha_switch = { - aha_scsi_cmd, - ahaminphys, - 0, - 0, -}; - -/* the below structure is so we have a default dev struct for out link struct */ -struct scsi_device aha_dev = { - NULL, /* Use default error handler */ - NULL, /* have a queue, served by this */ - NULL, /* have no async handler */ - NULL, /* Use default 'done' routine */ -}; - -int ahaprobe __P((struct device *, void *, void *)); -void ahaattach __P((struct device *, struct device *, void *)); -int ahaprint __P((void *, char *)); - -struct cfdriver ahacd = { - NULL, "aha", ahaprobe, ahaattach, DV_DULL, sizeof(struct aha_softc) -}; - -#define AHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */ - -/* - * aha_cmd(aha,icnt, ocnt,wait, retval, opcode, args) - * Activate Adapter command - * icnt: number of args (outbound bytes written after opcode) - * ocnt: number of expected returned bytes - * wait: number of seconds to wait for response - * retval: buffer where to place returned bytes - * opcode: opcode AHA_NOP, AHA_MBX_INIT, AHA_START_SCSI ... - * args: parameters - * - * Performs an adapter command through the ports. Not to be confused - * with a scsi command, which is read in via the dma. One of the adapter - * commands tells it to read in a scsi command but that one is done - * separately. This is only called during set-up. - */ -int -aha_cmd(aha, icnt, ocnt, wait, retval, opcode, args) - struct aha_softc *aha; - int icnt, ocnt, wait; - u_char *retval; - unsigned opcode; - u_char args; -{ - unsigned *ic = &opcode; - u_char oc; - register i; - int sts; - - /* - * multiply the wait argument by a big constant - * zero defaults to 1 sec.. - * all wait loops are in 50uSec cycles - */ - if (wait) - wait *= 20000; - else - wait = 20000; - /* - * Wait for the adapter to go idle, unless it's one of - * the commands which don't need this - */ - if (opcode != AHA_MBX_INIT && opcode != AHA_START_SCSI) { - i = 20000; /*do this for upto about a second */ - while (--i) { - sts = inb(AHA_CTRL_STAT_PORT); - if (sts & AHA_IDLE) - break; - delay(50); - } - if (!i) { - printf("%s: aha_cmd, host not idle(0x%x)\n", - aha->sc_dev.dv_xname, sts); - return ENXIO; - } - } - /* - * Now that it is idle, if we expect output, preflush the - * queue feeding to us. - */ - if (ocnt) { - while ((inb(AHA_CTRL_STAT_PORT)) & AHA_DF) - inb(AHA_CMD_DATA_PORT); - } - /* - * Output the command and the number of arguments given - * for each byte, first check the port is empty. - */ - icnt++; - /* include the command */ - while (icnt--) { - sts = inb(AHA_CTRL_STAT_PORT); - for (i = wait; i; i--) { - sts = inb(AHA_CTRL_STAT_PORT); - if (!(sts & AHA_CDF)) - break; - delay(50); - } - if (!i) { - if (opcode != AHA_INQUIRE) - printf("%s: aha_cmd, cmd/data port full\n", - aha->sc_dev.dv_xname); - outb(AHA_CTRL_STAT_PORT, AHA_SRST); - return ENXIO; - } - outb(AHA_CMD_DATA_PORT, (u_char) (*ic++)); - } - /* - * If we expect input, loop that many times, each time, - * looking for the data register to have valid data - */ - while (ocnt--) { - sts = inb(AHA_CTRL_STAT_PORT); - for (i = wait; i; i--) { - sts = inb(AHA_CTRL_STAT_PORT); - if (sts & AHA_DF) - break; - delay(50); - } - if (!i) { - if (opcode != AHA_INQUIRE) - printf("%s: aha_cmd, cmd/data port empty %d\n", - aha->sc_dev.dv_xname, ocnt); - outb(AHA_CTRL_STAT_PORT, AHA_SRST); - return ENXIO; - } - oc = inb(AHA_CMD_DATA_PORT); - if (retval) - *retval++ = oc; - } - /* - * Wait for the board to report a finised instruction - */ - i = 20000; - while (--i) { - sts = inb(AHA_INTR_PORT); - if (sts & AHA_HACC) - break; - delay(50); - } - if (!i) { - printf("%s: aha_cmd, host not finished(0x%x)\n", - aha->sc_dev.dv_xname, sts); - return ENXIO; - } - outb(AHA_CTRL_STAT_PORT, AHA_IRST); - return 0; -} - -/* - * Check if the device can be found at the port given - * and if so, set it up ready for further work - * as an argument, takes the isa_device structure from - * autoconf.c - */ -int -ahaprobe(parent, match, aux) - struct device *parent; - void *match, *aux; -{ - struct aha_softc *aha = match; - struct isa_attach_args *ia = aux; - -#ifdef NEWCONFIG - if (ia->ia_iobase == IOBASEUNK) - return 0; -#endif - - aha->sc_iobase = ia->ia_iobase; - - /* - * Try initialise a unit at this location - * sets up dma and bus speed, loads aha->sc_irq - */ - if (aha_find(aha) != 0) - return 0; - - if (ia->ia_irq != IRQUNK) { - if (ia->ia_irq != aha->sc_irq) { - printf("%s: irq mismatch; kernel configured %d != board configured %d\n", - aha->sc_dev.dv_xname, ia->ia_irq, aha->sc_irq); - return 0; - } - } else - ia->ia_irq = aha->sc_irq; - - if (ia->ia_drq != DRQUNK) { - if (ia->ia_drq != aha->sc_drq) { - printf("%s: drq mismatch; kernel configured %d != board configured %d\n", - aha->sc_dev.dv_xname, ia->ia_drq, aha->sc_drq); - return 0; - } - } else - ia->ia_drq = aha->sc_drq; - - ia->ia_msize = 0; - ia->ia_iosize = 4; - return 1; -} - -int -ahaprint(aux, name) - void *aux; - char *name; -{ - if (name != NULL) - printf("%s: scsibus ", name); - return UNCONF; -} - -/* - * Attach all the sub-devices we can find - */ -void -ahaattach(parent, self, aux) - struct device *parent, *self; - void *aux; -{ - struct isa_attach_args *ia = aux; - struct aha_softc *aha = (void *)self; - - if (ia->ia_drq != DRQUNK) - isadma_cascade(ia->ia_drq); - - aha_init(aha); - TAILQ_INIT(&aha->free_ccb); - - /* - * fill in the prototype scsi_link. - */ - aha->sc_link.adapter_softc = aha; - aha->sc_link.adapter_target = aha->aha_scsi_dev; - aha->sc_link.adapter = &aha_switch; - aha->sc_link.device = &aha_dev; - aha->sc_link.openings = 2; - - printf("\n"); - -#ifdef NEWCONFIG - isa_establish(&aha->sc_id, &aha->sc_dev); -#endif - aha->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_BIO, ahaintr, - aha, aha->sc_dev.dv_xname); - - /* - * ask the adapter what subunits are present - */ - config_found(self, &aha->sc_link, ahaprint); -} - -/* - * Catch an interrupt from the adaptor - */ -int -ahaintr(arg) - void *arg; -{ - struct aha_softc *aha = arg; - struct aha_mbx_in *wmbi; - struct aha_mbx *wmbx; - struct aha_ccb *ccb; - u_char stat; - int i; - int found = 0; - -#ifdef AHADEBUG - printf("%s: ahaintr ", aha->sc_dev.dv_xname); -#endif /*AHADEBUG */ - - /* - * First acknowlege the interrupt, Then if it's not telling about - * a completed operation just return. - */ - stat = inb(AHA_INTR_PORT); - if ((stat & (AHA_MBOA | AHA_MBIF)) == 0) { - outb(AHA_CTRL_STAT_PORT, AHA_IRST); - return -1; /* XXX */ - } - - /* Mail box out empty? */ - if (stat & AHA_MBOA) { - /* Disable MBO available interrupt. */ - outb(AHA_CMD_DATA_PORT, AHA_MBO_INTR_EN); - for (i = 100000; i; i--) { - if (!(inb(AHA_CTRL_STAT_PORT) & AHA_CDF)) - break; - delay(10); - } - if (!i) { - printf("%s: ahaintr, cmd/data port full\n", - aha->sc_dev.dv_xname); - outb(AHA_CTRL_STAT_PORT, AHA_SRST); - return 1; - } - outb(AHA_CMD_DATA_PORT, 0x00); /* Disable */ - wakeup(&aha->aha_mbx); - } - - /* Mail box in full? */ - if ((stat & AHA_MBIF) == 0) - return 1; - wmbx = &aha->aha_mbx; - wmbi = wmbx->tmbi; -AGAIN: - while (wmbi->stat != AHA_MBI_FREE) { - ccb = aha_ccb_phys_kv(aha, _3btol(wmbi->ccb_addr)); - if (!ccb) { - wmbi->stat = AHA_MBI_FREE; - printf("%s: BAD CCB ADDR!\n", aha->sc_dev.dv_xname); - continue; - } - found++; - switch (wmbi->stat) { - case AHA_MBI_OK: - case AHA_MBI_ERROR: - break; - - case AHA_MBI_ABORT: - ccb->host_stat = AHA_ABORTED; - break; - - case AHA_MBI_UNKNOWN: - ccb = 0; - break; - - default: - panic("Impossible mbxi status"); - } -#ifdef AHADEBUG - if (aha_debug && ccb) { - u_char *cp = &ccb->scsi_cmd; - printf("op=%x %x %x %x %x %x\n", - cp[0], cp[1], cp[2], - cp[3], cp[4], cp[5]); - printf("stat %x for mbi addr = 0x%08x, ", - wmbi->stat, wmbi); - printf("ccb addr = 0x%x\n", ccb); - } -#endif /* AHADEBUG */ - wmbi->stat = AHA_MBI_FREE; - if (ccb) { - untimeout(aha_timeout, ccb); - aha_done(aha, ccb); - } - aha_nextmbx(wmbi, wmbx, mbi); - } - if (!found) { - for (i = 0; i < AHA_MBX_SIZE; i++) { - if (wmbi->stat != AHA_MBI_FREE) { - found++; - break; - } - aha_nextmbx(wmbi, wmbx, mbi); - } - if (!found) { -#if 0 - printf("%s: mbi interrupt with no full mailboxes\n", - aha->sc_dev.dv_xname); -#endif - } else { - found = 0; - goto AGAIN; - } - } - wmbx->tmbi = wmbi; - outb(AHA_CTRL_STAT_PORT, AHA_IRST); - return 1; -} - -/* - * A ccb (and hence a mbx-out is put onto the - * free list. - */ -void -aha_free_ccb(aha, ccb, flags) - struct aha_softc *aha; - struct aha_ccb *ccb; - int flags; -{ - 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 = &aha->ccbhash[hashnum]; - - while (*hashccb) { - if ((*hashccb)->ccb_phys[0].addr == ccb->ccb_phys[0].addr) { - *hashccb = (*hashccb)->nexthash; - break; - } - hashccb = &(*hashccb)->nexthash; - } - - ccb->flags = CCB_FREE; - TAILQ_INSERT_HEAD(&aha->free_ccb, ccb, chain); - - /* - * If there were none, wake anybody waiting for one to come free, - * starting with queued entries. - */ - if (ccb->chain.tqe_next == 0) - wakeup(&aha->free_ccb); - - splx(s); -} - -static inline void -aha_init_ccb(aha, ccb) - struct aha_softc *aha; - struct aha_ccb *ccb; -{ - bzero(ccb, sizeof(struct aha_ccb)); -} - -static inline void -aha_reset_ccb(aha, ccb) - struct aha_softc *aha; - struct aha_ccb *ccb; -{ - -} - -/* - * Get a free ccb - */ -struct aha_ccb * -aha_get_ccb(aha, flags) - struct aha_softc *aha; - int flags; -{ - struct aha_ccb *ccb; - 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 - */ - for (;;) { - ccb = aha->free_ccb.tqh_first; - if (ccb) { - TAILQ_REMOVE(&aha->free_ccb, ccb, chain); - break; - } - if (aha->numccbs < AHA_CCB_MAX) { - if (ccb = (struct aha_ccb *) malloc(sizeof(struct aha_ccb), - M_TEMP, M_NOWAIT)) { - aha_init_ccb(aha, ccb); - aha->numccbs++; - } else { - printf("%s: can't malloc ccb\n", - aha->sc_dev.dv_xname); - goto out; - } - break; - } - if ((flags & SCSI_NOSLEEP) != 0) - goto out; - tsleep(&aha->free_ccb, PRIBIO, "ahaccb", 0); - } - - 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); -} - -/* - * given a physical address, find the ccb that it corresponds to. - */ -struct aha_ccb * -aha_ccb_phys_kv(aha, ccb_phys) - struct aha_softc *aha; - u_long ccb_phys; -{ - int hashnum = CCB_HASH(ccb_phys); - struct aha_ccb *res = aha->ccbhash[hashnum]; - - while (res) { - if (res->ccb_phys[0].addr == ccb_phys) - break; - res = res->nexthash; - } - - return res; -} - -/* - * Get a mbo and send the ccb. - */ -struct aha_mbx_out * -aha_send_mbo(aha, cmd, ccb) - struct aha_softc *aha; - int cmd; - struct aha_ccb *ccb; -{ - struct aha_mbx_out *wmbo; /* Mail Box Out pointer */ - struct aha_mbx *wmbx; /* Mail Box pointer specified unit */ - int i; - - /* Get the target out mail box pointer and increment. */ - wmbx = &aha->aha_mbx; - wmbo = wmbx->tmbo; - aha_nextmbx(wmbx->tmbo, wmbx, mbo); - - /* - * Check the outmail box is free or not. - * Note: Under the normal operation, it shuld NOT happen to wait. - */ - while (wmbo->cmd != AHA_MBO_FREE) { - /* Enable mbo available interrupt. */ - outb(AHA_CMD_DATA_PORT, AHA_MBO_INTR_EN); - for (i = 100000; i; i--) { - if (!(inb(AHA_CTRL_STAT_PORT) & AHA_CDF)) - break; - delay(10); - } - if (!i) { - printf("%s: aha_send_mbo, cmd/data port full\n", - aha->sc_dev.dv_xname); - outb(AHA_CTRL_STAT_PORT, AHA_SRST); - return NULL; - } - outb(AHA_CMD_DATA_PORT, 0x01); /* Enable */ - tsleep(wmbx, PRIBIO, "ahasnd", 0);/*XXX can't do this */ - } - - /* Link ccb to mbo. */ - lto3b(ccb->ccb_phys[0].addr, wmbo->ccb_addr); - ccb->mbx = wmbo; - wmbo->cmd = cmd; - - /* Sent it! */ - outb(AHA_CMD_DATA_PORT, AHA_START_SCSI); - - return wmbo; -} - -/* - * We have a ccb which has been processed by the - * adaptor, now we look to see how the operation - * went. Wake up the owner if waiting - */ -void -aha_done(aha, ccb) - struct aha_softc *aha; - struct aha_ccb *ccb; -{ - struct scsi_sense_data *s1, *s2; - struct scsi_xfer *xs = ccb->xs; - - SC_DEBUG(xs->sc_link, SDEV_DB2, ("aha_done\n")); - /* - * Otherwise, put the results of the operation - * into the xfer and call whoever started it - */ - if ((xs->flags & INUSE) == 0) { - printf("%s: exiting but not in use!\n", aha->sc_dev.dv_xname); - Debugger(); - } - if (xs->error == XS_NOERROR) { - if (ccb->host_stat != AHA_OK) { - switch (ccb->host_stat) { - case AHA_ABORTED: - xs->error = XS_DRIVER_STUFFUP; - break; - case AHA_SEL_TIMEOUT: /* No response */ - xs->error = XS_SELTIMEOUT; - break; - default: /* Other scsi protocol messes */ - printf("%s: host_stat %x\n", - aha->sc_dev.dv_xname, ccb->host_stat); - xs->error = XS_DRIVER_STUFFUP; - } - } else if (ccb->target_stat != SCSI_OK) { - switch (ccb->target_stat) { - case SCSI_CHECK: - s1 = (struct scsi_sense_data *) (((char *) (&ccb->scsi_cmd)) + - ccb->scsi_cmd_length); - s2 = &xs->sense; - *s2 = *s1; - xs->error = XS_SENSE; - break; - case SCSI_BUSY: - xs->error = XS_BUSY; - break; - default: - printf("%s: target_stat %x\n", - aha->sc_dev.dv_xname, ccb->target_stat); - xs->error = XS_DRIVER_STUFFUP; - } - } else - 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); -} - -/* - * Find the board and find its irq/drq - */ -int -aha_find(aha) - struct aha_softc *aha; -{ - volatile int i, sts; - struct aha_config conf; - struct aha_inquire inquire; - struct aha_extbios extbios; - - /* - * reset board, If it doesn't respond, assume - * that it's not there.. good for the probe - */ - - outb(AHA_CTRL_STAT_PORT, AHA_HRST | AHA_SRST); - - for (i = AHA_RESET_TIMEOUT; i; i--) { - sts = inb(AHA_CTRL_STAT_PORT); - if (sts == (AHA_IDLE | AHA_INIT)) - break; - delay(1000); /* calibrated in msec */ - } - if (!i) { -#ifdef AHADEBUG - if (aha_debug) - printf("aha_find: No answer from adaptec board\n"); -#endif /*AHADEBUG */ - return ENXIO; - } - - /* - * Assume we have a board at this stage, do an adapter inquire - * to find out what type of controller it is. If the command - * fails, we assume it's either a crusty board or an old 1542 - * clone, and skip the board-specific stuff. - */ - if (aha_cmd(aha, 0, sizeof(inquire), 1, &inquire, AHA_INQUIRE)) { - /* - * aha_cmd() already started the reset. It's not clear we - * even need to bother here. - */ - for (i = AHA_RESET_TIMEOUT; i; i--) { - sts = inb(AHA_CTRL_STAT_PORT); - if (sts == (AHA_IDLE | AHA_INIT)) - break; - delay(1000); - } - if (!i) { -#ifdef AHADEBUG - printf("aha_init: soft reset failed\n"); -#endif /* AHADEBUG */ - return ENXIO; - } -#ifdef AHADEBUG - printf("aha_init: inquire command failed\n"); -#endif /* AHADEBUG */ - goto noinquire; - } -#ifdef AHADEBUG - printf("%s: inquire %x, %x, %x, %x\n", - aha->sc_dev.dv_xname, - inquire.boardid, inquire.spec_opts, - inquire.revision_1, inquire.revision_2); -#endif /* AHADEBUG */ - /* - * If we are a 1542C or 1542CF disable the extended bios so that the - * mailbox interface is unlocked. - * No need to check the extended bios flags as some of the - * extensions that cause us problems are not flagged in that byte. - */ - if (inquire.boardid == 0x43 || inquire.boardid == 0x44 || - inquire.boardid == 0x45) { - aha_cmd(aha, 0, sizeof(extbios), 0, &extbios, AHA_EXT_BIOS); -#ifdef AHADEBUG - printf("%s: extended bios flags %x\n", aha->sc_dev.dv_xname, - extbios.flags); -#endif /* AHADEBUG */ - printf("%s: 1542C/CF detected, unlocking mailbox\n", - aha->sc_dev.dv_xname); - aha_cmd(aha, 2, 0, 0, 0, AHA_MBX_ENABLE, - 0, extbios.mailboxlock); - } -noinquire: - - /* - * setup dma channel from jumpers and save int - * level - */ - delay(1000); /* for Bustek 545 */ - aha_cmd(aha, 0, sizeof(conf), 0, &conf, AHA_CONF_GET); - switch (conf.chan) { - case CHAN0: - aha->sc_drq = 0; - break; - case CHAN5: - aha->sc_drq = 5; - break; - case CHAN6: - aha->sc_drq = 6; - break; - case CHAN7: - aha->sc_drq = 7; - break; - default: - printf("%s: illegal drq setting %x\n", aha->sc_dev.dv_xname, - conf.chan); - return EIO; - } - - switch (conf.intr) { - case INT9: - aha->sc_irq = 9; - break; - case INT10: - aha->sc_irq = 10; - break; - case INT11: - aha->sc_irq = 11; - break; - case INT12: - aha->sc_irq = 12; - break; - case INT14: - aha->sc_irq = 14; - break; - case INT15: - aha->sc_irq = 15; - break; - default: - printf("%s: illegal irq setting %x\n", aha->sc_dev.dv_xname, - conf.intr); - return EIO; - } - - /* who are we on the scsi bus? */ - aha->aha_scsi_dev = conf.scsi_dev; - - /* - * Change the bus on/off times to not clash with other dma users. - */ - 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); - - return 0; -} - -/* - * Start the board, ready for normal operation - */ -void -aha_init(aha) - struct aha_softc *aha; -{ - u_char ad[3]; - struct isadma_seg mbx_phys[1]; - int i; - -#ifdef TUNE_1542 - /* - * 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. - */ - 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]); - - for (i = 0; i < AHA_MBX_SIZE; i++) { - aha->aha_mbx.mbo[i].cmd = AHA_MBO_FREE; - aha->aha_mbx.mbi[i].stat = AHA_MBO_FREE; - } - - /* - * Set up initial mail box for round-robin operation. - */ - aha->aha_mbx.tmbo = &aha->aha_mbx.mbo[0]; - aha->aha_mbx.tmbi = &aha->aha_mbx.mbi[0]; -} - -void -ahaminphys(bp) - struct buf *bp; -{ - - if (bp->b_bcount > ((AHA_NSEG - 1) << PGSHIFT)) - bp->b_bcount = ((AHA_NSEG - 1) << PGSHIFT); - minphys(bp); -} - -/* - * start a scsi operation given the command and the data address. Also needs - * the unit, target and lu. - */ -int -aha_scsi_cmd(xs) - struct scsi_xfer *xs; -{ - struct scsi_link *sc_link = xs->sc_link; - struct aha_softc *aha = sc_link->adapter_softc; - struct aha_ccb *ccb; - struct aha_scat_gath *sg; - int seg, datalen, flags, mflags; - struct iovec *iovp; - struct aha_mbx_out *mbo; - int s; - - SC_DEBUG(sc_link, SDEV_DB2, ("aha_scsi_cmd\n")); - /* - * get a ccb to use. If the transfer - * is from a buf (possibly from interrupt time) - * 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; - xs->flags |= INUSE; - } - if ((ccb = aha_get_ccb(aha, flags)) == NULL) { - xs->error = XS_DRIVER_STUFFUP; - return TRY_AGAIN_LATER; - } - ccb->xs = xs; - - /* - * Put all the arguments for the xfer in the ccb - */ - if (flags & SCSI_RESET) { - ccb->opcode = AHA_RESET_CCB; - } else { - /* can't use S/G if zero length */ - ccb->opcode = (xs->datalen ? AHA_INIT_SCAT_GATH_CCB - : AHA_INITIATOR_CCB); - } - ccb->data_out = 0; - ccb->data_in = 0; - ccb->target = sc_link->target; - ccb->lun = sc_link->lun; - ccb->scsi_cmd_length = xs->cmdlen; - 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) { - 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 - if (flags & SCSI_DATA_UIO) { - iovp = ((struct uio *)xs->data)->uio_iov; - datalen = ((struct uio *)xs->data)->uio_iovcnt; - xs->datalen = 0; - while (datalen && seg < AHA_NSEG) { - lto3b(iovp->iov_base, sg->seg_addr); - lto3b(iovp->iov_len, sg->seg_len); - xs->datalen += iovp->iov_len; - SC_DEBUGN(sc_link, SDEV_DB4, ("UIO(0x%x@0x%x)", - iovp->iov_len, iovp->iov_base)); - sg++; - iovp++; - seg++; - datalen--; - } - } else -#endif /*TFS_ONLY */ - { - /* - * Set up the scatter gather block - */ - - 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(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); - } - ccb->link_id = 0; - lto3b(0, ccb->link_addr); - - /* - * Put the scsi command in the ccb and start it - */ - if ((flags & SCSI_RESET) == 0) - bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmd_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)) { - timeout(aha_timeout, ccb, (xs->timeout * hz) / 1000); - 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(aha, ccb, xs->flags); - scsi_done(xs); - return COMPLETE; - } - - if ((flags & SCSI_POLL) == 0) { - timeout(aha_timeout, ccb, (xs->timeout * hz) / 1000); - splx(s); - return SUCCESSFULLY_QUEUED; - } - - splx(s); - - /* - * If we can't use interrupts, poll on completion - */ - if (aha_poll(aha, xs, xs->timeout)) { - aha_timeout(ccb); - if (aha_poll(aha, xs, 2000)) - aha_timeout(ccb); - } - return COMPLETE; -} - -/* - * Poll a particular unit, looking for a particular xs - */ -int -aha_poll(aha, xs, count) - struct aha_softc *aha; - struct scsi_xfer *xs; - int count; -{ - - /* timeouts are in msec, so we loop in 1000 usec cycles */ - while (count) { - /* - * If we had interrupts enabled, would we - * have got an interrupt? - */ - if (inb(AHA_INTR_PORT) & AHA_ANY_INTR) - ahaintr(aha); - if (xs->flags & ITSDONE) - return 0; - delay(1000); /* only happens in boot so ok */ - count--; - } - return 1; -} - -#ifdef TUNE_1542 -/* - * Try all the speeds from slowest to fastest.. if it finds a - * speed that fails, back off one notch from the last working - * speed (unless there is no other notch). - * Returns the nSEC value of the time used - * or 0 if it could get a working speed (or the NEXT speed - * failed) - */ -static struct bus_speed { - u_char arg; - int nsecs; -} aha_bus_speeds[] = { - {0x88, 100}, - {0x99, 150}, - {0xaa, 200}, - {0xbb, 250}, - {0xcc, 300}, - {0xdd, 350}, - {0xee, 400}, - {0xff, 450} -}; - -int -aha_set_bus_speed(aha) - struct aha_softc *aha; -{ - int speed; - int lastworking; - - lastworking = -1; - for (speed = 7; speed >= 0; speed--) { - if (!aha_bus_speed_check(aha, speed)) - break; - lastworking = speed; - } - if (lastworking == -1) { - printf(" no working bus speed"); - return 0; - } - printf(", %d nsec ", aha_bus_speeds[lastworking].nsecs); - if (lastworking == 7) /* is slowest already */ - printf("marginal"); - else { - lastworking++; - printf("ok, using %d nsec", aha_bus_speeds[lastworking].nsecs); - } - if (!aha_bus_speed_check(aha, lastworking)) { - printf("test retry failed.. aborting."); - return 0; - } - return 1; -} - -/* - * Set the DMA speed to the Nth speed and try an xfer. If it - * fails return 0, if it succeeds return the nSec value selected - * If there is no such speed return COMPLETE. - */ -char aha_scratch_buf[256]; -char aha_test_string[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz!@"; - -int -aha_bus_speed_check(aha, speed) - struct aha_softc *aha; - int speed; -{ - int numspeeds = sizeof(aha_bus_speeds) / sizeof(struct bus_speed); - 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 - */ - aha_cmd(aha, 1, 0, 0, 0, AHA_SPEED_SET, aha_bus_speeds[speed].arg); - - /* - * put the test data into the buffer and calculate - * it's address. Read it onto the board - */ - for (loopcount = 100; loopcount; loopcount--) { - lto3b(test_phys[0].addr, ad); - aha_cmd(aha, 3, 0, 0, 0, AHA_WRITE_FIFO, ad[0], ad[1], ad[2]); - - /* - * Clear the buffer then copy the contents back from the - * board. - */ - bzero(aha_scratch_buf, 54); - isadma_copytobuf(aha_scratch_buf, sizeof(aha_scratch_buf), - 1, scratch_phys); - - 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 - * correct value depending upon the result. We only check 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)) { - 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 result; -} -#endif /* TUNE_1542 */ - -void -aha_timeout(arg) - void *arg; -{ - struct aha_ccb *ccb = arg; - struct scsi_xfer *xs = ccb->xs; - struct scsi_link *sc_link = xs->sc_link; - struct aha_softc *aha = sc_link->adapter_softc; - int s; - - sc_print_addr(sc_link); - printf("timed out"); - - s = splbio(); - - /* - * If The ccb's mbx is not free, then the board has gone south? - */ - if (aha_ccb_phys_kv(aha, _3btol(ccb->mbx->ccb_addr)) == ccb && - ccb->mbx->cmd != AHA_MBO_FREE) { - printf("%s: not taking commands!\n", aha->sc_dev.dv_xname); - Debugger(); - } - - /* - * If it has been through before, then - * a previous abort has failed, don't - * try abort again - */ - if (ccb->flags == CCB_ABORTED) { - /* abort timed out */ - printf(" AGAIN\n"); - ccb->xs->retries = 0; - aha_done(aha, ccb); - } else { - /* abort the operation that has timed out */ - printf("\n"); - ccb->xs->error = XS_TIMEOUT; - ccb->flags = CCB_ABORTED; - aha_send_mbo(aha, AHA_MBO_ABORT, ccb); - /* 2 secs for the abort */ - if ((xs->flags & SCSI_POLL) == 0) - timeout(aha_timeout, ccb, 2 * hz); - } - - splx(s); -} diff --git a/sys/dev/isa/aha284x.c b/sys/dev/isa/aha284x.c index 749f87840e0..bff15bed8e3 100644 --- a/sys/dev/isa/aha284x.c +++ b/sys/dev/isa/aha284x.c @@ -1,4 +1,4 @@ -/* $NetBSD: aha284x.c,v 1.2 1996/01/13 02:06:30 thorpej Exp $ */ +/* $NetBSD: aha284x.c,v 1.4 1996/04/11 22:28:04 cgd Exp $ */ /* * Copyright (c) 1996 Michael Graff. All rights reserved. @@ -47,13 +47,12 @@ static int ahe_probe __P((struct device *, void *, void *)); static void ahe_attach __P((struct device *, struct device *, void *)); -struct cfdriver ahecd = { - NULL, /* devices found */ - "ahe", /* device name */ - ahe_probe, /* match routine */ - ahe_attach, /* attach routine */ - DV_DULL, /* device class */ - sizeof(struct ahc_softc), /* size of private dev data */ +struct cfattach ahe_ca = { + sizeof(struct ahc_softc), ahe_probe, ahe_attach +}; + +struct cfdriver ahe_cd = { + NULL, "ahe", DV_DULL }; /* @@ -179,8 +178,8 @@ ahe_attach(parent, self, aux) #ifdef NEWCONFIG isa_establish(&ahc->sc_id, &ahc->sc_dev); #endif - ahc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_BIO, - ahcintr, ahc, ahc->sc_dev.dv_xname); + ahc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_BIO, ahcintr, ahc, ahc->sc_dev.dv_xname); /* * attach the devices on the bus diff --git a/sys/dev/isa/ahareg.h b/sys/dev/isa/ahareg.h new file mode 100644 index 00000000000..a55684bf044 --- /dev/null +++ b/sys/dev/isa/ahareg.h @@ -0,0 +1,264 @@ +typedef u_int8_t physaddr[3]; +typedef u_int8_t physlen[3]; +#define ltophys _lto3b +#define phystol _3btol + +/* + * I/O port offsets + */ +#define AHA_CTRL_PORT 0 /* control (wo) */ +#define AHA_STAT_PORT 0 /* status (ro) */ +#define AHA_CMD_PORT 1 /* command (wo) */ +#define AHA_DATA_PORT 1 /* data (ro) */ +#define AHA_INTR_PORT 2 /* interrupt status (ro) */ + +/* + * AHA_CTRL bits + */ +#define AHA_CTRL_HRST 0x80 /* Hardware reset */ +#define AHA_CTRL_SRST 0x40 /* Software reset */ +#define AHA_CTRL_IRST 0x20 /* Interrupt reset */ +#define AHA_CTRL_SCRST 0x10 /* SCSI bus reset */ + +/* + * AHA_STAT bits + */ +#define AHA_STAT_STST 0x80 /* Self test in Progress */ +#define AHA_STAT_DIAGF 0x40 /* Diagnostic Failure */ +#define AHA_STAT_INIT 0x20 /* Mbx Init required */ +#define AHA_STAT_IDLE 0x10 /* Host Adapter Idle */ +#define AHA_STAT_CDF 0x08 /* cmd/data out port full */ +#define AHA_STAT_DF 0x04 /* Data in port full */ +#define AHA_STAT_INVDCMD 0x01 /* Invalid command */ + +/* + * AHA_CMD opcodes + */ +#define AHA_NOP 0x00 /* No operation */ +#define AHA_MBX_INIT 0x01 /* Mbx initialization */ +#define AHA_START_SCSI 0x02 /* start scsi command */ +#define AHA_INQUIRE_REVISION 0x04 /* Adapter Inquiry */ +#define AHA_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */ +/*#define AHA_SEL_TIMEOUT_SET 0x06 /* set selection time-out */ +/*#define AHA_BUS_ON_TIME_SET 0x07 /* set bus-on time */ +/*#define AHA_BUS_OFF_TIME_SET 0x08 /* set bus-off time */ +/*#define AHA_SPEED_SET 0x09 /* set transfer speed */ +#define AHA_INQUIRE_DEVICES 0x0a /* return installed devices 0-7 */ +#define AHA_INQUIRE_CONFIG 0x0b /* return configuration data */ +#define AHA_TARGET_EN 0x0c /* enable target mode */ +#define AHA_INQUIRE_SETUP 0x0d /* return setup data */ +#define AHA_ECHO 0x1e /* Echo command data */ +#define AHA_INQUIRE_DEVICES_2 0x23 /* return installed devices 8-15 */ +#define AHA_EXT_BIOS 0x28 /* return extended bios info */ +#define AHA_MBX_ENABLE 0x29 /* enable mail box interface */ + +/* + * AHA_INTR bits + */ +#define AHA_INTR_ANYINTR 0x80 /* Any interrupt */ +#define AHA_INTR_SCRD 0x08 /* SCSI reset detected */ +#define AHA_INTR_HACC 0x04 /* Command complete */ +#define AHA_INTR_MBOA 0x02 /* MBX out empty */ +#define AHA_INTR_MBIF 0x01 /* MBX in full */ + +struct aha_mbx_out { + u_char cmd; + physaddr ccb_addr; +}; + +struct aha_mbx_in { + u_char stat; + physaddr ccb_addr; +}; + +/* + * mbo.cmd values + */ +#define AHA_MBO_FREE 0x0 /* MBO entry is free */ +#define AHA_MBO_START 0x1 /* MBO activate entry */ +#define AHA_MBO_ABORT 0x2 /* MBO abort entry */ + +/* + * mbi.stat values + */ +#define AHA_MBI_FREE 0x0 /* MBI entry is free */ +#define AHA_MBI_OK 0x1 /* completed without error */ +#define AHA_MBI_ABORT 0x2 /* aborted ccb */ +#define AHA_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */ +#define AHA_MBI_ERROR 0x4 /* Completed with error */ + +/* 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) */ + +struct aha_scat_gath { + physlen seg_len; + physaddr seg_addr; +}; + +struct aha_ccb { + u_char opcode; + u_char lun:3; + u_char data_in:1; /* must be 0 */ + u_char data_out:1; /* must be 0 */ + u_char target:3; + u_char scsi_cmd_length; + u_char req_sense_length; + physlen data_length; + physaddr data_addr; + physaddr link_addr; + u_char link_id; + u_char host_stat; + u_char target_stat; + u_char reserved[2]; + struct scsi_generic scsi_cmd; + struct scsi_sense_data scsi_sense; + struct aha_scat_gath scat_gath[AHA_NSEG]; + /*----------------------------------------------------------------*/ + 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_ALLOC 0x01 +#define CCB_ABORT 0x02 +#ifdef AHADIAG +#define CCB_SENDING 0x04 +#endif + int timeout; +}; + +/* + * opcode fields + */ +#define AHA_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */ +#define AHA_TARGET_CCB 0x01 /* SCSI Target CCB */ +#define AHA_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scatter gather */ +#define AHA_RESET_CCB 0x81 /* SCSI Bus reset */ + +/* + * aha_ccb.host_stat values + */ +#define AHA_OK 0x00 /* cmd ok */ +#define AHA_LINK_OK 0x0a /* Link cmd ok */ +#define AHA_LINK_IT 0x0b /* Link cmd ok + int */ +#define AHA_SEL_TIMEOUT 0x11 /* Selection time out */ +#define AHA_OVER_UNDER 0x12 /* Data over/under run */ +#define AHA_BUS_FREE 0x13 /* Bus dropped at unexpected time */ +#define AHA_INV_BUS 0x14 /* Invalid bus phase/sequence */ +#define AHA_BAD_MBO 0x15 /* Incorrect MBO cmd */ +#define AHA_BAD_CCB 0x16 /* Incorrect ccb opcode */ +#define AHA_BAD_LINK 0x17 /* Not same values of LUN for links */ +#define AHA_INV_TARGET 0x18 /* Invalid target direction */ +#define AHA_CCB_DUP 0x19 /* Duplicate CCB received */ +#define AHA_INV_CCB 0x1a /* Invalid CCB or segment list */ + +struct aha_revision { + struct { + u_char opcode; + } cmd; + struct { + u_char boardid; /* type of board */ + /* 0x31 = AHA-1540 */ + /* 0x41 = AHA-1540A/1542A/1542B */ + /* 0x42 = AHA-1640 */ + /* 0x43 = AHA-1542C */ + /* 0x44 = AHA-1542CF */ + /* 0x45 = AHA-1542CF, BIOS v2.01 */ + /* 0x46 = AHA-1542CP */ + u_char spec_opts; /* special options ID */ + /* 0x41 = Board is standard model */ + u_char revision_1; /* firmware revision [0-9A-Z] */ + u_char revision_2; /* firmware revision [0-9A-Z] */ + } reply; +}; + +struct aha_extbios { + struct { + u_char opcode; + } cmd; + struct { + u_char flags; /* Bit 3 == 1 extended bios enabled */ + u_char mailboxlock; /* mail box lock code to unlock it */ + } reply; +}; + +struct aha_toggle { + struct { + u_char opcode; + u_char enable; + } cmd; +}; + +struct aha_config { + struct { + u_char opcode; + } cmd; + struct { + u_char chan; + u_char intr; + u_char scsi_dev:3; + u_char :5; + } reply; +}; + +struct aha_mailbox { + struct { + u_char opcode; + u_char nmbx; + physaddr addr; + } cmd; +}; + +struct aha_unlock { + struct { + u_char opcode; + u_char junk; + u_char magic; + } cmd; +}; + +struct aha_devices { + struct { + u_char opcode; + } cmd; + struct { + u_char junk[8]; + } reply; +}; + +struct aha_setup { + struct { + u_char opcode; + u_char len; + } cmd; + struct { + u_char sync_neg:1; + u_char parity:1; + u_char :6; + u_char speed; + u_char bus_on; + u_char bus_off; + u_char num_mbx; + u_char mbx[3]; + struct { + u_char offset:4; + u_char period:3; + u_char valid:1; + } sync[8]; + u_char disc_sts; + } reply; +}; + +#define INT9 0x01 +#define INT10 0x02 +#define INT11 0x04 +#define INT12 0x08 +#define INT14 0x20 +#define INT15 0x40 + +#define EISADMA 0x00 +#define CHAN0 0x01 +#define CHAN5 0x20 +#define CHAN6 0x40 +#define CHAN7 0x80 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 diff --git a/sys/dev/isa/ast.c b/sys/dev/isa/ast.c index 654c5a77cb3..366e1bf5a4a 100644 --- a/sys/dev/isa/ast.c +++ b/sys/dev/isa/ast.c @@ -1,5 +1,5 @@ -/* $OpenBSD: ast.c,v 1.7 1996/04/18 23:47:29 niklas Exp $ */ -/* $NetBSD: ast.c,v 1.22 1996/03/10 09:01:20 cgd Exp $ */ +/* $OpenBSD: ast.c,v 1.8 1996/04/21 22:22:48 deraadt Exp $ */ +/* $NetBSD: ast.c,v 1.26 1996/04/15 18:55:23 cgd Exp $ */ /* * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. @@ -36,7 +36,13 @@ #include <sys/param.h> #include <sys/device.h> +#include <sys/termios.h> +#ifdef i386 /* XXX */ +#include <machine/cpu.h> /* XXX */ +#else /* XXX */ +#include <machine/intr.h> +#endif /* XXX */ #include <machine/bus.h> #include <dev/isa/isavar.h> @@ -61,8 +67,12 @@ int astprobe(); void astattach(); int astintr __P((void *)); -struct cfdriver astcd = { - NULL, "ast", astprobe, astattach, DV_TTY, sizeof(struct ast_softc) +struct cfattach ast_ca = { + sizeof(struct ast_softc), astprobe, astattach +}; + +struct cfdriver ast_cd = { + NULL, "ast", DV_TTY }; int @@ -163,20 +173,13 @@ astattach(parent, self, aux) ca.ca_iobase = sc->sc_iobase + i * COM_NPORTS; ca.ca_noien = 1; - /* mimic config_found(), but with special functionality */ - if ((match = config_search(NULL, self, &ca)) != NULL) { - subunit = match->cf_unit; /* can change if unit == * */ - config_attach(self, match, &ca, astprint); - sc->sc_slaves[i] = match->cf_driver->cd_devs[subunit]; + sc->sc_slaves[i] = config_found(self, &ca, astprint); + if (sc->sc_slaves[i] != NULL) sc->sc_alive |= 1 << i; - } else { - astprint(&ca, self->dv_xname); - printf(" not configured\n"); - } } - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_TTY, astintr, - sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_TTY, astintr, sc, sc->sc_dev.dv_xname); } int diff --git a/sys/dev/isa/boca.c b/sys/dev/isa/boca.c index d05fa84ae6f..c4ece6a26c5 100644 --- a/sys/dev/isa/boca.c +++ b/sys/dev/isa/boca.c @@ -1,5 +1,5 @@ -/* $OpenBSD: boca.c,v 1.7 1996/04/18 23:47:30 niklas Exp $ */ -/* $NetBSD: boca.c,v 1.9 1996/03/10 09:01:22 cgd Exp $ */ +/* $OpenBSD: boca.c,v 1.8 1996/04/21 22:22:52 deraadt Exp $ */ +/* $NetBSD: boca.c,v 1.13 1996/04/15 18:55:28 cgd Exp $ */ /* * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. @@ -36,7 +36,13 @@ #include <sys/param.h> #include <sys/device.h> +#include <sys/termios.h> +#ifdef i386 /* XXX */ +#include <machine/cpu.h> /* XXX */ +#else /* XXX */ +#include <machine/intr.h> +#endif /* XXX */ #include <machine/bus.h> #include <dev/isa/isavar.h> @@ -61,8 +67,12 @@ int bocaprobe(); void bocaattach(); int bocaintr __P((void *)); -struct cfdriver bocacd = { - NULL, "boca", bocaprobe, bocaattach, DV_TTY, sizeof(struct boca_softc) +struct cfattach boca_ca = { + sizeof(struct boca_softc), bocaprobe, bocaattach, +}; + +struct cfdriver boca_cd = { + NULL, "boca", DV_TTY }; int @@ -158,20 +168,13 @@ bocaattach(parent, self, aux) ca.ca_iobase = sc->sc_iobase + i * COM_NPORTS; ca.ca_noien = 0; - /* mimic config_found(), but with special functionality */ - if ((match = config_search(NULL, self, &ca)) != NULL) { - subunit = match->cf_unit; /* can change if unit == * */ - config_attach(self, match, &ca, bocaprint); - sc->sc_slaves[i] = match->cf_driver->cd_devs[subunit]; + sc->sc_slaves[i] = config_found(self, &ca, bocaprint); + if (sc->sc_slaves[i] != NULL) sc->sc_alive |= 1 << i; - } else { - bocaprint(&ca, self->dv_xname); - printf(" not configured\n"); - } } - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_TTY, bocaintr, - sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_TTY, bocaintr, sc, sc->sc_dev.dv_xname); } int diff --git a/sys/dev/isa/bt.c b/sys/dev/isa/bt.c index 42638c6607f..1875d60eb93 100644 --- a/sys/dev/isa/bt.c +++ b/sys/dev/isa/bt.c @@ -1,8 +1,10 @@ -/* $OpenBSD: bt.c,v 1.7 1996/04/18 23:47:31 niklas Exp $ */ -/* $NetBSD: bt742a.c,v 1.55 1996/03/16 05:33:28 cgd Exp $ */ +/* $NetBSD: bt.c,v 1.7 1996/04/11 22:28:25 cgd Exp $ */ + +#define BTDIAG +#define integrate /* - * Copyright (c) 1994 Charles Hannum. All rights reserved. + * Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,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. * @@ -45,10 +47,6 @@ * functioning of this software in any circumstances. */ -/* - * bt742a SCSI driver - */ - #include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> @@ -63,92 +61,17 @@ #include <machine/pio.h> -#include <dev/isa/isavar.h> -#include <dev/isa/isadmavar.h> #include <scsi/scsi_all.h> #include <scsi/scsiconf.h> -/* - * Note that stdarg.h and the ANSI style va_start macro is used for both - * ANSI and traditional C compilers. - */ -#include <machine/stdarg.h> +#include <dev/isa/isavar.h> +#include <dev/isa/isadmavar.h> +#include <dev/isa/btreg.h> #ifndef DDB #define Debugger() panic("should call debugger here (bt742a.c)") #endif /* ! DDB */ -typedef u_long physaddr; -typedef u_long physlen; - -/* - * I/O Port Interface - */ -#define BT_CTRL_STAT_PORT 0x0 /* control & status */ -#define BT_CMD_DATA_PORT 0x1 /* cmds and datas */ -#define BT_INTR_PORT 0x2 /* Intr. stat */ - -/* - * BT_CTRL_STAT bits (write) - */ -#define BT_HRST 0x80 /* Hardware reset */ -#define BT_SRST 0x40 /* Software reset */ -#define BT_IRST 0x20 /* Interrupt reset */ -#define BT_SCRST 0x10 /* SCSI bus reset */ - -/* - * BT_CTRL_STAT bits (read) - */ -#define BT_STST 0x80 /* Self test in Progress */ -#define BT_DIAGF 0x40 /* Diagnostic Failure */ -#define BT_INIT 0x20 /* Mbx Init required */ -#define BT_IDLE 0x10 /* Host Adapter Idle */ -#define BT_CDF 0x08 /* cmd/data out port full */ -#define BT_DF 0x04 /* Data in port full */ -#define BT_INVDCMD 0x01 /* Invalid command */ - -/* - * BT_CMD_DATA bits (write) - */ -#define BT_NOP 0x00 /* No operation */ -#define BT_MBX_INIT 0x01 /* Mbx initialization */ -#define BT_START_SCSI 0x02 /* start scsi command */ -#define BT_START_BIOS 0x03 /* start bios command */ -#define BT_INQUIRE 0x04 /* Adapter Inquiry */ -#define BT_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */ -#define BT_SEL_TIMEOUT_SET 0x06 /* set selection time-out */ -#define BT_BUS_ON_TIME_SET 0x07 /* set bus-on time */ -#define BT_BUS_OFF_TIME_SET 0x08 /* set bus-off time */ -#define BT_SPEED_SET 0x09 /* set transfer speed */ -#define BT_DEV_GET 0x0a /* return installed devices */ -#define BT_CONF_GET 0x0b /* return configuration data */ -#define BT_TARGET_EN 0x0c /* enable target mode */ -#define BT_SETUP_GET 0x0d /* return setup data */ -#define BT_WRITE_CH2 0x1a /* write channel 2 buffer */ -#define BT_READ_CH2 0x1b /* read channel 2 buffer */ -#define BT_WRITE_FIFO 0x1c /* write fifo buffer */ -#define BT_READ_FIFO 0x1d /* read fifo buffer */ -#define BT_ECHO 0x1e /* Echo command data */ -#define BT_MBX_INIT_EXTENDED 0x81 /* Mbx initialization */ -#define BT_INQUIRE_REV_THIRD 0x84 /* Get 3rd firmware version byte */ -#define BT_INQUIRE_REV_FOURTH 0x85 /* Get 4th firmware version byte */ -#define BT_GET_BOARD_INFO 0x8b /* Get hardware ID and revision */ -#define BT_INQUIRE_EXTENDED 0x8d /* Adapter Setup Inquiry */ - -/* Follows command appeared at firmware 3.31 */ -#define BT_ROUND_ROBIN 0x8f /* Enable/Disable(default) round robin */ -#define BT_DISABLE 0x00 /* Parameter value for Disable */ -#define BT_ENABLE 0x01 /* Parameter value for Enable */ - -/* - * BT_INTR_PORT bits (read) - */ -#define BT_ANY_INTR 0x80 /* Any interrupt */ -#define BT_SCRD 0x08 /* SCSI reset detected */ -#define BT_HACC 0x04 /* Command complete */ -#define BT_MBOA 0x02 /* MBX out empty */ -#define BT_MBIF 0x01 /* MBX in full */ - /* * Mail box defs etc. * these could be bigger but we need the bt_softc to fit on a single page.. @@ -166,180 +89,14 @@ typedef u_long physlen; else \ (wmb)++; -struct bt_mbx_out { - physaddr ccb_addr; - u_char dummy[3]; - u_char cmd; -}; - -struct bt_mbx_in { - physaddr ccb_addr; - u_char btstat; - u_char sdstat; - u_char dummy; - u_char stat; -}; - struct bt_mbx { struct bt_mbx_out mbo[BT_MBX_SIZE]; struct bt_mbx_in mbi[BT_MBX_SIZE]; + struct bt_mbx_out *cmbo; /* Collection Mail Box out */ struct bt_mbx_out *tmbo; /* Target Mail Box out */ struct bt_mbx_in *tmbi; /* Target Mail Box in */ }; -/* - * mbo.cmd values - */ -#define BT_MBO_FREE 0x0 /* MBO entry is free */ -#define BT_MBO_START 0x1 /* MBO activate entry */ -#define BT_MBO_ABORT 0x2 /* MBO abort entry */ - -/* - * mbi.stat values - */ -#define BT_MBI_FREE 0x0 /* MBI entry is free */ -#define BT_MBI_OK 0x1 /* completed without error */ -#define BT_MBI_ABORT 0x2 /* aborted ccb */ -#define BT_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */ -#define BT_MBI_ERROR 0x4 /* Completed with error */ - -#if defined(BIG_DMA) -WARNING...THIS WON'T WORK(won't fit on 1 page) -/* #define BT_NSEG 2048 /* Number of scatter gather segments - to much vm */ -#define BT_NSEG 128 -#else -#define BT_NSEG 33 -#endif /* BIG_DMA */ - -struct bt_scat_gath { - physlen seg_len; - physaddr seg_addr; -}; - -struct bt_ccb { - u_char opcode; - u_char:3, data_in:1, data_out:1,:3; - u_char scsi_cmd_length; - u_char req_sense_length; - /*------------------------------------longword boundary */ - physlen data_length; - /*------------------------------------longword boundary */ - physaddr data_addr; - /*------------------------------------longword boundary */ - u_char dummy1[2]; - u_char host_stat; - u_char target_stat; - /*------------------------------------longword boundary */ - u_char target; - u_char lun; - struct scsi_generic scsi_cmd; - u_char dummy2[1]; - u_char link_id; - /*------------------------------------longword boundary */ - physaddr link_addr; - /*------------------------------------longword boundary */ - physaddr sense_ptr; -/*-----end of HW fields-----------------------longword boundary */ - struct scsi_sense_data scsi_sense; - /*------------------------------------longword boundary */ - struct bt_scat_gath scat_gath[BT_NSEG]; - /*------------------------------------longword boundary */ - TAILQ_ENTRY(bt_ccb) chain; - struct bt_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 bt_mbx_out *mbx; /* pointer to mail box */ -}; - -/* - * opcode fields - */ -#define BT_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */ -#define BT_TARGET_CCB 0x01 /* SCSI Target CCB */ -#define BT_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather */ -#define BT_RESET_CCB 0x81 /* SCSI Bus reset */ - -/* - * bt_ccb.host_stat values - */ -#define BT_OK 0x00 /* cmd ok */ -#define BT_LINK_OK 0x0a /* Link cmd ok */ -#define BT_LINK_IT 0x0b /* Link cmd ok + int */ -#define BT_SEL_TIMEOUT 0x11 /* Selection time out */ -#define BT_OVER_UNDER 0x12 /* Data over/under run */ -#define BT_BUS_FREE 0x13 /* Bus dropped at unexpected time */ -#define BT_INV_BUS 0x14 /* Invalid bus phase/sequence */ -#define BT_BAD_MBO 0x15 /* Incorrect MBO cmd */ -#define BT_BAD_CCB 0x16 /* Incorrect ccb opcode */ -#define BT_BAD_LINK 0x17 /* Not same values of LUN for links */ -#define BT_INV_TARGET 0x18 /* Invalid target direction */ -#define BT_CCB_DUP 0x19 /* Duplicate CCB received */ -#define BT_INV_CCB 0x1a /* Invalid CCB or segment list */ -#define BT_ABORTED 42 /* pseudo value from driver */ - -struct bt_extended_inquire { - u_char bus_type; /* Type of bus connected to */ -#define BT_BUS_TYPE_24BIT 'A' /* ISA bus */ -#define BT_BUS_TYPE_32BIT 'E' /* EISA/VLB/PCI bus */ -#define BT_BUS_TYPE_MCA 'M' /* MicroChannel bus */ - u_char bios_address; /* Address of adapter BIOS */ - u_short max_segment; /* ? */ -}; - -struct bt_boardID { - u_char board_type; - u_char custom_feture; - char firm_revision; - u_char firm_version; -}; - -struct bt_board_info { - u_char id[4]; /* i.e bt742a -> '7','4','2','A' */ - u_char version[2]; /* i.e Board Revision 'H' -> 'H', 0x00 */ -}; - -struct bt_setup { - u_char sync_neg:1; - u_char parity:1; - u_char :6; - u_char speed; - u_char bus_on; - u_char bus_off; - u_char num_mbx; - u_char mbx[3]; /*XXX */ - /* doesn't make sense with 32bit addresses */ - struct { - u_char offset:4; - u_char period:3; - u_char valid:1; - } sync[8]; - u_char disc_sts; -}; - -struct bt_config { - u_char chan; - u_char intr; - u_char scsi_dev:3; - u_char :5; -}; - -#define INT9 0x01 -#define INT10 0x02 -#define INT11 0x04 -#define INT12 0x08 -#define INT14 0x20 -#define INT15 0x40 - -#define EISADMA 0x00 -#define CHAN0 0x01 -#define CHAN5 0x20 -#define CHAN6 0x40 -#define CHAN7 0x80 - #define KVTOPHYS(x) vtophys(x) struct bt_softc { @@ -350,28 +107,33 @@ struct bt_softc { int sc_iobase; int sc_irq, sc_drq; + char sc_model[7], + sc_firmware[6]; + struct bt_mbx sc_mbx; /* all our mailboxes */ +#define wmbx (&sc->sc_mbx) struct bt_ccb *sc_ccbhash[CCB_HASH_SIZE]; - TAILQ_HEAD(, bt_ccb) sc_free_ccb; - int sc_numccbs; + TAILQ_HEAD(, bt_ccb) sc_free_ccb, sc_waiting_ccb; + int sc_numccbs, sc_mbofull; int sc_scsi_dev; /* adapters scsi id */ struct scsi_link sc_link; /* prototype for devs */ }; -/***********debug values *************/ -#define BT_SHOWCCBS 0x01 -#define BT_SHOWINTS 0x02 -#define BT_SHOWCMDS 0x04 -#define BT_SHOWMISC 0x08 +#ifdef BTDEBUG int bt_debug = 0; +#endif /* BTDEBUG */ -int bt_cmd __P((int, struct bt_softc *, int, int, int, u_char *, - unsigned, ...)); +int bt_cmd __P((int, struct bt_softc *, int, u_char *, int, u_char *)); +integrate void bt_finish_ccbs __P((struct bt_softc *)); int btintr __P((void *)); -void bt_free_ccb __P((struct bt_softc *, struct bt_ccb *, int)); +integrate void bt_reset_ccb __P((struct bt_softc *, struct bt_ccb *)); +void bt_free_ccb __P((struct bt_softc *, struct bt_ccb *)); +integrate void bt_init_ccb __P((struct bt_softc *, struct bt_ccb *)); struct bt_ccb *bt_get_ccb __P((struct bt_softc *, int)); struct bt_ccb *bt_ccb_phys_kv __P((struct bt_softc *, u_long)); -struct bt_mbx_out *bt_send_mbo __P((struct bt_softc *, int, struct bt_ccb *)); +void bt_queue_ccb __P((struct bt_softc *, struct bt_ccb *)); +void bt_collect_mbo __P((struct bt_softc *)); +void bt_start_ccbs __P((struct bt_softc *)); void bt_done __P((struct bt_softc *, struct bt_ccb *)); int bt_find __P((struct isa_attach_args *, struct bt_softc *)); void bt_init __P((struct bt_softc *)); @@ -380,10 +142,6 @@ void btminphys __P((struct buf *)); int bt_scsi_cmd __P((struct scsi_xfer *)); int bt_poll __P((struct bt_softc *, struct scsi_xfer *, int)); void bt_timeout __P((void *arg)); -#ifdef UTEST -void bt_print_ccb __P((struct bt_ccb *)); -void bt_print_active_ccbs __P((struct bt_softc *)); -#endif struct scsi_adapter bt_switch = { bt_scsi_cmd, @@ -404,47 +162,43 @@ int btprobe __P((struct device *, void *, void *)); void btattach __P((struct device *, struct device *, void *)); int btprint __P((void *, char *)); -struct cfdriver btcd = { - NULL, "bt", btprobe, btattach, DV_DULL, sizeof(struct bt_softc) +struct cfattach bt_ca = { + sizeof(struct bt_softc), btprobe, btattach +}; + +struct cfdriver bt_cd = { + NULL, "bt", DV_DULL }; -#define BT_RESET_TIMEOUT 1000 +#define BT_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */ +#define BT_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */ /* - * bt_cmd(iobase, sc, icnt, ocnt, wait, retval, opcode, ... args ...) + * bt_cmd(iobase, sc, icnt, ibuf, ocnt, obuf) * * Activate Adapter command - * icnt: number of args (outbound bytes written after opcode) + * icnt: number of args (outbound bytes including opcode) + * ibuf: argument buffer * ocnt: number of expected returned bytes + * obuf: result buffer * wait: number of seconds to wait for response - * retval: buffer where to place returned bytes - * opcode: opcode BT_NOP, BT_MBX_INIT, BT_START_SCSI ... - * args: variable number of parameters * * Performs an adapter command through the ports. Not to be confused with a * scsi command, which is read in via the dma; one of the adapter commands * tells it to read in a scsi command. */ int -#ifdef __STDC__ -bt_cmd(int iobase, struct bt_softc *sc, int icnt, int ocnt, int wait, - u_char *retval, unsigned opcode, ...) -#else -bt_cmd(iobase, sc, icnt, ocnt, wait, retval, opcode, va_alist) +bt_cmd(iobase, sc, icnt, ibuf, ocnt, obuf) int iobase; struct bt_softc *sc; - int icnt, ocnt, wait; - u_char *retval; - unsigned opcode; - va_dcl -#endif + int icnt, ocnt; + u_char *ibuf, *obuf; { - va_list ap; - unsigned data; const char *name; - u_char oc; - register i; - int sts; + register int i; + int wait; + u_char sts; + u_char opcode = ibuf[0]; if (sc == NULL) name = sc->sc_dev.dv_xname; @@ -452,29 +206,31 @@ bt_cmd(iobase, sc, icnt, ocnt, wait, retval, opcode, va_alist) name = "(probe)"; /* - * multiply the wait argument by a big constant - * zero defaults to 1 + * Calculate a reasonable timeout for the command. */ - if (wait) - wait *= 100000; - else - wait = 100000; + switch (opcode) { + case BT_INQUIRE_DEVICES: + wait = 15 * 20000; + break; + default: + wait = 1 * 20000; + break; + } + /* * Wait for the adapter to go idle, unless it's one of * the commands which don't need this */ - if (opcode != BT_MBX_INIT && opcode != BT_START_SCSI) { - i = 100000; /* 1 sec? */ - while (--i) { - sts = inb(iobase + BT_CTRL_STAT_PORT); - if (sts & BT_IDLE) { + if (opcode != BT_MBO_INTR_EN) { + for (i = 20000; i; i--) { /* 1 sec? */ + sts = inb(iobase + BT_STAT_PORT); + if (sts & BT_STAT_IDLE) break; - } - delay(10); + delay(50); } if (!i) { printf("%s: bt_cmd, host not idle(0x%x)\n", - name, sts); + name, sts); return ENXIO; } } @@ -483,69 +239,68 @@ bt_cmd(iobase, sc, icnt, ocnt, wait, retval, opcode, va_alist) * queue feeding to us. */ if (ocnt) { - while ((inb(iobase + BT_CTRL_STAT_PORT)) & BT_DF) - inb(iobase + BT_CMD_DATA_PORT); + while ((inb(iobase + BT_STAT_PORT)) & BT_STAT_DF) + inb(iobase + BT_DATA_PORT); } /* * Output the command and the number of arguments given * for each byte, first check the port is empty. */ - va_start(ap, opcode); - /* test icnt >= 0, to include the command in data sent */ - for (data = opcode; icnt >= 0; icnt--, data = va_arg(ap, u_char)) { - sts = inb(iobase + BT_CTRL_STAT_PORT); + while (icnt--) { for (i = wait; i; i--) { - sts = inb(iobase + BT_CTRL_STAT_PORT); - if (!(sts & BT_CDF)) + sts = inb(iobase + BT_STAT_PORT); + if (!(sts & BT_STAT_CDF)) break; - delay(10); + delay(50); } if (!i) { - printf("%s: bt_cmd, cmd/data port full\n", name); - outb(iobase + BT_CTRL_STAT_PORT, BT_SRST); - va_end(ap); + if (opcode != BT_INQUIRE_REVISION) + printf("%s: bt_cmd, cmd/data port full\n", name); + outb(iobase + BT_CTRL_PORT, BT_CTRL_SRST); return ENXIO; } - outb(iobase + BT_CMD_DATA_PORT, data); + outb(iobase + BT_CMD_PORT, *ibuf++); } - va_end(ap); /* * If we expect input, loop that many times, each time, * looking for the data register to have valid data */ while (ocnt--) { - sts = inb(iobase + BT_CTRL_STAT_PORT); for (i = wait; i; i--) { - sts = inb(iobase + BT_CTRL_STAT_PORT); - if (sts & BT_DF) + sts = inb(iobase + BT_STAT_PORT); + if (sts & BT_STAT_DF) break; - delay(10); + delay(50); } if (!i) { - printf("bt%d: bt_cmd, cmd/data port empty %d\n", - name, ocnt); + if (opcode != BT_INQUIRE_REVISION) + printf("%s: bt_cmd, cmd/data port empty %d\n", + name, ocnt); + outb(iobase + BT_CTRL_PORT, BT_CTRL_SRST); return ENXIO; } - oc = inb(iobase + BT_CMD_DATA_PORT); - if (retval) - *retval++ = oc; + *obuf++ = inb(iobase + BT_DATA_PORT); } /* - * Wait for the board to report a finised instruction + * Wait for the board to report a finished instruction. + * We may get an extra interrupt for the HACC signal, but this is + * unimportant. */ - i = 100000; /* 1 sec? */ - while (--i) { - sts = inb(iobase + BT_INTR_PORT); - if (sts & BT_HACC) - break; - delay(10); - } - if (!i) { - printf("%s: bt_cmd, host not finished(0x%x)\n", - name, sts); - return ENXIO; + if (opcode != BT_MBO_INTR_EN) { + for (i = 20000; i; i--) { /* 1 sec? */ + sts = inb(iobase + BT_INTR_PORT); + /* XXX Need to save this in the interrupt handler? */ + if (sts & BT_INTR_HACC) + break; + delay(50); + } + if (!i) { + printf("%s: bt_cmd, host not finished(0x%x)\n", + name, sts); + return ENXIO; + } } - outb(iobase + BT_CTRL_STAT_PORT, BT_IRST); + outb(iobase + BT_CTRL_PORT, BT_CTRL_IRST); return 0; } @@ -560,7 +315,6 @@ btprobe(parent, match, aux) struct device *parent; void *match, *aux; { - struct bt_softc *sc = match; register struct isa_attach_args *ia = aux; #ifdef NEWCONFIG @@ -568,16 +322,13 @@ btprobe(parent, match, aux) return 0; #endif - /* - * Try initialise a unit at this location - * sets up dma and bus speed, loads sc->sc_irq - */ + /* See if there is a unit at this location. */ if (bt_find(ia, NULL) != 0) return 0; ia->ia_msize = 0; ia->ia_iosize = 4; - /* IRQ and DRQ set by bt_find() */ + /* IRQ and DRQ set by bt_find(). */ return 1; } @@ -586,6 +337,7 @@ btprint(aux, name) void *aux; char *name; { + if (name != NULL) printf("%s: scsibus ", name); return UNCONF; @@ -600,7 +352,7 @@ btattach(parent, self, aux) void *aux; { struct isa_attach_args *ia = aux; - struct bt_softc *sc = (struct bt_softc *)self; + struct bt_softc *sc = (void *)self; if (bt_find(ia, sc) != 0) panic("btattach: bt_find of %s failed", self->dv_xname); @@ -609,8 +361,10 @@ btattach(parent, self, aux) if (sc->sc_drq != DRQUNK) isa_dmacascade(sc->sc_drq); + bt_inquire_setup_information(sc); bt_init(sc); TAILQ_INIT(&sc->sc_free_ccb); + TAILQ_INIT(&sc->sc_waiting_ccb); /* * fill in the prototype scsi_link. @@ -619,15 +373,13 @@ btattach(parent, self, aux) sc->sc_link.adapter_target = sc->sc_scsi_dev; sc->sc_link.adapter = &bt_switch; sc->sc_link.device = &bt_dev; - sc->sc_link.openings = 2; - - printf("\n"); + sc->sc_link.openings = 4; #ifdef NEWCONFIG isa_establish(&sc->sc_id, &sc->sc_dev); #endif - sc->sc_ih = isa_intr_establish(sc->sc_irq, IST_EDGE, IPL_BIO, btintr, - sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, sc->sc_irq, IST_EDGE, + IPL_BIO, btintr, sc, sc->sc_dev.dv_xname); /* * ask the adapter what subunits are present @@ -635,141 +387,162 @@ btattach(parent, self, aux) config_found(self, &sc->sc_link, btprint); } -/* - * Catch an interrupt from the adaptor - */ -int -btintr(arg) - void *arg; +integrate void +bt_finish_ccbs(sc) + struct bt_softc *sc; { - struct bt_softc *sc = arg; - int iobase = sc->sc_iobase; struct bt_mbx_in *wmbi; - struct bt_mbx *wmbx; struct bt_ccb *ccb; - u_char stat; int i; - int found = 0; -#ifdef BTDEBUG - printf("%s: btintr ", sc->sc_dev.dv_xname); -#endif /* BTDEBUG */ - - /* - * First acknowlege the interrupt, Then if it's - * not telling about a completed operation - * just return. - */ - stat = inb(iobase + BT_INTR_PORT); - if ((stat & (BT_MBOA | BT_MBIF)) == 0) { - outb(iobase + BT_CTRL_STAT_PORT, BT_IRST); - return -1; /* XXX */ - } + wmbi = wmbx->tmbi; - /* Mail box out empty? */ - if (stat & BT_MBOA) { - /* Disable MBO available interrupt. */ - outb(iobase + BT_CMD_DATA_PORT, BT_MBO_INTR_EN); - for (i = 100000; i; i--) { - if (!(inb(iobase + BT_CTRL_STAT_PORT) & BT_CDF)) - break; - delay(10); - } - if (!i) { - printf("%s: btintr, cmd/data port full\n", - sc->sc_dev.dv_xname); - outb(iobase + BT_CTRL_STAT_PORT, BT_SRST); - return 1; + if (wmbi->stat == BT_MBI_FREE) { + for (i = 0; i < BT_MBX_SIZE; i++) { + if (wmbi->stat != BT_MBI_FREE) { + printf("%s: mbi not in round-robin order\n", + sc->sc_dev.dv_xname); + goto AGAIN; + } + bt_nextmbx(wmbi, wmbx, mbi); } - outb(iobase + BT_CMD_DATA_PORT, 0x00); /* Disable */ - wakeup(&sc->sc_mbx); +#ifdef BTDIAGnot + printf("%s: mbi interrupt with no full mailboxes\n", + sc->sc_dev.dv_xname); +#endif + return; } - /* Mail box in full? */ - if ((stat & BT_MBIF) == 0) - return 1; - wmbx = &sc->sc_mbx; - wmbi = wmbx->tmbi; AGAIN: - while (wmbi->stat != BT_MBI_FREE) { - ccb = bt_ccb_phys_kv(sc, wmbi->ccb_addr); + do { + ccb = bt_ccb_phys_kv(sc, phystol(wmbi->ccb_addr)); if (!ccb) { - wmbi->stat = BT_MBI_FREE; - printf("%s: BAD CCB ADDR!\n", sc->sc_dev.dv_xname); - continue; + printf("%s: bad mbi ccb pointer; skipping\n", + sc->sc_dev.dv_xname); + goto next; + } + +#ifdef BTDEBUG + if (bt_debug) { + u_char *cp = &ccb->scsi_cmd; + printf("op=%x %x %x %x %x %x\n", + cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); + printf("stat %x for mbi addr = 0x%08x, ", + wmbi->stat, wmbi); + printf("ccb addr = 0x%x\n", ccb); } - found++; +#endif /* BTDEBUG */ + switch (wmbi->stat) { case BT_MBI_OK: case BT_MBI_ERROR: + if ((ccb->flags & CCB_ABORT) != 0) { + /* + * If we already started an abort, wait for it + * to complete before clearing the CCB. We + * could instead just clear CCB_SENDING, but + * what if the mailbox was already received? + * The worst that happens here is that we clear + * the CCB a bit later than we need to. BFD. + */ + goto next; + } break; case BT_MBI_ABORT: - ccb->host_stat = BT_ABORTED; - break; - case BT_MBI_UNKNOWN: - ccb = 0; + /* + * Even if the CCB wasn't found, we clear it anyway. + * See preceeding comment. + */ break; default: - panic("Impossible mbxi status"); + printf("%s: bad mbi status %02x; skipping\n", + sc->sc_dev.dv_xname, wmbi->stat); + goto next; } -#ifdef BTDEBUG - if (bt_debug && ccb) { - u_char *cp = &ccb->scsi_cmd; - printf("op=%x %x %x %x %x %x\n", - cp[0], cp[1], cp[2], - cp[3], cp[4], cp[5]); - printf("stat %x for mbi addr = 0x%08x, ", - wmbi->stat, wmbi); - printf("ccb addr = 0x%x\n", ccb); - } -#endif /* BTDEBUG */ + + untimeout(bt_timeout, ccb); + bt_done(sc, ccb); + + next: wmbi->stat = BT_MBI_FREE; - if (ccb) { - untimeout(bt_timeout, ccb); - bt_done(sc, ccb); - } bt_nextmbx(wmbi, wmbx, mbi); - } - if (!found) { - for (i = 0; i < BT_MBX_SIZE; i++) { - if (wmbi->stat != BT_MBI_FREE) { - found++; - break; - } - bt_nextmbx(wmbi, wmbx, mbi); - } - if (!found) { -#if 0 - printf("%s: mbi interrupt with no full mailboxes\n", - sc->sc_dev.dv_xname); + } while (wmbi->stat != BT_MBI_FREE); + + wmbx->tmbi = wmbi; +} + +/* + * Catch an interrupt from the adaptor + */ +int +btintr(arg) + void *arg; +{ + struct bt_softc *sc = arg; + int iobase = sc->sc_iobase; + u_char sts; + +#ifdef BTDEBUG + printf("%s: btintr ", sc->sc_dev.dv_xname); +#endif /* BTDEBUG */ + + /* + * First acknowlege the interrupt, Then if it's not telling about + * a completed operation just return. + */ + sts = inb(iobase + BT_INTR_PORT); + if ((sts & BT_INTR_ANYINTR) == 0) + return 0; + outb(iobase + BT_CTRL_PORT, BT_CTRL_IRST); + +#ifdef BTDIAG + /* Make sure we clear CCB_SENDING before finishing a CCB. */ + bt_collect_mbo(sc); #endif - } else { - found = 0; - goto AGAIN; - } + + /* Mail box out empty? */ + if (sts & BT_INTR_MBOA) { + struct bt_toggle toggle; + + toggle.cmd.opcode = BT_MBO_INTR_EN; + toggle.cmd.enable = 0; + bt_cmd(iobase, sc, sizeof(toggle.cmd), (u_char *)&toggle.cmd, 0, + (u_char *)0); + bt_start_ccbs(sc); } - wmbx->tmbi = wmbi; - outb(iobase + BT_CTRL_STAT_PORT, BT_IRST); + + /* Mail box in full? */ + if (sts & BT_INTR_MBIF) + bt_finish_ccbs(sc); + return 1; } +integrate void +bt_reset_ccb(sc, ccb) + struct bt_softc *sc; + struct bt_ccb *ccb; +{ + + ccb->flags = 0; +} + /* * A ccb is put onto the free list. */ void -bt_free_ccb(sc, ccb, flags) +bt_free_ccb(sc, ccb) struct bt_softc *sc; struct bt_ccb *ccb; - int flags; { int s; s = splbio(); - ccb->flags = CCB_FREE; + bt_reset_ccb(sc, ccb); TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, chain); /* @@ -782,7 +555,7 @@ bt_free_ccb(sc, ccb, flags) splx(s); } -static inline void +integrate void bt_init_ccb(sc, ccb) struct bt_softc *sc; struct bt_ccb *ccb; @@ -798,14 +571,7 @@ bt_init_ccb(sc, ccb) hashnum = CCB_HASH(ccb->hashkey); ccb->nexthash = sc->sc_ccbhash[hashnum]; sc->sc_ccbhash[hashnum] = ccb; -} - -static inline void -bt_reset_ccb(sc, ccb) - struct bt_softc *sc; - struct bt_ccb *ccb; -{ - + bt_reset_ccb(sc, ccb); } /* @@ -835,15 +601,15 @@ bt_get_ccb(sc, flags) break; } if (sc->sc_numccbs < BT_CCB_MAX) { - if (ccb = (struct bt_ccb *) malloc(sizeof(struct bt_ccb), - M_TEMP, M_NOWAIT)) { - bt_init_ccb(sc, ccb); - sc->sc_numccbs++; - } else { + ccb = (struct bt_ccb *) malloc(sizeof(struct bt_ccb), + M_TEMP, M_NOWAIT); + if (!ccb) { printf("%s: can't malloc ccb\n", sc->sc_dev.dv_xname); goto out; } + bt_init_ccb(sc, ccb); + sc->sc_numccbs++; break; } if ((flags & SCSI_NOSLEEP) != 0) @@ -851,8 +617,7 @@ bt_get_ccb(sc, flags) tsleep(&sc->sc_free_ccb, PRIBIO, "btccb", 0); } - bt_reset_ccb(sc, ccb); - ccb->flags = CCB_ACTIVE; + ccb->flags |= CCB_ALLOC; out: splx(s); @@ -860,8 +625,7 @@ out: } /* - * given a physical address, find the ccb that - * it corresponds to: + * Given a physical address, find the ccb that it corresponds to. */ struct bt_ccb * bt_ccb_phys_kv(sc, ccb_phys) @@ -880,55 +644,97 @@ bt_ccb_phys_kv(sc, ccb_phys) } /* - * Get a mbo and send the ccb. + * Queue a CCB to be sent to the controller, and send it if possible. + */ +void +bt_queue_ccb(sc, ccb) + struct bt_softc *sc; + struct bt_ccb *ccb; +{ + + TAILQ_INSERT_TAIL(&sc->sc_waiting_ccb, ccb, chain); + bt_start_ccbs(sc); +} + +/* + * Garbage collect mailboxes that are no longer in use. */ -struct bt_mbx_out * -bt_send_mbo(sc, cmd, ccb) +void +bt_collect_mbo(sc) struct bt_softc *sc; - int cmd; +{ + struct bt_mbx_out *wmbo; /* Mail Box Out pointer */ struct bt_ccb *ccb; + + wmbo = wmbx->cmbo; + + while (sc->sc_mbofull > 0) { + if (wmbo->cmd != BT_MBO_FREE) + break; + +#ifdef BTDIAG + ccb = bt_ccb_phys_kv(sc, phystol(wmbo->ccb_addr)); + ccb->flags &= ~CCB_SENDING; +#endif + + --sc->sc_mbofull; + bt_nextmbx(wmbo, wmbx, mbo); + } + + wmbx->cmbo = wmbo; +} + +/* + * Send as many CCBs as we have empty mailboxes for. + */ +void +bt_start_ccbs(sc) + struct bt_softc *sc; { int iobase = sc->sc_iobase; struct bt_mbx_out *wmbo; /* Mail Box Out pointer */ - struct bt_mbx *wmbx; /* Mail Box pointer specified unit */ + struct bt_ccb *ccb; int i; - /* Get the target out mail box pointer and increment. */ - wmbx = &sc->sc_mbx; wmbo = wmbx->tmbo; - bt_nextmbx(wmbx->tmbo, wmbx, mbo); - /* - * Check the outmail box is free or not. - * Note: Under the normal operation, it shuld NOT happen to wait. - */ - while (wmbo->cmd != BT_MBO_FREE) { - /* Enable mbo available interrupt. */ - outb(iobase + BT_CMD_DATA_PORT, BT_MBO_INTR_EN); - for (i = 100000; i; i--) { - if (!(inb(iobase + BT_CTRL_STAT_PORT) & BT_CDF)) + while (ccb = sc->sc_waiting_ccb.tqh_first) { + if (sc->sc_mbofull >= BT_MBX_SIZE) { + bt_collect_mbo(sc); + if (sc->sc_mbofull >= BT_MBX_SIZE) { + struct bt_toggle toggle; + + toggle.cmd.opcode = BT_MBO_INTR_EN; + toggle.cmd.enable = 1; + bt_cmd(iobase, sc, sizeof(toggle.cmd), + (u_char *)&toggle.cmd, 0, (u_char *)0); break; - delay(10); - } - if (!i) { - printf("%s: bt_send_mbo, cmd/data port full\n", - sc->sc_dev.dv_xname); - outb(iobase + BT_CTRL_STAT_PORT, BT_SRST); - return NULL; + } } - outb(iobase + BT_CMD_DATA_PORT, 0x01); /* Enable */ - tsleep(wmbx, PRIBIO, "btsnd", 0);/*XXX can't do this */ - } - /* Link ccb to mbo. */ - wmbo->ccb_addr = KVTOPHYS(ccb); - ccb->mbx = wmbo; - wmbo->cmd = cmd; + TAILQ_REMOVE(&sc->sc_waiting_ccb, ccb, chain); +#ifdef BTDIAG + ccb->flags |= CCB_SENDING; +#endif + + /* Link ccb to mbo. */ + ltophys(KVTOPHYS(ccb), wmbo->ccb_addr); + if (ccb->flags & CCB_ABORT) + wmbo->cmd = BT_MBO_ABORT; + else + wmbo->cmd = BT_MBO_START; + + /* Tell the card to poll immediately. */ + outb(iobase + BT_CMD_PORT, BT_START_SCSI); + + if ((ccb->xs->flags & SCSI_POLL) == 0) + timeout(bt_timeout, ccb, (ccb->timeout * hz) / 1000); - /* Send it! */ - outb(iobase + BT_CMD_DATA_PORT, BT_START_SCSI); + ++sc->sc_mbofull; + bt_nextmbx(wmbo, wmbx, mbo); + } - return wmbo; + wmbx->tmbo = wmbo; } /* @@ -949,16 +755,21 @@ bt_done(sc, ccb) * Otherwise, put the results of the operation * into the xfer and call whoever started it */ - if ((xs->flags & INUSE) == 0) { - printf("%s: exiting but not in use!\n", sc->sc_dev.dv_xname); +#ifdef BTDIAG + if (ccb->flags & CCB_SENDING) { + printf("%s: exiting ccb still in transit!\n", sc->sc_dev.dv_xname); Debugger(); + return; + } +#endif + if ((ccb->flags & CCB_ALLOC) == 0) { + printf("%s: exiting ccb not allocated!\n", sc->sc_dev.dv_xname); + Debugger(); + return; } if (xs->error == XS_NOERROR) { if (ccb->host_stat != BT_OK) { switch (ccb->host_stat) { - case BT_ABORTED: - xs->error = XS_DRIVER_STUFFUP; - break; case BT_SEL_TIMEOUT: /* No response */ xs->error = XS_SELTIMEOUT; break; @@ -966,6 +777,7 @@ bt_done(sc, ccb) printf("%s: host_stat %x\n", sc->sc_dev.dv_xname, ccb->host_stat); xs->error = XS_DRIVER_STUFFUP; + break; } } else if (ccb->target_stat != SCSI_OK) { switch (ccb->target_stat) { @@ -982,12 +794,13 @@ bt_done(sc, ccb) printf("%s: target_stat %x\n", sc->sc_dev.dv_xname, ccb->target_stat); xs->error = XS_DRIVER_STUFFUP; + break; } } else xs->resid = 0; } + bt_free_ccb(sc, ccb); xs->flags |= ITSDONE; - bt_free_ccb(sc, ccb, xs->flags); scsi_done(xs); } @@ -1000,10 +813,10 @@ bt_find(ia, sc) struct bt_softc *sc; { int iobase = ia->ia_iobase; - u_char ad[4]; - volatile int i, sts; - struct bt_extended_inquire info; - struct bt_config conf; + int i; + u_char sts; + struct bt_extended_inquire inquire; + struct bt_config config; int irq, drq; /* @@ -1011,18 +824,20 @@ bt_find(ia, sc) * that it's not there.. good for the probe */ - outb(iobase + BT_CTRL_STAT_PORT, BT_HRST | BT_SRST); + outb(iobase + BT_CTRL_PORT, BT_CTRL_HRST | BT_CTRL_SRST); + delay(100); for (i = BT_RESET_TIMEOUT; i; i--) { - sts = inb(iobase + BT_CTRL_STAT_PORT); - if (sts == (BT_IDLE | BT_INIT)) + sts = inb(iobase + BT_STAT_PORT); + if (sts == (BT_STAT_IDLE | BT_STAT_INIT)) break; delay(1000); } if (!i) { -#ifdef UTEST - printf("bt_find: No answer from bt742a board\n"); -#endif +#ifdef BTDEBUG + if (bt_debug) + printf("bt_find: No answer from buslogic board\n"); +#endif /* BTDEBUG */ return 1; } @@ -1030,9 +845,11 @@ bt_find(ia, sc) * Check that we actually know how to use this board. */ delay(1000); - bt_cmd(iobase, sc, 1, sizeof(info), 0, (u_char *)&info, - BT_INQUIRE_EXTENDED, sizeof(info)); - switch (info.bus_type) { + inquire.cmd.opcode = BT_INQUIRE_EXTENDED; + inquire.cmd.len = sizeof(inquire.reply); + bt_cmd(iobase, sc, sizeof(inquire.cmd), (u_char *)&inquire.cmd, + sizeof(inquire.reply), (u_char *)&inquire.reply); + switch (inquire.reply.bus_type) { case BT_BUS_TYPE_24BIT: /* XXXX How do we avoid conflicting with the aha1542 probe? */ case BT_BUS_TYPE_32BIT: @@ -1041,7 +858,7 @@ bt_find(ia, sc) /* We don't grok MicroChannel (yet). */ return 1; default: - printf("bt_find: illegal bus type %c\n", info.bus_type); + printf("bt_find: illegal bus type %c\n", inquire.reply.bus_type); return 1; } @@ -1050,8 +867,10 @@ bt_find(ia, sc) * jumpers and save int level */ delay(1000); - bt_cmd(iobase, sc, 0, sizeof(conf), 0, (u_char *)&conf, BT_CONF_GET); - switch (conf.chan) { + config.cmd.opcode = BT_INQUIRE_CONFIG; + bt_cmd(iobase, sc, sizeof(config.cmd), (u_char *)&config.cmd, + sizeof(config.reply), (u_char *)&config.reply); + switch (config.reply.chan) { case EISADMA: drq = DRQUNK; break; @@ -1068,11 +887,11 @@ bt_find(ia, sc) drq = 7; break; default: - printf("bt_find: illegal dma setting %x\n", conf.chan); + printf("bt_find: illegal drq setting %x\n", config.reply.chan); return 1; } - switch (conf.intr) { + switch (config.reply.intr) { case INT9: irq = 9; break; @@ -1092,13 +911,13 @@ bt_find(ia, sc) irq = 15; break; default: - printf("bt_find: illegal int setting %x\n", conf.intr); + printf("bt_find: illegal irq setting %x\n", config.reply.intr); return 1; } if (sc != NULL) { /* who are we on the scsi bus? */ - sc->sc_scsi_dev = conf.scsi_dev; + sc->sc_scsi_dev = config.reply.scsi_dev; sc->sc_iobase = iobase; sc->sc_irq = irq; @@ -1125,29 +944,74 @@ bt_init(sc) struct bt_softc *sc; { int iobase = sc->sc_iobase; - u_char ad[4]; + struct bt_devices devices; + struct bt_setup setup; + struct bt_mailbox mailbox; + struct bt_period period; int i; - /* - * Initialize mail box - */ - *((physaddr *)ad) = KVTOPHYS(&sc->sc_mbx); + /* Enable round-robin scheme - appeared at firmware rev. 3.31. */ + if (strcmp(sc->sc_firmware, "3.31") >= 0) { + struct bt_toggle toggle; - bt_cmd(iobase, sc, 5, 0, 0, 0, BT_MBX_INIT_EXTENDED, BT_MBX_SIZE, - ad[0], ad[1], ad[2], ad[3]); + toggle.cmd.opcode = BT_ROUND_ROBIN; + toggle.cmd.enable = 1; + bt_cmd(iobase, sc, sizeof(toggle.cmd), (u_char *)&toggle.cmd, + 0, (u_char *)0); + } - for (i = 0; i < BT_MBX_SIZE; i++) { - sc->sc_mbx.mbo[i].cmd = BT_MBO_FREE; - sc->sc_mbx.mbi[i].stat = BT_MBI_FREE; + /* Inquire Installed Devices (to force synchronous negotiation). */ + devices.cmd.opcode = BT_INQUIRE_DEVICES; + bt_cmd(iobase, sc, sizeof(devices.cmd), (u_char *)&devices.cmd, + sizeof(devices.reply), (u_char *)&devices.reply); + + /* Obtain setup information from. */ + setup.cmd.opcode = BT_INQUIRE_SETUP; + setup.cmd.len = sizeof(setup.reply); + bt_cmd(iobase, sc, sizeof(setup.cmd), (u_char *)&setup.cmd, + sizeof(setup.reply), (u_char *)&setup.reply); + + printf("%s: %s, %s\n", + sc->sc_dev.dv_xname, + setup.reply.sync_neg ? "sync" : "async", + setup.reply.parity ? "parity" : "no parity"); + + for (i = 0; i < 8; i++) + period.reply.period[i] = setup.reply.sync[i].period * 5 + 20; + + if (sc->sc_firmware[0] >= '3') { + period.cmd.opcode = BT_INQUIRE_PERIOD; + period.cmd.len = sizeof(period.reply); + bt_cmd(iobase, sc, sizeof(period.cmd), (u_char *)&period.cmd, + sizeof(period.reply), (u_char *)&period.reply); + } + + for (i = 0; i < 8; i++) { + if (!setup.reply.sync[i].valid || + (!setup.reply.sync[i].offset && !setup.reply.sync[i].period)) + continue; + printf("%s targ %d: sync, offset %d, period %dnsec\n", + sc->sc_dev.dv_xname, i, + setup.reply.sync[i].offset, period.reply.period[i] * 10); } /* * Set up initial mail box for round-robin operation. */ - sc->sc_mbx.tmbo = &sc->sc_mbx.mbo[0]; - sc->sc_mbx.tmbi = &sc->sc_mbx.mbi[0]; - - bt_inquire_setup_information(sc); + for (i = 0; i < BT_MBX_SIZE; i++) { + wmbx->mbo[i].cmd = BT_MBO_FREE; + wmbx->mbi[i].stat = BT_MBI_FREE; + } + wmbx->cmbo = wmbx->tmbo = &wmbx->mbo[0]; + wmbx->tmbi = &wmbx->mbi[0]; + sc->sc_mbofull = 0; + + /* Initialize mail box. */ + mailbox.cmd.opcode = BT_MBX_INIT_EXTENDED; + mailbox.cmd.nmbx = BT_MBX_SIZE; + ltophys(KVTOPHYS(wmbx), mailbox.cmd.addr); + bt_cmd(iobase, sc, sizeof(mailbox.cmd), (u_char *)&mailbox.cmd, + 0, (u_char *)0); } void @@ -1155,72 +1019,61 @@ bt_inquire_setup_information(sc) struct bt_softc *sc; { int iobase = sc->sc_iobase; - struct bt_boardID bID; - struct bt_board_info binfo; - char dummy[8], sub_ver[3]; - struct bt_setup setup; - int i, ver; + struct bt_model model; + struct bt_revision revision; + struct bt_digit digit; + char dummy[8]; + char *p; /* - * Get and print board hardware information. + * Get the firmware revision. */ - bt_cmd(iobase, sc, 1, sizeof(binfo), 0, (u_char *)&binfo, - BT_GET_BOARD_INFO, sizeof(binfo)); - printf(": Bt%c%c%c", binfo.id[0], binfo.id[1], binfo.id[2]); - if (binfo.id[3] != ' ') - printf("%c", binfo.id[3]); - if (binfo.version[0] != ' ') - printf("%c%s", binfo.version[0], binfo.version[1]); - printf("\n"); - - /* - * Inquire Board ID to Bt742 for board type and firmware version. - */ - bt_cmd(iobase, sc, 0, sizeof(bID), 0, (u_char *)&bID, BT_INQUIRE); - ver = (bID.firm_revision - '0') * 10 + (bID.firm_version - '0'); + p = sc->sc_firmware; + revision.cmd.opcode = BT_INQUIRE_REVISION; + bt_cmd(iobase, sc, sizeof(revision.cmd), (u_char *)&revision.cmd, + sizeof(revision.reply), (u_char *)&revision.reply); + *p++ = revision.reply.firm_revision; + *p++ = '.'; + *p++ = revision.reply.firm_version; + digit.cmd.opcode = BT_INQUIRE_REVISION_3; + bt_cmd(iobase, sc, sizeof(digit.cmd), (u_char *)&digit.cmd, + sizeof(digit.reply), (u_char *)&digit.reply); + *p++ = digit.reply.digit; + if (revision.reply.firm_revision >= '3' || + (revision.reply.firm_revision == '3' && revision.reply.firm_version >= '3')) { + digit.cmd.opcode = BT_INQUIRE_REVISION_4; + bt_cmd(iobase, sc, sizeof(digit.cmd), (u_char *)&digit.cmd, + sizeof(digit.reply), (u_char *)&digit.reply); + *p++ = digit.reply.digit; + } + while (p > sc->sc_firmware && (p[-1] == ' ' || p[-1] == '\0')) + p--; + *p = '\0'; /* - * Get the rest of the firmware version. Firmware revisions - * before 3.3 apparently don't accept the BT_INQUIRE_REV_FOURTH - * command. + * Get the model number. */ - i = 0; - bt_cmd(iobase, sc, 0, 1, 0, &sub_ver[i++], BT_INQUIRE_REV_THIRD); - if (ver >= 33) - bt_cmd(iobase, sc, 0, 1, 0, &sub_ver[i++], - BT_INQUIRE_REV_FOURTH); - if (sub_ver[i - 1] == ' ') - i--; - sub_ver[i] = '\0'; - - printf("%s: firmware version %c.%c%s, ", sc->sc_dev.dv_xname, - bID.firm_revision, bID.firm_version, sub_ver); - - /* Enable round-robin scheme - appeared at firmware rev. 3.31 */ - if (ver > 33 || (ver == 33 && sub_ver[0] >= 1)) { - bt_cmd(iobase, sc, 1, 0, 0, 0, BT_ROUND_ROBIN, BT_ENABLE); - } - - /* Inquire Installed Devices (to force synchronous negotiation) */ - bt_cmd(iobase, sc, 0, sizeof(dummy), 10, dummy, BT_DEV_GET); - - /* Obtain setup information from Bt742. */ - bt_cmd(iobase, sc, 1, sizeof(setup), 0, (u_char *)&setup, BT_SETUP_GET, - sizeof(setup)); - - printf("%s, %s, %d mailboxes", - setup.sync_neg ? "sync" : "async", - setup.parity ? "parity" : "no parity", - setup.num_mbx); - - for (i = 0; i < 8; i++) { - if (!setup.sync[i].valid || - (!setup.sync[i].offset && !setup.sync[i].period)) - continue; - printf("\n%s targ %d: sync, offset %d, period %dnsec", - sc->sc_dev.dv_xname, i, - setup.sync[i].offset, setup.sync[i].period * 50 + 200); - } + if (revision.reply.firm_revision >= '3') { + p = sc->sc_model; + model.cmd.opcode = BT_INQUIRE_MODEL; + model.cmd.len = sizeof(model.reply); + bt_cmd(iobase, sc, sizeof(model.cmd), (u_char *)&model.cmd, + sizeof(model.reply), (u_char *)&model.reply); + *p++ = model.reply.id[0]; + *p++ = model.reply.id[1]; + *p++ = model.reply.id[2]; + *p++ = model.reply.id[3]; + while (p > sc->sc_model && (p[-1] == ' ' || p[-1] == '\0')) + p--; + *p++ = model.reply.version[0]; + *p++ = model.reply.version[1]; + while (p > sc->sc_model && (p[-1] == ' ' || p[-1] == '\0')) + p--; + *p = '\0'; + } else + strcpy(sc->sc_model, "542B"); + + printf(": model BT-%s, firmware %s\n", sc->sc_model, sc->sc_firmware); } void @@ -1246,11 +1099,9 @@ bt_scsi_cmd(xs) struct bt_ccb *ccb; struct bt_scat_gath *sg; int seg; /* scatter gather seg being worked on */ - int thiskv; - physaddr thisphys, nextphys; + u_long thiskv, thisphys, nextphys; int bytes_this_seg, bytes_this_page, datalen, flags; struct iovec *iovp; - struct bt_mbx_out *mbo; int s; SC_DEBUG(sc_link, SDEV_DB2, ("bt_scsi_cmd\n")); @@ -1260,39 +1111,28 @@ bt_scsi_cmd(xs) * then we can't allow it to sleep */ 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 ((ccb = bt_get_ccb(sc, flags)) == NULL) { xs->error = XS_DRIVER_STUFFUP; return TRY_AGAIN_LATER; } ccb->xs = xs; + ccb->timeout = xs->timeout; /* * Put all the arguments for the xfer in the ccb */ if (flags & SCSI_RESET) { ccb->opcode = BT_RESET_CCB; + ccb->scsi_cmd_length = 0; } else { /* can't use S/G if zero length */ ccb->opcode = (xs->datalen ? BT_INIT_SCAT_GATH_CCB : BT_INITIATOR_CCB); + bcopy(xs->cmd, &ccb->scsi_cmd, + ccb->scsi_cmd_length = xs->cmdlen); } - ccb->data_out = 0; - ccb->data_in = 0; - ccb->target = sc_link->target; - ccb->lun = sc_link->lun; - ccb->scsi_cmd_length = xs->cmdlen; - ccb->sense_ptr = KVTOPHYS(&ccb->scsi_sense); - ccb->req_sense_length = sizeof(ccb->scsi_sense); - ccb->host_stat = 0x00; - ccb->target_stat = 0x00; - if (xs->datalen && (flags & SCSI_RESET) == 0) { - ccb->data_addr = KVTOPHYS(ccb->scat_gath); + if (xs->datalen) { sg = ccb->scat_gath; seg = 0; #ifdef TFS @@ -1301,8 +1141,8 @@ bt_scsi_cmd(xs) datalen = ((struct uio *)xs->data)->uio_iovcnt; xs->datalen = 0; while (datalen && seg < BT_NSEG) { - sg->seg_addr = (physaddr)iovp->iov_base; - sg->seg_len = iovp->iov_len; + ltophys(iovp->iov_base, sg->seg_addr); + ltophys(iovp->iov_len, sg->seg_len); xs->datalen += iovp->iov_len; SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)", iovp->iov_len, iovp->iov_base)); @@ -1315,19 +1155,20 @@ bt_scsi_cmd(xs) #endif /* TFS */ { /* - * Set up the scatter gather block + * 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; + thiskv = (int)xs->data; thisphys = KVTOPHYS(thiskv); while (datalen && seg < BT_NSEG) { bytes_this_seg = 0; /* put in the base address */ - sg->seg_addr = thisphys; + ltophys(thisphys, sg->seg_addr); SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys)); @@ -1358,13 +1199,12 @@ bt_scsi_cmd(xs) */ SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x)", bytes_this_seg)); - sg->seg_len = bytes_this_seg; + ltophys(bytes_this_seg, sg->seg_len); sg++; seg++; } } /* end of iov/kv decision */ - ccb->data_length = seg * sizeof(struct bt_scat_gath); SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); if (datalen) { /* @@ -1372,53 +1212,51 @@ bt_scsi_cmd(xs) */ printf("%s: bt_scsi_cmd, more than %d dma segs\n", sc->sc_dev.dv_xname, BT_NSEG); - xs->error = XS_DRIVER_STUFFUP; - bt_free_ccb(sc, ccb, flags); - return COMPLETE; + goto bad; } + ltophys(KVTOPHYS(ccb->scat_gath), ccb->data_addr); + ltophys(seg * sizeof(struct bt_scat_gath), ccb->data_length); } else { /* No data xfer, use non S/G values */ - ccb->data_addr = (physaddr)0; - ccb->data_length = 0; + ltophys(0, ccb->data_addr); + ltophys(0, ccb->data_length); } - ccb->link_id = 0; - ccb->link_addr = (physaddr)0; - /* - * Put the scsi command in the ccb and start it - */ - if ((flags & SCSI_RESET) == 0) - bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmd_length); + ccb->data_out = 0; + ccb->data_in = 0; + ccb->target = sc_link->target; + ccb->lun = sc_link->lun; + ltophys(KVTOPHYS(&ccb->scsi_sense), ccb->sense_ptr); + ccb->req_sense_length = sizeof(ccb->scsi_sense); + ccb->host_stat = 0x00; + ccb->target_stat = 0x00; + ccb->link_id = 0; + ltophys(0, ccb->link_addr); s = splbio(); - - if (bt_send_mbo(sc, BT_MBO_START, ccb) == NULL) { - splx(s); - xs->error = XS_DRIVER_STUFFUP; - bt_free_ccb(sc, ccb, flags); - return TRY_AGAIN_LATER; - } + bt_queue_ccb(sc, ccb); + splx(s); /* * Usually return SUCCESSFULLY QUEUED */ SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n")); - if ((flags & SCSI_POLL) == 0) { - timeout(bt_timeout, ccb, (xs->timeout * hz) / 1000); - splx(s); + if ((flags & SCSI_POLL) == 0) return SUCCESSFULLY_QUEUED; - } - - splx(s); /* * If we can't use interrupts, poll on completion */ - if (bt_poll(sc, xs, xs->timeout)) { + if (bt_poll(sc, xs, ccb->timeout)) { bt_timeout(ccb); - if (bt_poll(sc, xs, 2000)) + if (bt_poll(sc, xs, ccb->timeout)) bt_timeout(ccb); } return COMPLETE; + +bad: + xs->error = XS_DRIVER_STUFFUP; + bt_free_ccb(sc, ccb); + return COMPLETE; } /* @@ -1438,7 +1276,7 @@ bt_poll(sc, xs, count) * If we had interrupts enabled, would we * have got an interrupt? */ - if (inb(iobase + BT_INTR_PORT) & BT_ANY_INTR) + if (inb(iobase + BT_INTR_PORT) & BT_INTR_ANYINTR) btintr(sc); if (xs->flags & ITSDONE) return 0; @@ -1463,66 +1301,34 @@ bt_timeout(arg) s = splbio(); +#ifdef BTDIAG /* * If the ccb's mbx is not free, then the board has gone Far East? */ - if (bt_ccb_phys_kv(sc, ccb->mbx->ccb_addr) == ccb && - ccb->mbx->cmd != BT_MBO_FREE) { + bt_collect_mbo(sc); + if (ccb->flags & CCB_SENDING) { printf("%s: not taking commands!\n", sc->sc_dev.dv_xname); Debugger(); } +#endif /* * If it has been through before, then * a previous abort has failed, don't * try abort again */ - if (ccb->flags == CCB_ABORTED) { + if (ccb->flags & CCB_ABORT) { /* abort timed out */ printf(" AGAIN\n"); - ccb->xs->retries = 0; - bt_done(sc, ccb); + /* XXX Must reset! */ } else { /* abort the operation that has timed out */ printf("\n"); ccb->xs->error = XS_TIMEOUT; - ccb->flags = CCB_ABORTED; - bt_send_mbo(sc, BT_MBO_ABORT, ccb); - /* 2 secs for the abort */ - if ((xs->flags & SCSI_POLL) == 0) - timeout(bt_timeout, ccb, 2 * hz); + ccb->timeout = BT_ABORT_TIMEOUT; + ccb->flags |= CCB_ABORT; + bt_queue_ccb(sc, ccb); } splx(s); } - -#ifdef UTEST -void -bt_print_ccb(ccb) - struct bt_ccb *ccb; -{ - - printf("ccb:%x op:%x cmdlen:%d senlen:%d\n", - ccb, ccb->opcode, ccb->scsi_cmd_length, ccb->req_sense_length); - printf(" datlen:%d hstat:%x tstat:%x flags:%x\n", - ccb->data_length, ccb->host_stat, ccb->target_stat, ccb->flags); -} - -void -bt_print_active_ccbs(sc) - struct bt_softc *sc; -{ - struct bt_ccb *ccb; - int i = 0; - - while (i < CCB_HASH_SIZE) { - ccb = sc->sc_ccbhash[i]; - while (ccb) { - if (ccb->flags != CCB_FREE) - bt_print_ccb(ccb); - ccb = ccb->nexthash; - } - i++; - } -} -#endif /*UTEST */ diff --git a/sys/dev/isa/bt742a.c b/sys/dev/isa/bt742a.c deleted file mode 100644 index 13798720e74..00000000000 --- a/sys/dev/isa/bt742a.c +++ /dev/null @@ -1,1528 +0,0 @@ -/* $OpenBSD: bt742a.c,v 1.7 1996/04/18 23:47:31 niklas Exp $ */ -/* $NetBSD: bt742a.c,v 1.55 1996/03/16 05:33:28 cgd Exp $ */ - -/* - * Copyright (c) 1994 Charles Hannum. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Charles 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Originally written by Julian Elischer (julian@tfs.com) - * for TRW Financial Systems for use under the MACH(2.5) operating system. - * - * TRW Financial Systems, in accordance with their agreement with Carnegie - * Mellon University, makes this software available to CMU to distribute - * or use in any manner that they see fit as long as this message is kept with - * the software. For this reason TFS also grants any other persons or - * organisations permission to use or modify this software. - * - * TFS supplies this software to be publicly redistributed - * on the understanding that TFS is not responsible for the correct - * functioning of this software in any circumstances. - */ - -/* - * bt742a SCSI driver - */ - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/errno.h> -#include <sys/ioctl.h> -#include <sys/device.h> -#include <sys/malloc.h> -#include <sys/buf.h> -#include <sys/proc.h> -#include <sys/user.h> - -#include <machine/pio.h> - -#include <dev/isa/isavar.h> -#include <dev/isa/isadmavar.h> -#include <scsi/scsi_all.h> -#include <scsi/scsiconf.h> - -/* - * Note that stdarg.h and the ANSI style va_start macro is used for both - * ANSI and traditional C compilers. - */ -#include <machine/stdarg.h> - -#ifndef DDB -#define Debugger() panic("should call debugger here (bt742a.c)") -#endif /* ! DDB */ - -typedef u_long physaddr; -typedef u_long physlen; - -/* - * I/O Port Interface - */ -#define BT_CTRL_STAT_PORT 0x0 /* control & status */ -#define BT_CMD_DATA_PORT 0x1 /* cmds and datas */ -#define BT_INTR_PORT 0x2 /* Intr. stat */ - -/* - * BT_CTRL_STAT bits (write) - */ -#define BT_HRST 0x80 /* Hardware reset */ -#define BT_SRST 0x40 /* Software reset */ -#define BT_IRST 0x20 /* Interrupt reset */ -#define BT_SCRST 0x10 /* SCSI bus reset */ - -/* - * BT_CTRL_STAT bits (read) - */ -#define BT_STST 0x80 /* Self test in Progress */ -#define BT_DIAGF 0x40 /* Diagnostic Failure */ -#define BT_INIT 0x20 /* Mbx Init required */ -#define BT_IDLE 0x10 /* Host Adapter Idle */ -#define BT_CDF 0x08 /* cmd/data out port full */ -#define BT_DF 0x04 /* Data in port full */ -#define BT_INVDCMD 0x01 /* Invalid command */ - -/* - * BT_CMD_DATA bits (write) - */ -#define BT_NOP 0x00 /* No operation */ -#define BT_MBX_INIT 0x01 /* Mbx initialization */ -#define BT_START_SCSI 0x02 /* start scsi command */ -#define BT_START_BIOS 0x03 /* start bios command */ -#define BT_INQUIRE 0x04 /* Adapter Inquiry */ -#define BT_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */ -#define BT_SEL_TIMEOUT_SET 0x06 /* set selection time-out */ -#define BT_BUS_ON_TIME_SET 0x07 /* set bus-on time */ -#define BT_BUS_OFF_TIME_SET 0x08 /* set bus-off time */ -#define BT_SPEED_SET 0x09 /* set transfer speed */ -#define BT_DEV_GET 0x0a /* return installed devices */ -#define BT_CONF_GET 0x0b /* return configuration data */ -#define BT_TARGET_EN 0x0c /* enable target mode */ -#define BT_SETUP_GET 0x0d /* return setup data */ -#define BT_WRITE_CH2 0x1a /* write channel 2 buffer */ -#define BT_READ_CH2 0x1b /* read channel 2 buffer */ -#define BT_WRITE_FIFO 0x1c /* write fifo buffer */ -#define BT_READ_FIFO 0x1d /* read fifo buffer */ -#define BT_ECHO 0x1e /* Echo command data */ -#define BT_MBX_INIT_EXTENDED 0x81 /* Mbx initialization */ -#define BT_INQUIRE_REV_THIRD 0x84 /* Get 3rd firmware version byte */ -#define BT_INQUIRE_REV_FOURTH 0x85 /* Get 4th firmware version byte */ -#define BT_GET_BOARD_INFO 0x8b /* Get hardware ID and revision */ -#define BT_INQUIRE_EXTENDED 0x8d /* Adapter Setup Inquiry */ - -/* Follows command appeared at firmware 3.31 */ -#define BT_ROUND_ROBIN 0x8f /* Enable/Disable(default) round robin */ -#define BT_DISABLE 0x00 /* Parameter value for Disable */ -#define BT_ENABLE 0x01 /* Parameter value for Enable */ - -/* - * BT_INTR_PORT bits (read) - */ -#define BT_ANY_INTR 0x80 /* Any interrupt */ -#define BT_SCRD 0x08 /* SCSI reset detected */ -#define BT_HACC 0x04 /* Command complete */ -#define BT_MBOA 0x02 /* MBX out empty */ -#define BT_MBIF 0x01 /* MBX in full */ - -/* - * Mail box defs etc. - * these could be bigger but we need the bt_softc to fit on a single page.. - */ -#define BT_MBX_SIZE 32 /* mail box size (MAX 255 MBxs) */ - /* don't need that many really */ -#define BT_CCB_MAX 32 /* store up to 32 CCBs at one time */ -#define CCB_HASH_SIZE 32 /* hash table size for phystokv */ -#define CCB_HASH_SHIFT 9 -#define CCB_HASH(x) ((((long)(x))>>CCB_HASH_SHIFT) & (CCB_HASH_SIZE - 1)) - -#define bt_nextmbx(wmb, mbx, mbio) \ - if ((wmb) == &(mbx)->mbio[BT_MBX_SIZE - 1]) \ - (wmb) = &(mbx)->mbio[0]; \ - else \ - (wmb)++; - -struct bt_mbx_out { - physaddr ccb_addr; - u_char dummy[3]; - u_char cmd; -}; - -struct bt_mbx_in { - physaddr ccb_addr; - u_char btstat; - u_char sdstat; - u_char dummy; - u_char stat; -}; - -struct bt_mbx { - struct bt_mbx_out mbo[BT_MBX_SIZE]; - struct bt_mbx_in mbi[BT_MBX_SIZE]; - struct bt_mbx_out *tmbo; /* Target Mail Box out */ - struct bt_mbx_in *tmbi; /* Target Mail Box in */ -}; - -/* - * mbo.cmd values - */ -#define BT_MBO_FREE 0x0 /* MBO entry is free */ -#define BT_MBO_START 0x1 /* MBO activate entry */ -#define BT_MBO_ABORT 0x2 /* MBO abort entry */ - -/* - * mbi.stat values - */ -#define BT_MBI_FREE 0x0 /* MBI entry is free */ -#define BT_MBI_OK 0x1 /* completed without error */ -#define BT_MBI_ABORT 0x2 /* aborted ccb */ -#define BT_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */ -#define BT_MBI_ERROR 0x4 /* Completed with error */ - -#if defined(BIG_DMA) -WARNING...THIS WON'T WORK(won't fit on 1 page) -/* #define BT_NSEG 2048 /* Number of scatter gather segments - to much vm */ -#define BT_NSEG 128 -#else -#define BT_NSEG 33 -#endif /* BIG_DMA */ - -struct bt_scat_gath { - physlen seg_len; - physaddr seg_addr; -}; - -struct bt_ccb { - u_char opcode; - u_char:3, data_in:1, data_out:1,:3; - u_char scsi_cmd_length; - u_char req_sense_length; - /*------------------------------------longword boundary */ - physlen data_length; - /*------------------------------------longword boundary */ - physaddr data_addr; - /*------------------------------------longword boundary */ - u_char dummy1[2]; - u_char host_stat; - u_char target_stat; - /*------------------------------------longword boundary */ - u_char target; - u_char lun; - struct scsi_generic scsi_cmd; - u_char dummy2[1]; - u_char link_id; - /*------------------------------------longword boundary */ - physaddr link_addr; - /*------------------------------------longword boundary */ - physaddr sense_ptr; -/*-----end of HW fields-----------------------longword boundary */ - struct scsi_sense_data scsi_sense; - /*------------------------------------longword boundary */ - struct bt_scat_gath scat_gath[BT_NSEG]; - /*------------------------------------longword boundary */ - TAILQ_ENTRY(bt_ccb) chain; - struct bt_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 bt_mbx_out *mbx; /* pointer to mail box */ -}; - -/* - * opcode fields - */ -#define BT_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */ -#define BT_TARGET_CCB 0x01 /* SCSI Target CCB */ -#define BT_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather */ -#define BT_RESET_CCB 0x81 /* SCSI Bus reset */ - -/* - * bt_ccb.host_stat values - */ -#define BT_OK 0x00 /* cmd ok */ -#define BT_LINK_OK 0x0a /* Link cmd ok */ -#define BT_LINK_IT 0x0b /* Link cmd ok + int */ -#define BT_SEL_TIMEOUT 0x11 /* Selection time out */ -#define BT_OVER_UNDER 0x12 /* Data over/under run */ -#define BT_BUS_FREE 0x13 /* Bus dropped at unexpected time */ -#define BT_INV_BUS 0x14 /* Invalid bus phase/sequence */ -#define BT_BAD_MBO 0x15 /* Incorrect MBO cmd */ -#define BT_BAD_CCB 0x16 /* Incorrect ccb opcode */ -#define BT_BAD_LINK 0x17 /* Not same values of LUN for links */ -#define BT_INV_TARGET 0x18 /* Invalid target direction */ -#define BT_CCB_DUP 0x19 /* Duplicate CCB received */ -#define BT_INV_CCB 0x1a /* Invalid CCB or segment list */ -#define BT_ABORTED 42 /* pseudo value from driver */ - -struct bt_extended_inquire { - u_char bus_type; /* Type of bus connected to */ -#define BT_BUS_TYPE_24BIT 'A' /* ISA bus */ -#define BT_BUS_TYPE_32BIT 'E' /* EISA/VLB/PCI bus */ -#define BT_BUS_TYPE_MCA 'M' /* MicroChannel bus */ - u_char bios_address; /* Address of adapter BIOS */ - u_short max_segment; /* ? */ -}; - -struct bt_boardID { - u_char board_type; - u_char custom_feture; - char firm_revision; - u_char firm_version; -}; - -struct bt_board_info { - u_char id[4]; /* i.e bt742a -> '7','4','2','A' */ - u_char version[2]; /* i.e Board Revision 'H' -> 'H', 0x00 */ -}; - -struct bt_setup { - u_char sync_neg:1; - u_char parity:1; - u_char :6; - u_char speed; - u_char bus_on; - u_char bus_off; - u_char num_mbx; - u_char mbx[3]; /*XXX */ - /* doesn't make sense with 32bit addresses */ - struct { - u_char offset:4; - u_char period:3; - u_char valid:1; - } sync[8]; - u_char disc_sts; -}; - -struct bt_config { - u_char chan; - u_char intr; - u_char scsi_dev:3; - u_char :5; -}; - -#define INT9 0x01 -#define INT10 0x02 -#define INT11 0x04 -#define INT12 0x08 -#define INT14 0x20 -#define INT15 0x40 - -#define EISADMA 0x00 -#define CHAN0 0x01 -#define CHAN5 0x20 -#define CHAN6 0x40 -#define CHAN7 0x80 - -#define KVTOPHYS(x) vtophys(x) - -struct bt_softc { - struct device sc_dev; - struct isadev sc_id; - void *sc_ih; - - int sc_iobase; - int sc_irq, sc_drq; - - struct bt_mbx sc_mbx; /* all our mailboxes */ - struct bt_ccb *sc_ccbhash[CCB_HASH_SIZE]; - TAILQ_HEAD(, bt_ccb) sc_free_ccb; - int sc_numccbs; - int sc_scsi_dev; /* adapters scsi id */ - struct scsi_link sc_link; /* prototype for devs */ -}; - -/***********debug values *************/ -#define BT_SHOWCCBS 0x01 -#define BT_SHOWINTS 0x02 -#define BT_SHOWCMDS 0x04 -#define BT_SHOWMISC 0x08 -int bt_debug = 0; - -int bt_cmd __P((int, struct bt_softc *, int, int, int, u_char *, - unsigned, ...)); -int btintr __P((void *)); -void bt_free_ccb __P((struct bt_softc *, struct bt_ccb *, int)); -struct bt_ccb *bt_get_ccb __P((struct bt_softc *, int)); -struct bt_ccb *bt_ccb_phys_kv __P((struct bt_softc *, u_long)); -struct bt_mbx_out *bt_send_mbo __P((struct bt_softc *, int, struct bt_ccb *)); -void bt_done __P((struct bt_softc *, struct bt_ccb *)); -int bt_find __P((struct isa_attach_args *, struct bt_softc *)); -void bt_init __P((struct bt_softc *)); -void bt_inquire_setup_information __P((struct bt_softc *)); -void btminphys __P((struct buf *)); -int bt_scsi_cmd __P((struct scsi_xfer *)); -int bt_poll __P((struct bt_softc *, struct scsi_xfer *, int)); -void bt_timeout __P((void *arg)); -#ifdef UTEST -void bt_print_ccb __P((struct bt_ccb *)); -void bt_print_active_ccbs __P((struct bt_softc *)); -#endif - -struct scsi_adapter bt_switch = { - bt_scsi_cmd, - btminphys, - 0, - 0, -}; - -/* the below structure is so we have a default dev struct for out link struct */ -struct scsi_device bt_dev = { - NULL, /* Use default error handler */ - NULL, /* have a queue, served by this */ - NULL, /* have no async handler */ - NULL, /* Use default 'done' routine */ -}; - -int btprobe __P((struct device *, void *, void *)); -void btattach __P((struct device *, struct device *, void *)); -int btprint __P((void *, char *)); - -struct cfdriver btcd = { - NULL, "bt", btprobe, btattach, DV_DULL, sizeof(struct bt_softc) -}; - -#define BT_RESET_TIMEOUT 1000 - -/* - * bt_cmd(iobase, sc, icnt, ocnt, wait, retval, opcode, ... args ...) - * - * Activate Adapter command - * icnt: number of args (outbound bytes written after opcode) - * ocnt: number of expected returned bytes - * wait: number of seconds to wait for response - * retval: buffer where to place returned bytes - * opcode: opcode BT_NOP, BT_MBX_INIT, BT_START_SCSI ... - * args: variable number of parameters - * - * Performs an adapter command through the ports. Not to be confused with a - * scsi command, which is read in via the dma; one of the adapter commands - * tells it to read in a scsi command. - */ -int -#ifdef __STDC__ -bt_cmd(int iobase, struct bt_softc *sc, int icnt, int ocnt, int wait, - u_char *retval, unsigned opcode, ...) -#else -bt_cmd(iobase, sc, icnt, ocnt, wait, retval, opcode, va_alist) - int iobase; - struct bt_softc *sc; - int icnt, ocnt, wait; - u_char *retval; - unsigned opcode; - va_dcl -#endif -{ - va_list ap; - unsigned data; - const char *name; - u_char oc; - register i; - int sts; - - if (sc == NULL) - name = sc->sc_dev.dv_xname; - else - name = "(probe)"; - - /* - * multiply the wait argument by a big constant - * zero defaults to 1 - */ - if (wait) - wait *= 100000; - else - wait = 100000; - /* - * Wait for the adapter to go idle, unless it's one of - * the commands which don't need this - */ - if (opcode != BT_MBX_INIT && opcode != BT_START_SCSI) { - i = 100000; /* 1 sec? */ - while (--i) { - sts = inb(iobase + BT_CTRL_STAT_PORT); - if (sts & BT_IDLE) { - break; - } - delay(10); - } - if (!i) { - printf("%s: bt_cmd, host not idle(0x%x)\n", - name, sts); - return ENXIO; - } - } - /* - * Now that it is idle, if we expect output, preflush the - * queue feeding to us. - */ - if (ocnt) { - while ((inb(iobase + BT_CTRL_STAT_PORT)) & BT_DF) - inb(iobase + BT_CMD_DATA_PORT); - } - /* - * Output the command and the number of arguments given - * for each byte, first check the port is empty. - */ - va_start(ap, opcode); - /* test icnt >= 0, to include the command in data sent */ - for (data = opcode; icnt >= 0; icnt--, data = va_arg(ap, u_char)) { - sts = inb(iobase + BT_CTRL_STAT_PORT); - for (i = wait; i; i--) { - sts = inb(iobase + BT_CTRL_STAT_PORT); - if (!(sts & BT_CDF)) - break; - delay(10); - } - if (!i) { - printf("%s: bt_cmd, cmd/data port full\n", name); - outb(iobase + BT_CTRL_STAT_PORT, BT_SRST); - va_end(ap); - return ENXIO; - } - outb(iobase + BT_CMD_DATA_PORT, data); - } - va_end(ap); - /* - * If we expect input, loop that many times, each time, - * looking for the data register to have valid data - */ - while (ocnt--) { - sts = inb(iobase + BT_CTRL_STAT_PORT); - for (i = wait; i; i--) { - sts = inb(iobase + BT_CTRL_STAT_PORT); - if (sts & BT_DF) - break; - delay(10); - } - if (!i) { - printf("bt%d: bt_cmd, cmd/data port empty %d\n", - name, ocnt); - return ENXIO; - } - oc = inb(iobase + BT_CMD_DATA_PORT); - if (retval) - *retval++ = oc; - } - /* - * Wait for the board to report a finised instruction - */ - i = 100000; /* 1 sec? */ - while (--i) { - sts = inb(iobase + BT_INTR_PORT); - if (sts & BT_HACC) - break; - delay(10); - } - if (!i) { - printf("%s: bt_cmd, host not finished(0x%x)\n", - name, sts); - return ENXIO; - } - outb(iobase + BT_CTRL_STAT_PORT, BT_IRST); - return 0; -} - -/* - * Check if the device can be found at the port given - * and if so, set it up ready for further work - * as an argument, takes the isa_device structure from - * autoconf.c - */ -int -btprobe(parent, match, aux) - struct device *parent; - void *match, *aux; -{ - struct bt_softc *sc = match; - register struct isa_attach_args *ia = aux; - -#ifdef NEWCONFIG - if (ia->ia_iobase == IOBASEUNK) - return 0; -#endif - - /* - * Try initialise a unit at this location - * sets up dma and bus speed, loads sc->sc_irq - */ - if (bt_find(ia, NULL) != 0) - return 0; - - ia->ia_msize = 0; - ia->ia_iosize = 4; - /* IRQ and DRQ set by bt_find() */ - return 1; -} - -int -btprint(aux, name) - void *aux; - char *name; -{ - if (name != NULL) - printf("%s: scsibus ", name); - return UNCONF; -} - -/* - * Attach all the sub-devices we can find - */ -void -btattach(parent, self, aux) - struct device *parent, *self; - void *aux; -{ - struct isa_attach_args *ia = aux; - struct bt_softc *sc = (struct bt_softc *)self; - - if (bt_find(ia, sc) != 0) - panic("btattach: bt_find of %s failed", self->dv_xname); - sc->sc_iobase = ia->ia_iobase; - - if (sc->sc_drq != DRQUNK) - isa_dmacascade(sc->sc_drq); - - bt_init(sc); - TAILQ_INIT(&sc->sc_free_ccb); - - /* - * fill in the prototype scsi_link. - */ - sc->sc_link.adapter_softc = sc; - sc->sc_link.adapter_target = sc->sc_scsi_dev; - sc->sc_link.adapter = &bt_switch; - sc->sc_link.device = &bt_dev; - sc->sc_link.openings = 2; - - printf("\n"); - -#ifdef NEWCONFIG - isa_establish(&sc->sc_id, &sc->sc_dev); -#endif - sc->sc_ih = isa_intr_establish(sc->sc_irq, IST_EDGE, IPL_BIO, btintr, - sc, sc->sc_dev.dv_xname); - - /* - * ask the adapter what subunits are present - */ - config_found(self, &sc->sc_link, btprint); -} - -/* - * Catch an interrupt from the adaptor - */ -int -btintr(arg) - void *arg; -{ - struct bt_softc *sc = arg; - int iobase = sc->sc_iobase; - struct bt_mbx_in *wmbi; - struct bt_mbx *wmbx; - struct bt_ccb *ccb; - u_char stat; - int i; - int found = 0; - -#ifdef BTDEBUG - printf("%s: btintr ", sc->sc_dev.dv_xname); -#endif /* BTDEBUG */ - - /* - * First acknowlege the interrupt, Then if it's - * not telling about a completed operation - * just return. - */ - stat = inb(iobase + BT_INTR_PORT); - if ((stat & (BT_MBOA | BT_MBIF)) == 0) { - outb(iobase + BT_CTRL_STAT_PORT, BT_IRST); - return -1; /* XXX */ - } - - /* Mail box out empty? */ - if (stat & BT_MBOA) { - /* Disable MBO available interrupt. */ - outb(iobase + BT_CMD_DATA_PORT, BT_MBO_INTR_EN); - for (i = 100000; i; i--) { - if (!(inb(iobase + BT_CTRL_STAT_PORT) & BT_CDF)) - break; - delay(10); - } - if (!i) { - printf("%s: btintr, cmd/data port full\n", - sc->sc_dev.dv_xname); - outb(iobase + BT_CTRL_STAT_PORT, BT_SRST); - return 1; - } - outb(iobase + BT_CMD_DATA_PORT, 0x00); /* Disable */ - wakeup(&sc->sc_mbx); - } - - /* Mail box in full? */ - if ((stat & BT_MBIF) == 0) - return 1; - wmbx = &sc->sc_mbx; - wmbi = wmbx->tmbi; -AGAIN: - while (wmbi->stat != BT_MBI_FREE) { - ccb = bt_ccb_phys_kv(sc, wmbi->ccb_addr); - if (!ccb) { - wmbi->stat = BT_MBI_FREE; - printf("%s: BAD CCB ADDR!\n", sc->sc_dev.dv_xname); - continue; - } - found++; - switch (wmbi->stat) { - case BT_MBI_OK: - case BT_MBI_ERROR: - break; - - case BT_MBI_ABORT: - ccb->host_stat = BT_ABORTED; - break; - - case BT_MBI_UNKNOWN: - ccb = 0; - break; - - default: - panic("Impossible mbxi status"); - } -#ifdef BTDEBUG - if (bt_debug && ccb) { - u_char *cp = &ccb->scsi_cmd; - printf("op=%x %x %x %x %x %x\n", - cp[0], cp[1], cp[2], - cp[3], cp[4], cp[5]); - printf("stat %x for mbi addr = 0x%08x, ", - wmbi->stat, wmbi); - printf("ccb addr = 0x%x\n", ccb); - } -#endif /* BTDEBUG */ - wmbi->stat = BT_MBI_FREE; - if (ccb) { - untimeout(bt_timeout, ccb); - bt_done(sc, ccb); - } - bt_nextmbx(wmbi, wmbx, mbi); - } - if (!found) { - for (i = 0; i < BT_MBX_SIZE; i++) { - if (wmbi->stat != BT_MBI_FREE) { - found++; - break; - } - bt_nextmbx(wmbi, wmbx, mbi); - } - if (!found) { -#if 0 - printf("%s: mbi interrupt with no full mailboxes\n", - sc->sc_dev.dv_xname); -#endif - } else { - found = 0; - goto AGAIN; - } - } - wmbx->tmbi = wmbi; - outb(iobase + BT_CTRL_STAT_PORT, BT_IRST); - return 1; -} - -/* - * A ccb is put onto the free list. - */ -void -bt_free_ccb(sc, ccb, flags) - struct bt_softc *sc; - struct bt_ccb *ccb; - int flags; -{ - int s; - - s = splbio(); - - ccb->flags = CCB_FREE; - TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, chain); - - /* - * If there were none, wake anybody waiting for one to come free, - * starting with queued entries. - */ - if (ccb->chain.tqe_next == 0) - wakeup(&sc->sc_free_ccb); - - splx(s); -} - -static inline void -bt_init_ccb(sc, ccb) - struct bt_softc *sc; - struct bt_ccb *ccb; -{ - int hashnum; - - bzero(ccb, sizeof(struct bt_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; -} - -static inline void -bt_reset_ccb(sc, ccb) - struct bt_softc *sc; - struct bt_ccb *ccb; -{ - -} - -/* - * Get a free ccb - * - * If there are none, see if we can allocate a new one. If so, put it in - * the hash table too otherwise either return an error or sleep. - */ -struct bt_ccb * -bt_get_ccb(sc, flags) - struct bt_softc *sc; - int flags; -{ - struct bt_ccb *ccb; - int s; - - s = splbio(); - - /* - * If we can and have to, sleep waiting for one to come free - * but only if we can't allocate a new one. - */ - for (;;) { - ccb = sc->sc_free_ccb.tqh_first; - if (ccb) { - TAILQ_REMOVE(&sc->sc_free_ccb, ccb, chain); - break; - } - if (sc->sc_numccbs < BT_CCB_MAX) { - if (ccb = (struct bt_ccb *) malloc(sizeof(struct bt_ccb), - M_TEMP, M_NOWAIT)) { - bt_init_ccb(sc, ccb); - sc->sc_numccbs++; - } else { - printf("%s: can't malloc ccb\n", - sc->sc_dev.dv_xname); - goto out; - } - break; - } - if ((flags & SCSI_NOSLEEP) != 0) - goto out; - tsleep(&sc->sc_free_ccb, PRIBIO, "btccb", 0); - } - - bt_reset_ccb(sc, ccb); - ccb->flags = CCB_ACTIVE; - -out: - splx(s); - return ccb; -} - -/* - * given a physical address, find the ccb that - * it corresponds to: - */ -struct bt_ccb * -bt_ccb_phys_kv(sc, ccb_phys) - struct bt_softc *sc; - u_long ccb_phys; -{ - int hashnum = CCB_HASH(ccb_phys); - struct bt_ccb *ccb = sc->sc_ccbhash[hashnum]; - - while (ccb) { - if (ccb->hashkey == ccb_phys) - break; - ccb = ccb->nexthash; - } - return ccb; -} - -/* - * Get a mbo and send the ccb. - */ -struct bt_mbx_out * -bt_send_mbo(sc, cmd, ccb) - struct bt_softc *sc; - int cmd; - struct bt_ccb *ccb; -{ - int iobase = sc->sc_iobase; - struct bt_mbx_out *wmbo; /* Mail Box Out pointer */ - struct bt_mbx *wmbx; /* Mail Box pointer specified unit */ - int i; - - /* Get the target out mail box pointer and increment. */ - wmbx = &sc->sc_mbx; - wmbo = wmbx->tmbo; - bt_nextmbx(wmbx->tmbo, wmbx, mbo); - - /* - * Check the outmail box is free or not. - * Note: Under the normal operation, it shuld NOT happen to wait. - */ - while (wmbo->cmd != BT_MBO_FREE) { - /* Enable mbo available interrupt. */ - outb(iobase + BT_CMD_DATA_PORT, BT_MBO_INTR_EN); - for (i = 100000; i; i--) { - if (!(inb(iobase + BT_CTRL_STAT_PORT) & BT_CDF)) - break; - delay(10); - } - if (!i) { - printf("%s: bt_send_mbo, cmd/data port full\n", - sc->sc_dev.dv_xname); - outb(iobase + BT_CTRL_STAT_PORT, BT_SRST); - return NULL; - } - outb(iobase + BT_CMD_DATA_PORT, 0x01); /* Enable */ - tsleep(wmbx, PRIBIO, "btsnd", 0);/*XXX can't do this */ - } - - /* Link ccb to mbo. */ - wmbo->ccb_addr = KVTOPHYS(ccb); - ccb->mbx = wmbo; - wmbo->cmd = cmd; - - /* Send it! */ - outb(iobase + BT_CMD_DATA_PORT, BT_START_SCSI); - - return wmbo; -} - -/* - * We have a ccb which has been processed by the - * adaptor, now we look to see how the operation - * went. Wake up the owner if waiting - */ -void -bt_done(sc, ccb) - struct bt_softc *sc; - struct bt_ccb *ccb; -{ - struct scsi_sense_data *s1, *s2; - struct scsi_xfer *xs = ccb->xs; - - SC_DEBUG(xs->sc_link, SDEV_DB2, ("bt_done\n")); - /* - * Otherwise, put the results of the operation - * into the xfer and call whoever started it - */ - if ((xs->flags & INUSE) == 0) { - printf("%s: exiting but not in use!\n", sc->sc_dev.dv_xname); - Debugger(); - } - if (xs->error == XS_NOERROR) { - if (ccb->host_stat != BT_OK) { - switch (ccb->host_stat) { - case BT_ABORTED: - xs->error = XS_DRIVER_STUFFUP; - break; - case BT_SEL_TIMEOUT: /* No response */ - xs->error = XS_SELTIMEOUT; - break; - default: /* Other scsi protocol messes */ - printf("%s: host_stat %x\n", - sc->sc_dev.dv_xname, ccb->host_stat); - xs->error = XS_DRIVER_STUFFUP; - } - } else if (ccb->target_stat != SCSI_OK) { - switch (ccb->target_stat) { - case SCSI_CHECK: - s1 = &ccb->scsi_sense; - s2 = &xs->sense; - *s2 = *s1; - xs->error = XS_SENSE; - break; - case SCSI_BUSY: - xs->error = XS_BUSY; - break; - default: - printf("%s: target_stat %x\n", - sc->sc_dev.dv_xname, ccb->target_stat); - xs->error = XS_DRIVER_STUFFUP; - } - } else - xs->resid = 0; - } - xs->flags |= ITSDONE; - bt_free_ccb(sc, ccb, xs->flags); - scsi_done(xs); -} - -/* - * Find the board and find it's irq/drq - */ -int -bt_find(ia, sc) - struct isa_attach_args *ia; - struct bt_softc *sc; -{ - int iobase = ia->ia_iobase; - u_char ad[4]; - volatile int i, sts; - struct bt_extended_inquire info; - struct bt_config conf; - int irq, drq; - - /* - * reset board, If it doesn't respond, assume - * that it's not there.. good for the probe - */ - - outb(iobase + BT_CTRL_STAT_PORT, BT_HRST | BT_SRST); - - for (i = BT_RESET_TIMEOUT; i; i--) { - sts = inb(iobase + BT_CTRL_STAT_PORT); - if (sts == (BT_IDLE | BT_INIT)) - break; - delay(1000); - } - if (!i) { -#ifdef UTEST - printf("bt_find: No answer from bt742a board\n"); -#endif - return 1; - } - - /* - * Check that we actually know how to use this board. - */ - delay(1000); - bt_cmd(iobase, sc, 1, sizeof(info), 0, (u_char *)&info, - BT_INQUIRE_EXTENDED, sizeof(info)); - switch (info.bus_type) { - case BT_BUS_TYPE_24BIT: - /* XXXX How do we avoid conflicting with the aha1542 probe? */ - case BT_BUS_TYPE_32BIT: - break; - case BT_BUS_TYPE_MCA: - /* We don't grok MicroChannel (yet). */ - return 1; - default: - printf("bt_find: illegal bus type %c\n", info.bus_type); - return 1; - } - - /* - * Assume we have a board at this stage setup dma channel from - * jumpers and save int level - */ - delay(1000); - bt_cmd(iobase, sc, 0, sizeof(conf), 0, (u_char *)&conf, BT_CONF_GET); - switch (conf.chan) { - case EISADMA: - drq = DRQUNK; - break; - case CHAN0: - drq = 0; - break; - case CHAN5: - drq = 5; - break; - case CHAN6: - drq = 6; - break; - case CHAN7: - drq = 7; - break; - default: - printf("bt_find: illegal dma setting %x\n", conf.chan); - return 1; - } - - switch (conf.intr) { - case INT9: - irq = 9; - break; - case INT10: - irq = 10; - break; - case INT11: - irq = 11; - break; - case INT12: - irq = 12; - break; - case INT14: - irq = 14; - break; - case INT15: - irq = 15; - break; - default: - printf("bt_find: illegal int setting %x\n", conf.intr); - return 1; - } - - if (sc != NULL) { - /* who are we on the scsi bus? */ - sc->sc_scsi_dev = conf.scsi_dev; - - sc->sc_iobase = iobase; - sc->sc_irq = irq; - sc->sc_drq = drq; - } else { - if (ia->ia_irq == IRQUNK) - ia->ia_irq = irq; - else if (ia->ia_irq != irq) - return 1; - if (ia->ia_drq == DRQUNK) - ia->ia_drq = drq; - else if (ia->ia_drq != drq) - return 1; - } - - return 0; -} - -/* - * Start the board, ready for normal operation - */ -void -bt_init(sc) - struct bt_softc *sc; -{ - int iobase = sc->sc_iobase; - u_char ad[4]; - int i; - - /* - * Initialize mail box - */ - *((physaddr *)ad) = KVTOPHYS(&sc->sc_mbx); - - bt_cmd(iobase, sc, 5, 0, 0, 0, BT_MBX_INIT_EXTENDED, BT_MBX_SIZE, - ad[0], ad[1], ad[2], ad[3]); - - for (i = 0; i < BT_MBX_SIZE; i++) { - sc->sc_mbx.mbo[i].cmd = BT_MBO_FREE; - sc->sc_mbx.mbi[i].stat = BT_MBI_FREE; - } - - /* - * Set up initial mail box for round-robin operation. - */ - sc->sc_mbx.tmbo = &sc->sc_mbx.mbo[0]; - sc->sc_mbx.tmbi = &sc->sc_mbx.mbi[0]; - - bt_inquire_setup_information(sc); -} - -void -bt_inquire_setup_information(sc) - struct bt_softc *sc; -{ - int iobase = sc->sc_iobase; - struct bt_boardID bID; - struct bt_board_info binfo; - char dummy[8], sub_ver[3]; - struct bt_setup setup; - int i, ver; - - /* - * Get and print board hardware information. - */ - bt_cmd(iobase, sc, 1, sizeof(binfo), 0, (u_char *)&binfo, - BT_GET_BOARD_INFO, sizeof(binfo)); - printf(": Bt%c%c%c", binfo.id[0], binfo.id[1], binfo.id[2]); - if (binfo.id[3] != ' ') - printf("%c", binfo.id[3]); - if (binfo.version[0] != ' ') - printf("%c%s", binfo.version[0], binfo.version[1]); - printf("\n"); - - /* - * Inquire Board ID to Bt742 for board type and firmware version. - */ - bt_cmd(iobase, sc, 0, sizeof(bID), 0, (u_char *)&bID, BT_INQUIRE); - ver = (bID.firm_revision - '0') * 10 + (bID.firm_version - '0'); - - /* - * Get the rest of the firmware version. Firmware revisions - * before 3.3 apparently don't accept the BT_INQUIRE_REV_FOURTH - * command. - */ - i = 0; - bt_cmd(iobase, sc, 0, 1, 0, &sub_ver[i++], BT_INQUIRE_REV_THIRD); - if (ver >= 33) - bt_cmd(iobase, sc, 0, 1, 0, &sub_ver[i++], - BT_INQUIRE_REV_FOURTH); - if (sub_ver[i - 1] == ' ') - i--; - sub_ver[i] = '\0'; - - printf("%s: firmware version %c.%c%s, ", sc->sc_dev.dv_xname, - bID.firm_revision, bID.firm_version, sub_ver); - - /* Enable round-robin scheme - appeared at firmware rev. 3.31 */ - if (ver > 33 || (ver == 33 && sub_ver[0] >= 1)) { - bt_cmd(iobase, sc, 1, 0, 0, 0, BT_ROUND_ROBIN, BT_ENABLE); - } - - /* Inquire Installed Devices (to force synchronous negotiation) */ - bt_cmd(iobase, sc, 0, sizeof(dummy), 10, dummy, BT_DEV_GET); - - /* Obtain setup information from Bt742. */ - bt_cmd(iobase, sc, 1, sizeof(setup), 0, (u_char *)&setup, BT_SETUP_GET, - sizeof(setup)); - - printf("%s, %s, %d mailboxes", - setup.sync_neg ? "sync" : "async", - setup.parity ? "parity" : "no parity", - setup.num_mbx); - - for (i = 0; i < 8; i++) { - if (!setup.sync[i].valid || - (!setup.sync[i].offset && !setup.sync[i].period)) - continue; - printf("\n%s targ %d: sync, offset %d, period %dnsec", - sc->sc_dev.dv_xname, i, - setup.sync[i].offset, setup.sync[i].period * 50 + 200); - } -} - -void -btminphys(bp) - struct buf *bp; -{ - - if (bp->b_bcount > ((BT_NSEG - 1) << PGSHIFT)) - bp->b_bcount = ((BT_NSEG - 1) << PGSHIFT); - minphys(bp); -} - -/* - * start a scsi operation given the command and the data address. Also needs - * the unit, target and lu. - */ -int -bt_scsi_cmd(xs) - struct scsi_xfer *xs; -{ - struct scsi_link *sc_link = xs->sc_link; - struct bt_softc *sc = sc_link->adapter_softc; - struct bt_ccb *ccb; - struct bt_scat_gath *sg; - int seg; /* scatter gather seg being worked on */ - int thiskv; - physaddr thisphys, nextphys; - int bytes_this_seg, bytes_this_page, datalen, flags; - struct iovec *iovp; - struct bt_mbx_out *mbo; - int s; - - SC_DEBUG(sc_link, SDEV_DB2, ("bt_scsi_cmd\n")); - /* - * get a ccb to use. If the transfer - * is from a buf (possibly from interrupt time) - * then we can't allow it to sleep - */ - 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 ((ccb = bt_get_ccb(sc, flags)) == NULL) { - xs->error = XS_DRIVER_STUFFUP; - return TRY_AGAIN_LATER; - } - ccb->xs = xs; - - /* - * Put all the arguments for the xfer in the ccb - */ - if (flags & SCSI_RESET) { - ccb->opcode = BT_RESET_CCB; - } else { - /* can't use S/G if zero length */ - ccb->opcode = (xs->datalen ? BT_INIT_SCAT_GATH_CCB - : BT_INITIATOR_CCB); - } - ccb->data_out = 0; - ccb->data_in = 0; - ccb->target = sc_link->target; - ccb->lun = sc_link->lun; - ccb->scsi_cmd_length = xs->cmdlen; - ccb->sense_ptr = KVTOPHYS(&ccb->scsi_sense); - ccb->req_sense_length = sizeof(ccb->scsi_sense); - ccb->host_stat = 0x00; - ccb->target_stat = 0x00; - - if (xs->datalen && (flags & SCSI_RESET) == 0) { - ccb->data_addr = KVTOPHYS(ccb->scat_gath); - sg = ccb->scat_gath; - seg = 0; -#ifdef TFS - if (flags & SCSI_DATA_UIO) { - iovp = ((struct uio *)xs->data)->uio_iov; - datalen = ((struct uio *)xs->data)->uio_iovcnt; - xs->datalen = 0; - while (datalen && seg < BT_NSEG) { - sg->seg_addr = (physaddr)iovp->iov_base; - sg->seg_len = iovp->iov_len; - xs->datalen += iovp->iov_len; - SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)", - iovp->iov_len, iovp->iov_base)); - sg++; - iovp++; - seg++; - datalen--; - } - } else -#endif /* TFS */ - { - /* - * Set up the scatter gather block - */ - SC_DEBUG(sc_link, SDEV_DB4, - ("%d @0x%x:- ", xs->datalen, xs->data)); - datalen = xs->datalen; - thiskv = (int) xs->data; - thisphys = KVTOPHYS(thiskv); - - while (datalen && seg < BT_NSEG) { - bytes_this_seg = 0; - - /* put in the base address */ - sg->seg_addr = thisphys; - - SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys)); - - /* do it at least once */ - nextphys = thisphys; - while (datalen && thisphys == nextphys) { - /* - * This page is contiguous (physically) - * with the the last, just extend the - * length - */ - /* how far to the end of the page */ - nextphys = (thisphys & ~PGOFSET) + NBPG; - bytes_this_page = nextphys - thisphys; - /**** or the data ****/ - bytes_this_page = min(bytes_this_page, - datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; - - /* get more ready for the next page */ - thiskv = (thiskv & ~PGOFSET) + NBPG; - if (datalen) - thisphys = KVTOPHYS(thiskv); - } - /* - * next page isn't contiguous, finish the seg - */ - SC_DEBUGN(sc_link, SDEV_DB4, - ("(0x%x)", bytes_this_seg)); - sg->seg_len = bytes_this_seg; - sg++; - seg++; - } - } - /* end of iov/kv decision */ - ccb->data_length = seg * sizeof(struct bt_scat_gath); - SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); - if (datalen) { - /* - * there's still data, must have run out of segs! - */ - printf("%s: bt_scsi_cmd, more than %d dma segs\n", - sc->sc_dev.dv_xname, BT_NSEG); - xs->error = XS_DRIVER_STUFFUP; - bt_free_ccb(sc, ccb, flags); - return COMPLETE; - } - } else { /* No data xfer, use non S/G values */ - ccb->data_addr = (physaddr)0; - ccb->data_length = 0; - } - ccb->link_id = 0; - ccb->link_addr = (physaddr)0; - - /* - * Put the scsi command in the ccb and start it - */ - if ((flags & SCSI_RESET) == 0) - bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmd_length); - - s = splbio(); - - if (bt_send_mbo(sc, BT_MBO_START, ccb) == NULL) { - splx(s); - xs->error = XS_DRIVER_STUFFUP; - bt_free_ccb(sc, ccb, flags); - return TRY_AGAIN_LATER; - } - - /* - * Usually return SUCCESSFULLY QUEUED - */ - SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n")); - if ((flags & SCSI_POLL) == 0) { - timeout(bt_timeout, ccb, (xs->timeout * hz) / 1000); - splx(s); - return SUCCESSFULLY_QUEUED; - } - - splx(s); - - /* - * If we can't use interrupts, poll on completion - */ - if (bt_poll(sc, xs, xs->timeout)) { - bt_timeout(ccb); - if (bt_poll(sc, xs, 2000)) - bt_timeout(ccb); - } - return COMPLETE; -} - -/* - * Poll a particular unit, looking for a particular xs - */ -int -bt_poll(sc, xs, count) - struct bt_softc *sc; - struct scsi_xfer *xs; - int count; -{ - int iobase = sc->sc_iobase; - - /* timeouts are in msec, so we loop in 1000 usec cycles */ - while (count) { - /* - * If we had interrupts enabled, would we - * have got an interrupt? - */ - if (inb(iobase + BT_INTR_PORT) & BT_ANY_INTR) - btintr(sc); - if (xs->flags & ITSDONE) - return 0; - delay(1000); /* only happens in boot so ok */ - count--; - } - return 1; -} - -void -bt_timeout(arg) - void *arg; -{ - struct bt_ccb *ccb = arg; - struct scsi_xfer *xs = ccb->xs; - struct scsi_link *sc_link = xs->sc_link; - struct bt_softc *sc = sc_link->adapter_softc; - int s; - - sc_print_addr(sc_link); - printf("timed out"); - - s = splbio(); - - /* - * If the ccb's mbx is not free, then the board has gone Far East? - */ - if (bt_ccb_phys_kv(sc, ccb->mbx->ccb_addr) == ccb && - ccb->mbx->cmd != BT_MBO_FREE) { - printf("%s: not taking commands!\n", sc->sc_dev.dv_xname); - Debugger(); - } - - /* - * If it has been through before, then - * a previous abort has failed, don't - * try abort again - */ - if (ccb->flags == CCB_ABORTED) { - /* abort timed out */ - printf(" AGAIN\n"); - ccb->xs->retries = 0; - bt_done(sc, ccb); - } else { - /* abort the operation that has timed out */ - printf("\n"); - ccb->xs->error = XS_TIMEOUT; - ccb->flags = CCB_ABORTED; - bt_send_mbo(sc, BT_MBO_ABORT, ccb); - /* 2 secs for the abort */ - if ((xs->flags & SCSI_POLL) == 0) - timeout(bt_timeout, ccb, 2 * hz); - } - - splx(s); -} - -#ifdef UTEST -void -bt_print_ccb(ccb) - struct bt_ccb *ccb; -{ - - printf("ccb:%x op:%x cmdlen:%d senlen:%d\n", - ccb, ccb->opcode, ccb->scsi_cmd_length, ccb->req_sense_length); - printf(" datlen:%d hstat:%x tstat:%x flags:%x\n", - ccb->data_length, ccb->host_stat, ccb->target_stat, ccb->flags); -} - -void -bt_print_active_ccbs(sc) - struct bt_softc *sc; -{ - struct bt_ccb *ccb; - int i = 0; - - while (i < CCB_HASH_SIZE) { - ccb = sc->sc_ccbhash[i]; - while (ccb) { - if (ccb->flags != CCB_FREE) - bt_print_ccb(ccb); - ccb = ccb->nexthash; - } - i++; - } -} -#endif /*UTEST */ diff --git a/sys/dev/isa/btreg.h b/sys/dev/isa/btreg.h new file mode 100644 index 00000000000..886911afa7f --- /dev/null +++ b/sys/dev/isa/btreg.h @@ -0,0 +1,304 @@ +typedef u_int8_t physaddr[4]; +typedef u_int8_t physlen[4]; +#define ltophys _lto4l +#define phystol _4ltol + +/* + * I/O port offsets + */ +#define BT_CTRL_PORT 0 /* control (wo) */ +#define BT_STAT_PORT 0 /* status (ro) */ +#define BT_CMD_PORT 1 /* command (wo) */ +#define BT_DATA_PORT 1 /* data (ro) */ +#define BT_INTR_PORT 2 /* interrupt status (ro) */ + +/* + * BT_CTRL bits + */ +#define BT_CTRL_HRST 0x80 /* Hardware reset */ +#define BT_CTRL_SRST 0x40 /* Software reset */ +#define BT_CTRL_IRST 0x20 /* Interrupt reset */ +#define BT_CTRL_SCRST 0x10 /* SCSI bus reset */ + +/* + * BT_STAT bits + */ +#define BT_STAT_STST 0x80 /* Self test in Progress */ +#define BT_STAT_DIAGF 0x40 /* Diagnostic Failure */ +#define BT_STAT_INIT 0x20 /* Mbx Init required */ +#define BT_STAT_IDLE 0x10 /* Host Adapter Idle */ +#define BT_STAT_CDF 0x08 /* cmd/data out port full */ +#define BT_STAT_DF 0x04 /* Data in port full */ +#define BT_STAT_INVDCMD 0x01 /* Invalid command */ + +/* + * BT_CMD opcodes + */ +#define BT_NOP 0x00 /* No operation */ +#define BT_MBX_INIT 0x01 /* Mbx initialization */ +#define BT_START_SCSI 0x02 /* start scsi command */ +#define BT_INQUIRE_REVISION 0x04 /* Adapter Inquiry */ +#define BT_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */ +/*#define BT_SEL_TIMEOUT_SET 0x06 /* set selection time-out */ +/*#define BT_BUS_ON_TIME_SET 0x07 /* set bus-on time */ +/*#define BT_BUS_OFF_TIME_SET 0x08 /* set bus-off time */ +/*#define BT_SPEED_SET 0x09 /* set transfer speed */ +#define BT_INQUIRE_DEVICES 0x0a /* return installed devices 0-7 */ +#define BT_INQUIRE_CONFIG 0x0b /* return configuration data */ +#define BT_TARGET_EN 0x0c /* enable target mode */ +#define BT_INQUIRE_SETUP 0x0d /* return setup data */ +#define BT_ECHO 0x1e /* Echo command data */ +#define BT_INQUIRE_DEVICES_2 0x23 /* return installed devices 8-15 */ +#define BT_MBX_INIT_EXTENDED 0x81 /* Mbx initialization */ +#define BT_INQUIRE_REVISION_3 0x84 /* Get 3rd firmware version byte */ +#define BT_INQUIRE_REVISION_4 0x85 /* Get 4th firmware version byte */ +#define BT_INQUIRE_MODEL 0x8b /* Get hardware ID and revision */ +#define BT_INQUIRE_PERIOD 0x8c /* Get synchronous period */ +#define BT_INQUIRE_EXTENDED 0x8d /* Adapter Setup Inquiry */ +#define BT_ROUND_ROBIN 0x8f /* Enable/Disable(default) round robin */ + +/* + * BT_INTR bits + */ +#define BT_INTR_ANYINTR 0x80 /* Any interrupt */ +#define BT_INTR_SCRD 0x08 /* SCSI reset detected */ +#define BT_INTR_HACC 0x04 /* Command complete */ +#define BT_INTR_MBOA 0x02 /* MBX out empty */ +#define BT_INTR_MBIF 0x01 /* MBX in full */ + +struct bt_mbx_out { + physaddr ccb_addr; + u_char dummy[3]; + u_char cmd; +}; + +struct bt_mbx_in { + physaddr ccb_addr; + u_char dummy[3]; + u_char stat; +}; + +/* + * mbo.cmd values + */ +#define BT_MBO_FREE 0x0 /* MBO entry is free */ +#define BT_MBO_START 0x1 /* MBO activate entry */ +#define BT_MBO_ABORT 0x2 /* MBO abort entry */ + +/* + * mbi.stat values + */ +#define BT_MBI_FREE 0x0 /* MBI entry is free */ +#define BT_MBI_OK 0x1 /* completed without error */ +#define BT_MBI_ABORT 0x2 /* aborted ccb */ +#define BT_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */ +#define BT_MBI_ERROR 0x4 /* Completed with error */ + +#if defined(BIG_DMA) +WARNING...THIS WON'T WORK(won't fit on 1 page) +/* #define BT_NSEG 2048 /* Number of scatter gather segments - to much vm */ +#define BT_NSEG 128 +#else +#define BT_NSEG 33 +#endif /* BIG_DMA */ + +struct bt_scat_gath { + physlen seg_len; + physaddr seg_addr; +}; + +struct bt_ccb { + u_char opcode; + u_char:3, data_in:1, data_out:1,:3; + u_char scsi_cmd_length; + u_char req_sense_length; + /*------------------------------------longword boundary */ + physlen data_length; + /*------------------------------------longword boundary */ + physaddr data_addr; + /*------------------------------------longword boundary */ + u_char dummy1[2]; + u_char host_stat; + u_char target_stat; + /*------------------------------------longword boundary */ + u_char target; + u_char lun; + struct scsi_generic scsi_cmd; + u_char dummy2[1]; + u_char link_id; + /*------------------------------------longword boundary */ + physaddr link_addr; + /*------------------------------------longword boundary */ + physaddr sense_ptr; +/*-----end of HW fields-----------------------longword boundary */ + struct scsi_sense_data scsi_sense; + /*------------------------------------longword boundary */ + struct bt_scat_gath scat_gath[BT_NSEG]; + /*------------------------------------longword boundary */ + TAILQ_ENTRY(bt_ccb) chain; + struct bt_ccb *nexthash; + long hashkey; + struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ + int flags; +#define CCB_ALLOC 0x01 +#define CCB_ABORT 0x02 +#ifdef BTDIAG +#define CCB_SENDING 0x04 +#endif + int timeout; +}; + +/* + * opcode fields + */ +#define BT_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */ +#define BT_TARGET_CCB 0x01 /* SCSI Target CCB */ +#define BT_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather */ +#define BT_RESET_CCB 0x81 /* SCSI Bus reset */ + +/* + * bt_ccb.host_stat values + */ +#define BT_OK 0x00 /* cmd ok */ +#define BT_LINK_OK 0x0a /* Link cmd ok */ +#define BT_LINK_IT 0x0b /* Link cmd ok + int */ +#define BT_SEL_TIMEOUT 0x11 /* Selection time out */ +#define BT_OVER_UNDER 0x12 /* Data over/under run */ +#define BT_BUS_FREE 0x13 /* Bus dropped at unexpected time */ +#define BT_INV_BUS 0x14 /* Invalid bus phase/sequence */ +#define BT_BAD_MBO 0x15 /* Incorrect MBO cmd */ +#define BT_BAD_CCB 0x16 /* Incorrect ccb opcode */ +#define BT_BAD_LINK 0x17 /* Not same values of LUN for links */ +#define BT_INV_TARGET 0x18 /* Invalid target direction */ +#define BT_CCB_DUP 0x19 /* Duplicate CCB received */ +#define BT_INV_CCB 0x1a /* Invalid CCB or segment list */ + +struct bt_extended_inquire { + struct { + u_char opcode; + u_char len; + } cmd; + struct { + u_char bus_type; /* Type of bus connected to */ +#define BT_BUS_TYPE_24BIT 'A' /* ISA bus */ +#define BT_BUS_TYPE_32BIT 'E' /* EISA/VLB/PCI bus */ +#define BT_BUS_TYPE_MCA 'M' /* MicroChannel bus */ + u_char bios_address; /* Address of adapter BIOS */ + u_short max_segment; /* ? */ + } reply; +}; + +struct bt_config { + struct { + u_char opcode; + } cmd; + struct { + u_char chan; + u_char intr; + u_char scsi_dev:3; + u_char :5; + } reply; +}; + +struct bt_toggle { + struct { + u_char opcode; + u_char enable; + } cmd; +}; + +struct bt_mailbox { + struct { + u_char opcode; + u_char nmbx; + physaddr addr; + } cmd; +}; + +struct bt_model { + struct { + u_char opcode; + u_char len; + } cmd; + struct { + u_char id[4]; /* i.e bt742a -> '7','4','2','A' */ + u_char version[2]; /* i.e Board Revision 'H' -> 'H', 0x00 */ + } reply; +}; + +struct bt_revision { + struct { + u_char opcode; + } cmd; + struct { + u_char board_type; + u_char custom_feature; + char firm_revision; + u_char firm_version; + } reply; +}; + +struct bt_digit { + struct { + u_char opcode; + } cmd; + struct { + u_char digit; + } reply; +}; + +struct bt_devices { + struct { + u_char opcode; + } cmd; + struct { + u_char junk[8]; + } reply; +}; + +struct bt_setup { + struct { + u_char opcode; + u_char len; + } cmd; + struct { + u_char sync_neg:1; + u_char parity:1; + u_char :6; + u_char speed; + u_char bus_on; + u_char bus_off; + u_char num_mbx; + u_char mbx[3]; /*XXX */ + /* doesn't make sense with 32bit addresses */ + struct { + u_char offset:4; + u_char period:3; + u_char valid:1; + } sync[8]; + u_char disc_sts; + } reply; +}; + +struct bt_period { + struct { + u_char opcode; + u_char len; + } cmd; + struct { + u_char period[8]; + } reply; +}; + +#define INT9 0x01 +#define INT10 0x02 +#define INT11 0x04 +#define INT12 0x08 +#define INT14 0x20 +#define INT15 0x40 + +#define EISADMA 0x00 +#define CHAN0 0x01 +#define CHAN5 0x20 +#define CHAN6 0x40 +#define CHAN7 0x80 diff --git a/sys/dev/isa/com.c b/sys/dev/isa/com.c index d34ba82a096..77dd24748f4 100644 --- a/sys/dev/isa/com.c +++ b/sys/dev/isa/com.c @@ -1,5 +1,5 @@ -/* $OpenBSD: com.c,v 1.10 1996/04/18 23:47:32 niklas Exp $ */ -/* $NetBSD: com.c,v 1.75 1996/03/10 09:01:24 cgd Exp $ */ +/* $OpenBSD: com.c,v 1.11 1996/04/21 22:23:15 deraadt Exp $ */ +/* $NetBSD: com.c,v 1.79 1996/04/15 18:54:31 cgd Exp $ */ /*- * Copyright (c) 1993, 1994, 1995, 1996 @@ -57,7 +57,11 @@ #include <sys/types.h> #include <sys/device.h> -#include <machine/cpu.h> +#ifdef i386 /* XXX */ +#include <machine/cpu.h> /* XXX */ +#else /* XXX */ +#include <machine/intr.h> +#endif /* XXX */ #include <machine/bus.h> #include <dev/isa/isavar.h> @@ -69,6 +73,8 @@ #endif #define com_lcr com_cfcr +#include "com.h" + #define COM_IBUFSIZE (2 * 512) #define COM_IHIGHWATER ((3 * COM_IBUFSIZE) / 4) @@ -109,11 +115,9 @@ struct com_softc { u_char sc_ibufs[2][COM_IBUFSIZE]; }; -int comprobe __P((struct device *, void *, void *)); #ifdef COM_HAYESP int comprobeHAYESP __P((bus_io_handle_t hayespioh, struct com_softc *sc)); #endif -void comattach __P((struct device *, struct device *, void *)); int comopen __P((dev_t, int, int, struct proc *)); int comclose __P((dev_t, int, int, struct proc *)); void comdiag __P((void *)); @@ -122,11 +126,30 @@ void compoll __P((void *)); int comparam __P((struct tty *, struct termios *)); void comstart __P((struct tty *)); -int cominit __P((bus_chipset_tag_t, bus_io_handle_t, int)); +/* + * XXX the following two cfattach structs should be different, and possibly + * XXX elsewhere. + */ +int comprobe __P((struct device *, void *, void *)); +void comattach __P((struct device *, struct device *, void *)); + +#if NCOM_ISA +struct cfattach com_isa_ca = { + sizeof(struct com_softc), comprobe, comattach +}; +#endif -struct cfdriver comcd = { - NULL, "com", comprobe, comattach, DV_TTY, sizeof(struct com_softc) +#if NCOM_COMMULTI +struct cfattach com_commulti_ca = { + sizeof(struct com_softc), comprobe, comattach }; +#endif + +struct cfdriver com_cd = { + NULL, "com", DV_TTY +}; + +int cominit __P((bus_chipset_tag_t, bus_io_handle_t, int)); #ifdef COMCONSOLE int comdefaultrate = CONSPEED; /* XXX why set default? */ @@ -138,6 +161,7 @@ int comconsinit; int comconsattached; bus_chipset_tag_t comconsbc; bus_io_handle_t comconsioh; +tcflag_t comconscflag = TTYDEF_CFLAG; int commajor; int comsopen = 0; @@ -157,7 +181,7 @@ extern int kgdb_debug_init; #define CLR(t, f) (t) &= ~(f) #define ISSET(t, f) ((t) & (f)) -#include "pcmciabus.h" +/*#include "pcmciabus.h"*/ #if NPCMCIABUS >0 /* additional setup needed for pcmcia devices */ #include <dev/pcmcia/pcmciabus.h> @@ -327,13 +351,22 @@ comprobe(parent, match, aux) int iobase, needioh; int rv = 1; + /* + * XXX should be broken out into functions for isa probe and + * XXX for commulti probe, with a helper function that contains + * XXX most of the interesting stuff. + */ +#if NCOM_ISA if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) { struct isa_attach_args *ia = aux; bc = ia->ia_bc; iobase = ia->ia_iobase; needioh = 1; - } else { + } else +#endif +#if NCOM_COMMULTI + if (1) { struct commulti_attach_args *ca = aux; if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != ca->ca_slave) @@ -343,7 +376,9 @@ comprobe(parent, match, aux) iobase = ca->ca_iobase; ioh = ca->ca_ioh; needioh = 0; - } + } else +#endif + return(0); /* This cannot happen */ /* if it's in use as console, it's there. */ if (iobase == comconsaddr && !comconsattached) @@ -358,12 +393,14 @@ comprobe(parent, match, aux) bus_io_unmap(bc, ioh, COM_NPORTS); out: +#if NCOM_ISA if (rv && !strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) { struct isa_attach_args *ia = aux; ia->ia_iosize = COM_NPORTS; ia->ia_msize = 0; } +#endif return (rv); } @@ -383,8 +420,14 @@ comattach(parent, self, aux) int *hayespp; #endif + /* + * XXX should be broken out into functions for isa attach and + * XXX for commulti attach, with a helper function that contains + * XXX most of the interesting stuff. + */ sc->sc_hwflags = 0; sc->sc_swflags = 0; +#if NCOM_ISA if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) { struct isa_attach_args *ia = aux; @@ -399,7 +442,10 @@ comattach(parent, self, aux) } else ioh = comconsioh; irq = ia->ia_irq; - } else { + } else +#endif +#if NCOM_COMMULTI + if (1) { struct commulti_attach_args *ca = aux; /* @@ -412,7 +458,9 @@ comattach(parent, self, aux) if (ca->ca_noien) sc->sc_hwflags |= COM_HW_NOIEN; - } + } else +#endif + panic("comattach: impossible"); sc->sc_bc = bc; sc->sc_ioh = ioh; @@ -473,9 +521,18 @@ comattach(parent, self, aux) bus_io_write_1(bc, ioh, com_ier, 0); bus_io_write_1(bc, ioh, com_mcr, 0); - if (irq != IRQUNK) - sc->sc_ih = isa_intr_establish(irq, IST_EDGE, IPL_TTY, - comintr, sc, sc->sc_dev.dv_xname); + if (irq != IRQUNK) { +#if NCOM_ISA + if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) { + struct isa_attach_args *ia = aux; + + sc->sc_ih = isa_intr_establish(ia->ia_ic, irq, + IST_EDGE, IPL_TTY, comintr, sc, + sc->sc_dev.dv_xname); + } else +#endif + panic("comattach: IRQ but can't have one"); + } #ifdef KGDB if (kgdb_dev == makedev(commajor, unit)) { @@ -516,9 +573,9 @@ comopen(dev, flag, mode, p) int s; int error = 0; - if (unit >= comcd.cd_ndevs) + if (unit >= com_cd.cd_ndevs) return ENXIO; - sc = comcd.cd_devs[unit]; + sc = com_cd.cd_devs[unit]; if (!sc) return ENXIO; @@ -535,7 +592,10 @@ comopen(dev, flag, mode, p) ttychars(tp); tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; - tp->t_cflag = TTYDEF_CFLAG; + if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) + tp->t_cflag = comconscflag; + else + tp->t_cflag = TTYDEF_CFLAG; if (ISSET(sc->sc_swflags, COM_SW_CLOCAL)) SET(tp->t_cflag, CLOCAL); if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS)) @@ -644,7 +704,7 @@ comclose(dev, flag, mode, p) struct proc *p; { int unit = COMUNIT(dev); - struct com_softc *sc = comcd.cd_devs[unit]; + struct com_softc *sc = com_cd.cd_devs[unit]; struct tty *tp = sc->sc_tty; bus_chipset_tag_t bc = sc->sc_bc; bus_io_handle_t ioh = sc->sc_ioh; @@ -684,7 +744,7 @@ comread(dev, uio, flag) struct uio *uio; int flag; { - struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)]; + struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)]; struct tty *tp = sc->sc_tty; return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); @@ -696,7 +756,7 @@ comwrite(dev, uio, flag) struct uio *uio; int flag; { - struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)]; + struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)]; struct tty *tp = sc->sc_tty; return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); @@ -706,7 +766,7 @@ struct tty * comtty(dev) dev_t dev; { - struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)]; + struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)]; struct tty *tp = sc->sc_tty; return (tp); @@ -734,7 +794,7 @@ comioctl(dev, cmd, data, flag, p) struct proc *p; { int unit = COMUNIT(dev); - struct com_softc *sc = comcd.cd_devs[unit]; + struct com_softc *sc = com_cd.cd_devs[unit]; struct tty *tp = sc->sc_tty; bus_chipset_tag_t bc = sc->sc_bc; bus_io_handle_t ioh = sc->sc_ioh; @@ -846,7 +906,7 @@ comparam(tp, t) struct tty *tp; struct termios *t; { - struct com_softc *sc = comcd.cd_devs[COMUNIT(tp->t_dev)]; + struct com_softc *sc = com_cd.cd_devs[COMUNIT(tp->t_dev)]; bus_chipset_tag_t bc = sc->sc_bc; bus_io_handle_t ioh = sc->sc_ioh; int ospeed = comspeed(t->c_ospeed); @@ -985,7 +1045,7 @@ void comstart(tp) struct tty *tp; { - struct com_softc *sc = comcd.cd_devs[COMUNIT(tp->t_dev)]; + struct com_softc *sc = com_cd.cd_devs[COMUNIT(tp->t_dev)]; bus_chipset_tag_t bc = sc->sc_bc; bus_io_handle_t ioh = sc->sc_ioh; int s; @@ -1106,8 +1166,8 @@ compoll(arg) comevents = 0; splx(s); - for (unit = 0; unit < comcd.cd_ndevs; unit++) { - sc = comcd.cd_devs[unit]; + for (unit = 0; unit < com_cd.cd_ndevs; unit++) { + sc = com_cd.cd_devs[unit]; if (sc == 0 || sc->sc_ibufp == sc->sc_ibuf) continue; diff --git a/sys/dev/isa/comvar.h b/sys/dev/isa/comvar.h index 9b412b06936..c3f8068caec 100644 --- a/sys/dev/isa/comvar.h +++ b/sys/dev/isa/comvar.h @@ -1,5 +1,5 @@ -/* $OpenBSD: comvar.h,v 1.1 1996/04/19 16:08:34 niklas Exp $ */ -/* $NetBSD: comvar.h,v 1.3 1996/03/10 09:01:26 cgd Exp $ */ +/* $OpenBSD: comvar.h,v 1.2 1996/04/21 22:23:20 deraadt Exp $ */ +/* $NetBSD: comvar.h,v 1.4 1996/04/15 18:54:35 cgd Exp $ */ /* * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. @@ -46,3 +46,4 @@ extern int comconsaddr; extern int comconsattached; extern bus_chipset_tag_t comconsbc; extern bus_io_handle_t comconsioh; +extern tcflag_t comconscflag; diff --git a/sys/dev/isa/fd.c b/sys/dev/isa/fd.c index 45564bd20b9..a7b07df07c7 100644 --- a/sys/dev/isa/fd.c +++ b/sys/dev/isa/fd.c @@ -1,5 +1,5 @@ -/* $OpenBSD: fd.c,v 1.12 1996/04/18 17:12:13 niklas Exp $ */ -/* $NetBSD: fd.c,v 1.85 1996/03/04 04:01:03 mycroft Exp $ */ +/* $OpenBSD: fd.c,v 1.13 1996/04/21 22:16:52 deraadt Exp $ */ +/* $NetBSD: fd.c,v 1.87 1996/04/11 22:15:16 cgd Exp $ */ /*- * Copyright (c) 1993, 1994, 1995 Charles Hannum. @@ -112,8 +112,12 @@ void fdcforceintr __P((void *)); #endif void fdcattach __P((struct device *, struct device *, void *)); -struct cfdriver fdccd = { - NULL, "fdc", fdcprobe, fdcattach, DV_DULL, sizeof(struct fdc_softc) +struct cfattach fdc_ca = { + sizeof(struct fdc_softc), fdcprobe, fdcattach +}; + +struct cfdriver fdc_cd = { + NULL, "fdc", DV_DULL }; /* @@ -179,8 +183,12 @@ struct fd_softc { int fdprobe __P((struct device *, void *, void *)); void fdattach __P((struct device *, struct device *, void *)); -struct cfdriver fdcd = { - NULL, "fd", fdprobe, fdattach, DV_DISK, sizeof(struct fd_softc) +struct cfattach fd_ca = { + sizeof(struct fd_softc), fdprobe, fdattach +}; + +struct cfdriver fd_cd = { + NULL, "fd", DV_DISK }; void fdgetdisklabel __P((struct fd_softc *)); @@ -308,8 +316,8 @@ fdcattach(parent, self, aux) at_setup_dmachan(fdc->sc_drq, FDC_MAXIOSIZE); isa_establish(&fdc->sc_id, &fdc->sc_dev); #endif - fdc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_BIO, fdcintr, - fdc, fdc->sc_dev.dv_xname); + fdc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_BIO, fdcintr, fdc, fdc->sc_dev.dv_xname); /* * The NVRAM info only tells us about the first two disks on the @@ -477,8 +485,8 @@ fdstrategy(bp) int s; /* Valid unit, controller, and request? */ - if (unit >= fdcd.cd_ndevs || - (fd = fdcd.cd_devs[unit]) == 0 || + if (unit >= fd_cd.cd_ndevs || + (fd = fd_cd.cd_devs[unit]) == 0 || bp->b_blkno < 0 || (bp->b_bcount % FDC_BSIZE) != 0) { bp->b_error = EINVAL; @@ -705,9 +713,9 @@ Fdopen(dev, flags) struct fd_type *type; unit = FDUNIT(dev); - if (unit >= fdcd.cd_ndevs) + if (unit >= fd_cd.cd_ndevs) return ENXIO; - fd = fdcd.cd_devs[unit]; + fd = fd_cd.cd_devs[unit]; if (fd == 0) return ENXIO; type = fd_dev_to_type(fd, dev); @@ -730,7 +738,7 @@ fdclose(dev, flags) dev_t dev; int flags; { - struct fd_softc *fd = fdcd.cd_devs[FDUNIT(dev)]; + struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; fd->sc_flags &= ~FD_OPEN; return 0; @@ -1169,7 +1177,7 @@ fdioctl(dev, cmd, addr, flag) caddr_t addr; int flag; { - struct fd_softc *fd = fdcd.cd_devs[FDUNIT(dev)]; + struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; struct disklabel buffer; int error; diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa index 02c45fce533..47e4237a8b2 100644 --- a/sys/dev/isa/files.isa +++ b/sys/dev/isa/files.isa @@ -1,5 +1,5 @@ -# $OpenBSD: files.isa,v 1.7 1996/04/18 23:47:33 niklas Exp $ -# $NetBSD: files.isa,v 1.12 1996/03/04 03:29:16 cgd Exp $ +# $OpenBSD: files.isa,v 1.8 1996/04/21 22:23:23 deraadt Exp $ +# $NetBSD: files.isa,v 1.17 1996/03/29 20:53:30 mycroft Exp $ # # Config.new file and device description for machine-independent ISA code. # Included by ports that need it. Requires that the SCSI files be @@ -9,11 +9,10 @@ # devices: # mcd, scd, wd, wt -define isa {[port = -1], [size = 0], - [iomem = -1], [iosiz = 0], - [irq = -1], [drq = -1]} - -device isa at isabus: isa +device isa {[port = -1], [size = 0], + [iomem = -1], [iosiz = 0], + [irq = -1], [drq = -1]} +attach isa at isabus file dev/isa/isa.c isa needs-flag # ISA DMA controller @@ -28,7 +27,8 @@ file dev/isa/isadma.c isadma needs-flag define pcicbus {[iomem = -1], [iosiz = 0]} -device pcic at isa: pcicbus +device pcic: pcicbus +attach pcic at isa file dev/isa/pcmcia_pcic.c pcic file dev/isa/pcmcia_isa.c pcmcia @@ -47,15 +47,18 @@ include "../../../dev/pcmcia/files.pcmcia" define commulti {[slave = -1]} # AST 4-port board -device ast at isa: commulti +device ast: commulti +attach ast at isa file dev/isa/ast.c ast # BOCA 8-port board -device boca at isa: commulti +device boca: commulti +attach boca at isa file dev/isa/boca.c boca # IBM RT PC 4-port board -device rtfps at isa: commulti +device rtfps: commulti +attach rtfps at isa file dev/isa/rtfps.c rtfps # @@ -63,16 +66,20 @@ file dev/isa/rtfps.c rtfps # # 8250/16[45]50-based "com" ports -device com at isa, commulti: tty -file dev/isa/com.c com needs-flag +device com: tty +attach com at isa with com_isa +attach com at commulti with com_commulti +file dev/isa/com.c com & (com_isa | com_commulti) needs-flag # Cyclades Cyclom multiport serial cards # XXX currently broken -device cy at isa: tty +device cy: tty +attach cy at isa file dev/isa/cy.c cy needs-count # PC parallel ports (XXX what chip?) -device lpt at isa +device lpt +attach lpt at isa file dev/isa/lpt.c lpt needs-flag # @@ -80,53 +87,64 @@ file dev/isa/lpt.c lpt needs-flag # # Adaptec AHA-154x family -device aha at isa: scsi, isadma -file dev/isa/aha1542.c aha +device aha: scsi, isadma +attach aha at isa +file dev/isa/aha.c aha # Adapctec AIC-6[32]60 ICs -device aic at isa: scsi, isadma +device aic: scsi, isadma +attach aic at isa file dev/isa/aic6360.c aic # Adaptec 7770-based EISA, VLB, etc. controllers -device ahe at isa: scsi, aic7xxx +device ahe: scsi, aic7xxx +attach ahe at isa file dev/isa/aha284x.c ahe # BusLogic BT-74x EISA family (XXX; should be EISA. it's special) -device bt at isa: scsi, isadma -file dev/isa/bt742a.c bt +device bt: scsi, isadma +attach bt at isa +file dev/isa/bt.c bt # Seagate ST0[12] ICs -device sea at isa: scsi, isadma +device sea: scsi, isadma +attach sea at isa file dev/isa/seagate.c sea # UltraStor UHA-[13]4f boards -device uha at isa: scsi, isadma +device uha: scsi, isadma +attach uha at isa file dev/isa/ultra14f.c uha -# Western Digital WD7000 boards (XXX incomplete description) -# XXX not yet working -device wds at isa: scsi, isadma -file dev/isa/wd7000.c wds +# Western Digital WD7000 and Future Domain TMC-7000 boards +device wds: scsi, isadma +attach wds at isa +file dev/isa/wds.c wds # # Other ISA disk controllers # # Mitsumi CD-ROM controllers -device mcd at isa: disk +device mcd: disk +attach mcd at isa file dev/isa/mcd.c mcd needs-flag # Sony CDU-3[13]A CD-ROM drives -device scd at isa: disk +device scd: disk +attach scd at isa file dev/isa/scd.c scd needs-flag # ISA "wd" (ESDI/IDE/etc.) controllers -device wdc at isa {drive = -1} -device wd at wdc: disk, isadma +device wdc {drive = -1} +attach wdc at isa +device wd: disk, isadma +attach wd at wdc file dev/isa/wd.c wdc needs-flag # Wangtek- and Archive-compatible tape controller boards -device wt at isa: tape, isadma +device wt: tape, isadma +attach wt at isa file dev/isa/wt.c wt needs-flag # @@ -140,45 +158,55 @@ file dev/isa/elink.c elink # National Semiconductor DS8390/WD83C690-based boards # (WD/SMC 80x3 family, SMC Ultra [8216], 3Com 3C503, NE[12]000, and clones) # XXX conflicts with amiga if_ed.c -#device ed at isa, pcmcia: ether, ifnet -#file dev/isa/if_ed.c ed needs-flag +device ed: ether, ifnet +attach ed at isa +file dev/isa/if_ed.c ed needs-flag # 3Com 3C505 -device eg at isa: ether, ifnet +device eg: ether, ifnet +attach eg at isa file dev/isa/if_eg.c eg # 3Com 3C501 -device el at isa: ether, ifnet +device el: ether, ifnet +attach el at isa file dev/isa/if_el.c el # 3Com 3C5x9, 3c59x (EtherLink III) family -device ep at isa, pci: ether, ifnet, elink +device ep: ether, ifnet, elink +attach ep at isa with ep_isa +attach ep at pci with ep_pci file dev/isa/if_ep.c ep needs-flag # Fujitsu MB8696[05]-based boards # (Allied Telesis AT1700) -device fe at isa: ether, ifnet +device fe: ether, ifnet +attach fe at isa file dev/isa/if_fe.c fe # HP Lan Ethernet controllers # XXX currently broken -#device hp at isa: ether, ifnet +#device hp: ether, ifnet +#attach hp at isa #file dev/isa/if_hp.c hp # Intel i82586-based boards # (AT&T StarLAN 10, AT&T EN100, AT&T StarLAN Fiber, 3Com 3C507) -device ie at isa: ether, ifnet, elink +device ie: ether, ifnet, elink +attach ie at isa file dev/isa/if_ie.c ie # XXX ??? # XXX NOT IN TREE? -#device ix at isa: ether, ifnet +#device ix: ether, ifnet +#attach ix at isa #file dev/isa/if_ix.c ix # AMD am7990 (Lance) -based boards # (BICC Isolan, NE2100, DEPCA) # XXX conflicts with alpha if_le.c -#device le at isa: ether, ifnet, isadma +#device le: ether, ifnet, isadma +#attach le at isa with le_isa #file dev/isa/if_le.c le # @@ -190,11 +218,13 @@ define sbdsp file dev/isa/sbdsp.c sbdsp # SoundBlaster family -device sb at isa: audio, isadma, sbdsp, mulaw +device sb: audio, isadma, sbdsp, mulaw +attach sb at isa file dev/isa/sb.c sb needs-flag # ProAudio Spectrum -device pas at isa: audio, isadma, sbdsp, mulaw +device pas: audio, isadma, sbdsp, mulaw +attach pas at isa file dev/isa/pas.c pas needs-flag # AD1848 (CS4248, CS4231, AD1845) audio codec support; used by other drivers @@ -207,18 +237,22 @@ file dev/isa/ics2101.c ics2101 # Audio systems based on Echo Speech Corp. ESC61[45] ASICs -device pss at isa {[port = -1], [size = 0], - [iomem = -1], [iosiz = 0], - [irq = -1], [drq = -1]} -device sp at pss: audio, isadma, ad1848 +device pss {[port = -1], [size = 0], + [iomem = -1], [iosiz = 0], + [irq = -1], [drq = -1]} +attach pss at isa +device sp: audio, isadma, ad1848 +attach sp at pss file dev/isa/pss.c pss needs-flag # Microsoft Windows Sound System -device wss at isa: audio, isadma, ad1848 +device wss: audio, isadma, ad1848 +attach wss at isa file dev/isa/wss.c wss needs-flag # Gravis UltraSound & UltraSound MAX. # Use the "flags" keyword in a config file to specify an extra DMA # channel for full-duplex operation. -device gus at isa: audio, isadma, ics2101, ad1848, mulaw +device gus: audio, isadma, ics2101, ad1848, mulaw +attach gus at isa file dev/isa/gus.c gus needs-flag diff --git a/sys/dev/isa/gus.c b/sys/dev/isa/gus.c index a2c1b4f2014..9a72f7a6182 100644 --- a/sys/dev/isa/gus.c +++ b/sys/dev/isa/gus.c @@ -1,5 +1,5 @@ -/* $OpenBSD: gus.c,v 1.8 1996/04/18 23:47:34 niklas Exp $ */ -/* $NetBSD: gus.c,v 1.10 1996/03/01 04:08:31 mycroft Exp $ */ +/* $OpenBSD: gus.c,v 1.9 1996/04/21 22:23:28 deraadt Exp $ */ +/* $NetBSD: gus.c,v 1.13 1996/04/11 22:28:42 cgd Exp $ */ /*- * Copyright (c) 1996 The NetBSD Foundation, Inc. @@ -126,6 +126,7 @@ #include <dev/ic/ad1848reg.h> #include <dev/isa/ics2101var.h> #include <dev/isa/ad1848var.h> +#include <dev/isa/cs4231var.h> #include "gusreg.h" #ifdef AUDIO_DEBUG @@ -458,8 +459,12 @@ STATIC void gusics_cd_mute __P((struct ics2101_softc *, int)); int gusprobe __P((struct device *, void *, void *)); void gusattach __P((struct device *, struct device *, void *)); -struct cfdriver guscd = { - NULL, "gus", gusprobe, gusattach, DV_DULL, sizeof(struct gus_softc) +struct cfattach gus_ca = { + sizeof(struct gus_softc), gusprobe, gusattach, +}; + +struct cfdriver gus_cd = { + NULL, "gus", DV_DULL }; @@ -927,8 +932,8 @@ gusattach(parent, self, aux) /* XXX we shouldn't have to use splgus == splclock, nor should * we use IPL_CLOCK. */ - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_AUDIO, gusintr, - sc /* sc->sc_gusdsp */, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_AUDIO, gusintr, sc /* sc->sc_gusdsp */, sc->sc_dev.dv_xname); /* * Set some default values @@ -974,9 +979,9 @@ gusopen(dev, flags) DPRINTF(("gusopen() called\n")); - if (unit >= guscd.cd_ndevs) + if (unit >= gus_cd.cd_ndevs) return ENXIO; - sc = guscd.cd_devs[unit]; + sc = gus_cd.cd_devs[unit]; if (!sc) return ENXIO; diff --git a/sys/dev/isa/if_ed.c b/sys/dev/isa/if_ed.c index dc5993a34b7..b385c61d95a 100644 --- a/sys/dev/isa/if_ed.c +++ b/sys/dev/isa/if_ed.c @@ -1,5 +1,5 @@ -/* $OpenBSD: if_ed.c,v 1.9 1996/04/18 23:47:37 niklas Exp $ */ -/* $NetBSD: if_ed.c,v 1.90 1996/03/16 07:24:15 cgd Exp $ */ +/* $OpenBSD: if_ed.c,v 1.10 1996/04/21 22:23:41 deraadt Exp $ */ +/* $NetBSD: if_ed.c,v 1.93 1996/04/11 22:28:55 cgd Exp $ */ /* * Device driver for National Semiconductor DS8390/WD83C690 based ethernet @@ -18,7 +18,6 @@ * similar clones. */ -#include "pcmciabus.h" #include "bpfilter.h" #include <sys/param.h> @@ -54,11 +53,10 @@ #endif #include <machine/cpu.h> -#include <machine/pio.h> +#include <machine/bus.h> #include <dev/isa/isareg.h> #include <dev/isa/isavar.h> -#include <i386/isa/isa_machdep.h> /* XXX USES ISA HOLE DIRECTLY */ #define ED_BYTE_ORDER LITTLE_ENDIAN #include <dev/ic/dp8390reg.h> #include <dev/isa/if_edreg.h> @@ -81,8 +79,12 @@ struct ed_softc { #define ED_NOTPRESENT 0x0002 /* card not present; do not allow reconfiguration */ - int asic_base; /* Base ASIC I/O port */ - int nic_base; /* Base NIC (DS8390) I/O port */ + bus_chipset_tag_t sc_bc; /* bus identifier */ + bus_io_handle_t sc_ioh; /* io handle */ + bus_mem_handle_t sc_memh; /* bus memory handle */ + + bus_io_size_t asic_base; /* offset of ASIC I/O port */ + bus_io_size_t nic_base; /* offset of NIC (DS8390) I/O port */ /* * The following 'proto' variable is part of a work-around for 8013EBT asics @@ -98,10 +100,10 @@ struct ed_softc { u_char isa16bit; /* width of access to card 0=8 or 1=16 */ u_char is790; /* set by probe if NIC is a 790 */ - caddr_t mem_start; /* NIC memory start address */ - caddr_t mem_end; /* NIC memory end address */ - u_long mem_size; /* total NIC memory size */ - caddr_t mem_ring; /* start of RX ring-buffer (in NIC mem) */ + int mem_start; /* offset of NIC memory */ + int mem_end; /* offset of NIC memory end */ + int mem_size; /* total NIC memory size */ + int mem_ring; /* offset of RX ring-buffer (in NIC mem) */ u_char mem_shared; /* NIC memory is shared with host */ u_char txb_cnt; /* number of transmit buffers */ @@ -120,7 +122,7 @@ int edprobe __P((struct device *, void *, void *)); void edattach __P((struct device *, struct device *, void *)); int ed_find __P((struct ed_softc *, struct cfdata *, struct isa_attach_args *ia)); -int ed_probe_generic8390 __P((int)); +int ed_probe_generic8390 __P((bus_chipset_tag_t, bus_io_handle_t, int)); int ed_find_WD80x3 __P((struct ed_softc *, struct cfdata *, struct isa_attach_args *ia)); int ed_find_3Com __P((struct ed_softc *, struct cfdata *, @@ -135,31 +137,41 @@ void edreset __P((struct ed_softc *)); void edinit __P((struct ed_softc *)); void edstop __P((struct ed_softc *)); +void ed_shared_writemem __P((struct ed_softc *, caddr_t, int, int)); +void ed_shared_readmem __P((struct ed_softc *, int, caddr_t, int)); + #define inline /* XXX for debugging porpoises */ void ed_getmcaf __P((struct arpcom *, u_long *)); -void edread __P((struct ed_softc *, caddr_t, int)); -struct mbuf *edget __P((struct ed_softc *, caddr_t, int)); +void edread __P((struct ed_softc *, int, int)); +struct mbuf *edget __P((struct ed_softc *, int, int)); static inline void ed_rint __P((struct ed_softc *)); static inline void ed_xmit __P((struct ed_softc *)); -static inline caddr_t ed_ring_copy __P((struct ed_softc *, caddr_t, caddr_t, +static inline int ed_ring_copy __P((struct ed_softc *, int, caddr_t, u_short)); void ed_pio_readmem __P((struct ed_softc *, u_short, caddr_t, u_short)); void ed_pio_writemem __P((struct ed_softc *, caddr_t, u_short, u_short)); u_short ed_pio_write_mbufs __P((struct ed_softc *, struct mbuf *, u_short)); -struct cfdriver edcd = { - NULL, "ed", edprobe, edattach, DV_IFNET, sizeof(struct ed_softc) +struct cfattach ed_ca = { + sizeof(struct ed_softc), edprobe, edattach +}; + +struct cfdriver ed_cd = { + NULL, "ed", DV_IFNET }; #define ETHER_MIN_LEN 64 #define ETHER_MAX_LEN 1518 #define ETHER_ADDR_LEN 6 -#define NIC_PUT(base, off, val) outb((base) + (off), (val)) -#define NIC_GET(base, off) inb((base) + (off)) +#define NIC_PUT(bc, ioh, nic, reg, val) \ + bus_io_write_1((bc), (ioh), ((nic) + (reg)), (val)) +#define NIC_GET(bc, ioh, nic, reg) \ + bus_io_read_1((bc), (ioh), ((nic) + (reg))) +/*#include "pcmciabus.h"*/ #if NPCMCIABUS > 0 #include <dev/pcmcia/pcmciabus.h> @@ -359,15 +371,17 @@ ed_find(sc, cf, ia) * Return 1 if 8390 was found, 0 if not. */ int -ed_probe_generic8390(nicbase) +ed_probe_generic8390(bc, ioh, nicbase) + bus_chipset_tag_t bc; + bus_io_handle_t ioh; int nicbase; { - if ((NIC_GET(nicbase, ED_P0_CR) & + if ((NIC_GET(bc, ioh, nicbase, ED_P0_CR) & (ED_CR_RD2 | ED_CR_TXP | ED_CR_STA | ED_CR_STP)) != (ED_CR_RD2 | ED_CR_STP)) return (0); - if ((NIC_GET(nicbase, ED_P0_ISR) & ED_ISR_RST) != ED_ISR_RST) + if ((NIC_GET(bc, ioh, nicbase, ED_P0_ISR) & ED_ISR_RST) != ED_ISR_RST) return (0); return (1); @@ -385,17 +399,26 @@ ed_find_WD80x3(sc, cf, ia) struct cfdata *cf; struct isa_attach_args *ia; { - int i; + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + bus_mem_handle_t memh; u_int memsize; u_char iptr, isa16bit, sum; + int i, rv, mapped_mem = 0; int asicbase, nicbase; - sc->asic_base = asicbase = ia->ia_iobase; + bc = ia->ia_bc; + rv = 0; + + if (bus_io_map(bc, ia->ia_iobase, ED_WD_IO_PORTS, &ioh)) + return (0); + + sc->asic_base = asicbase = 0; sc->nic_base = nicbase = asicbase + ED_WD_NIC_OFFSET; sc->is790 = 0; #ifdef TOSH_ETHER - outb(asicbase + ED_WD_MSR, ED_WD_MSR_POW); + bus_io_write_1(bc, ioh, asicbase + ED_WD_MSR, ED_WD_MSR_POW); delay(10000); #endif @@ -406,7 +429,7 @@ ed_find_WD80x3(sc, cf, ia) * Danpex boards for one. */ for (sum = 0, i = 0; i < 8; ++i) - sum += inb(asicbase + ED_WD_PROM + i); + sum += bus_io_read_1(bc, ioh, asicbase + ED_WD_PROM + i); if (sum != ED_WD_ROM_CHECKSUM_TOTAL) { /* @@ -414,25 +437,27 @@ ed_find_WD80x3(sc, cf, ia) * clones. In this case, the checksum byte (the eighth byte) * seems to always be zero. */ - if (inb(asicbase + ED_WD_CARD_ID) != ED_TYPE_WD8003E || - inb(asicbase + ED_WD_PROM + 7) != 0) - return (0); + if (bus_io_read_1(bc, ioh, asicbase + ED_WD_CARD_ID) != + ED_TYPE_WD8003E || + bus_io_read_1(bc, ioh, asicbase + ED_WD_PROM + 7) != 0) + goto out; } /* Reset card to force it into a known state. */ #ifdef TOSH_ETHER - outb(asicbase + ED_WD_MSR, ED_WD_MSR_RST | ED_WD_MSR_POW); + bus_io_write_1(bc, ioh, asicbase + ED_WD_MSR, + ED_WD_MSR_RST | ED_WD_MSR_POW); #else - outb(asicbase + ED_WD_MSR, ED_WD_MSR_RST); + bus_io_write_1(bc, ioh, asicbase + ED_WD_MSR, ED_WD_MSR_RST); #endif delay(100); - outb(asicbase + ED_WD_MSR, - inb(asicbase + ED_WD_MSR) & ~ED_WD_MSR_RST); + bus_io_write_1(bc, ioh, asicbase + ED_WD_MSR, + bus_io_read_1(bc, ioh, asicbase + ED_WD_MSR) & ~ED_WD_MSR_RST); /* Wait in the case this card is reading it's EEROM. */ delay(5000); sc->vendor = ED_VENDOR_WD_SMC; - sc->type = inb(asicbase + ED_WD_CARD_ID); + sc->type = bus_io_read_1(bc, ioh, asicbase + ED_WD_CARD_ID); /* Set initial values for width/size. */ memsize = 8192; @@ -487,9 +512,11 @@ ed_find_WD80x3(sc, cf, ia) case ED_TYPE_SMC8216T: sc->type_str = (sc->type == ED_TYPE_SMC8216C) ? "SMC8216/SMC8216C" : "SMC8216T"; - outb(asicbase + ED_WD790_HWR, - inb(asicbase + ED_WD790_HWR) | ED_WD790_HWR_SWH); - switch (inb(asicbase + ED_WD790_RAR) & ED_WD790_RAR_SZ64) { + bus_io_write_1(bc, ioh, asicbase + ED_WD790_HWR, + bus_io_read_1(bc, ioh, asicbase + ED_WD790_HWR) + | ED_WD790_HWR_SWH); + switch (bus_io_read_1(bc, ioh, asicbase + ED_WD790_RAR) & + ED_WD790_RAR_SZ64) { case ED_WD790_RAR_SZ64: memsize = 65536; break; @@ -506,8 +533,9 @@ ed_find_WD80x3(sc, cf, ia) memsize = 8192; break; } - outb(asicbase + ED_WD790_HWR, - inb(asicbase + ED_WD790_HWR) & ~ED_WD790_HWR_SWH); + bus_io_write_1(bc, ioh, asicbase + ED_WD790_HWR, + bus_io_read_1(bc, ioh, + asicbase + ED_WD790_HWR) & ~ED_WD790_HWR_SWH); isa16bit = 1; sc->is790 = 1; @@ -536,7 +564,8 @@ ed_find_WD80x3(sc, cf, ia) #ifdef TOSH_ETHER (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4) && #endif - ((inb(asicbase + ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) { + ((bus_io_read_1(bc, ioh, + asicbase + ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) { isa16bit = 0; memsize = 8192; } @@ -567,13 +596,13 @@ ed_find_WD80x3(sc, cf, ia) if (sc->is790) { u_char x; /* Assemble together the encoded interrupt number. */ - outb(ia->ia_iobase + ED_WD790_HWR, - inb(ia->ia_iobase + ED_WD790_HWR) | ED_WD790_HWR_SWH); - x = inb(ia->ia_iobase + ED_WD790_GCR); + bus_io_write_1(bc, ioh, ED_WD790_HWR, + bus_io_read_1(bc, ioh, ED_WD790_HWR) | ED_WD790_HWR_SWH); + x = bus_io_read_1(bc, ioh, ED_WD790_GCR); iptr = ((x & ED_WD790_GCR_IR2) >> 4) | ((x & (ED_WD790_GCR_IR1|ED_WD790_GCR_IR0)) >> 2); - outb(ia->ia_iobase + ED_WD790_HWR, - inb(ia->ia_iobase + ED_WD790_HWR) & ~ED_WD790_HWR_SWH); + bus_io_write_1(bc, ioh, ED_WD790_HWR, + bus_io_read_1(bc, ioh, ED_WD790_HWR) & ~ED_WD790_HWR_SWH); /* * Translate it using translation table, and check for * correctness. @@ -583,17 +612,17 @@ ed_find_WD80x3(sc, cf, ia) printf("%s: irq mismatch; kernel configured %d != board configured %d\n", sc->sc_dev.dv_xname, ia->ia_irq, ed_wd790_irq[iptr]); - return (0); + goto out; } } else ia->ia_irq = ed_wd790_irq[iptr]; /* Enable the interrupt. */ - outb(ia->ia_iobase + ED_WD790_ICR, - inb(ia->ia_iobase + ED_WD790_ICR) | ED_WD790_ICR_EIL); + bus_io_write_1(bc, ioh, ED_WD790_ICR, + bus_io_read_1(bc, ioh, ED_WD790_ICR) | ED_WD790_ICR_EIL); } else if (sc->type & ED_WD_SOFTCONFIG) { /* Assemble together the encoded interrupt number. */ - iptr = (inb(ia->ia_iobase + ED_WD_ICR) & ED_WD_ICR_IR2) | - ((inb(ia->ia_iobase + ED_WD_IRR) & + iptr = (bus_io_read_1(bc, ioh, ED_WD_ICR) & ED_WD_ICR_IR2) | + ((bus_io_read_1(bc, ioh, ED_WD_IRR) & (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5); /* * Translate it using translation table, and check for @@ -604,18 +633,18 @@ ed_find_WD80x3(sc, cf, ia) printf("%s: irq mismatch; kernel configured %d != board configured %d\n", sc->sc_dev.dv_xname, ia->ia_irq, ed_wd584_irq[iptr]); - return (0); + goto out; } } else ia->ia_irq = ed_wd584_irq[iptr]; /* Enable the interrupt. */ - outb(ia->ia_iobase + ED_WD_IRR, - inb(ia->ia_iobase + ED_WD_IRR) | ED_WD_IRR_IEN); + bus_io_write_1(bc, ioh, ED_WD_IRR, + bus_io_read_1(bc, ioh, ED_WD_IRR) | ED_WD_IRR_IEN); } else { if (ia->ia_irq == IRQUNK) { printf("%s: %s does not have soft configuration\n", sc->sc_dev.dv_xname, sc->type_str); - return (0); + goto out; } } @@ -624,7 +653,10 @@ ed_find_WD80x3(sc, cf, ia) sc->isa16bit = isa16bit; sc->mem_shared = 1; ia->ia_msize = memsize; - sc->mem_start = ISA_HOLE_VADDR(ia->ia_maddr); + if (bus_mem_map(bc, ia->ia_maddr, memsize, 0, &memh)) + goto out; + mapped_mem = 1; + sc->mem_start = 0; /* offset */ /* Allocate one xmit buffer if < 16k, two buffers otherwise. */ if ((memsize < 16384) || (cf->cf_flags & ED_FLAGS_NO_MULTI_BUFFERING)) @@ -642,7 +674,7 @@ ed_find_WD80x3(sc, cf, ia) /* Get station address from on-board ROM. */ for (i = 0; i < ETHER_ADDR_LEN; ++i) sc->sc_arpcom.ac_enaddr[i] = - inb(asicbase + ED_WD_PROM + i); + bus_io_read_1(bc, ioh, asicbase + ED_WD_PROM + i); /* * Set upper address bits and 8/16 bit access to shared memory. @@ -650,15 +682,15 @@ ed_find_WD80x3(sc, cf, ia) if (isa16bit) { if (sc->is790) { sc->wd_laar_proto = - inb(asicbase + ED_WD_LAAR) & + bus_io_read_1(bc, ioh, asicbase + ED_WD_LAAR) & ~ED_WD_LAAR_M16EN; } else { sc->wd_laar_proto = ED_WD_LAAR_L16EN | - ((kvtop(sc->mem_start) >> 19) & + ((ia->ia_maddr >> 19) & ED_WD_LAAR_ADDRHI); } - outb(asicbase + ED_WD_LAAR, + bus_io_write_1(bc, ioh, asicbase + ED_WD_LAAR, sc->wd_laar_proto | ED_WD_LAAR_M16EN); } else { if ((sc->type & ED_WD_SOFTCONFIG) || @@ -668,9 +700,9 @@ ed_find_WD80x3(sc, cf, ia) #endif (sc->type == ED_TYPE_WD8013EBT) && !sc->is790) { sc->wd_laar_proto = - ((kvtop(sc->mem_start) >> 19) & + ((ia->ia_maddr >> 19) & ED_WD_LAAR_ADDRHI); - outb(asicbase + ED_WD_LAAR, + bus_io_write_1(bc, ioh, asicbase + ED_WD_LAAR, sc->wd_laar_proto); } } @@ -680,52 +712,53 @@ ed_find_WD80x3(sc, cf, ia) */ if (!sc->is790) { #ifdef TOSH_ETHER - outb(asicbase + ED_WD_MSR + 1, - ((kvtop(sc->mem_start) >> 8) & 0xe0) | 4); - outb(asicbase + ED_WD_MSR + 2, - ((kvtop(sc->mem_start) >> 16) & 0x0f)); + bus_io_write_1(bc, ioh, asicbase + ED_WD_MSR + 1, + ((ia->ia_maddr >> 8) & 0xe0) | 4); + bus_io_write_1(bc, ioh, asicbase + ED_WD_MSR + 2, + ((ia->ia_maddr >> 16) & 0x0f)); sc->wd_msr_proto = ED_WD_MSR_POW; #else sc->wd_msr_proto = - (kvtop(sc->mem_start) >> 13) & ED_WD_MSR_ADDR; + (ia->ia_maddr >> 13) & ED_WD_MSR_ADDR; #endif sc->cr_proto = ED_CR_RD2; } else { - outb(asicbase + 0x04, - inb(asicbase + 0x04) | 0x80); - outb(asicbase + 0x0b, - ((kvtop(sc->mem_start) >> 13) & 0x0f) | - ((kvtop(sc->mem_start) >> 11) & 0x40) | - (inb(asicbase + 0x0b) & 0xb0)); - outb(asicbase + 0x04, - inb(asicbase + 0x04) & ~0x80); + bus_io_write_1(bc, ioh, asicbase + 0x04, + bus_io_read_1(bc, ioh, asicbase + 0x04) | 0x80); + bus_io_write_1(bc, ioh, asicbase + 0x0b, + ((ia->ia_maddr >> 13) & 0x0f) | + ((ia->ia_maddr >> 11) & 0x40) | + (bus_io_read_1(bc, ioh, asicbase + 0x0b) & 0xb0)); + bus_io_write_1(bc, ioh, asicbase + 0x04, + bus_io_read_1(bc, ioh, asicbase + 0x04) & ~0x80); sc->wd_msr_proto = 0x00; sc->cr_proto = 0; } - outb(asicbase + ED_WD_MSR, + bus_io_write_1(bc, ioh, asicbase + ED_WD_MSR, sc->wd_msr_proto | ED_WD_MSR_MENB); - (void) inb(0x84); - (void) inb(0x84); + (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ + (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ /* Now zero memory and verify that it is clear. */ - bzero(sc->mem_start, memsize); + for (i = 0; i < memsize; ++i) + bus_mem_write_1(bc, memh, sc->mem_start + i, 0); for (i = 0; i < memsize; ++i) - if (sc->mem_start[i]) { + if (bus_mem_read_1(bc, memh, sc->mem_start + i)) { printf("%s: failed to clear shared memory at %x - check configuration\n", sc->sc_dev.dv_xname, - kvtop(sc->mem_start + i)); + (ia->ia_maddr + sc->mem_start + i)); /* Disable 16 bit access to shared memory. */ - outb(asicbase + ED_WD_MSR, + bus_io_write_1(bc, ioh, asicbase + ED_WD_MSR, sc->wd_msr_proto); if (isa16bit) - outb(asicbase + ED_WD_LAAR, + bus_io_write_1(bc, ioh, asicbase + ED_WD_LAAR, sc->wd_laar_proto); - (void) inb(0x84); - (void) inb(0x84); - return (0); + (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ + (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ + goto out; } /* @@ -736,14 +769,32 @@ ed_find_WD80x3(sc, cf, ia) * and 2) so that other 8 bit devices with shared memory can be * used in this 128k region, too. */ - outb(asicbase + ED_WD_MSR, sc->wd_msr_proto); + bus_io_write_1(bc, ioh, asicbase + ED_WD_MSR, sc->wd_msr_proto); if (isa16bit) - outb(asicbase + ED_WD_LAAR, sc->wd_laar_proto); - (void) inb(0x84); - (void) inb(0x84); + bus_io_write_1(bc, ioh, asicbase + ED_WD_LAAR, + sc->wd_laar_proto); + (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ + (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ ia->ia_iosize = ED_WD_IO_PORTS; - return (1); + rv = 1; + + out: + /* + * XXX Sould always unmap, but we can't yet. + * XXX Need to squish "indirect" first. + */ + if (rv == 0) { + bus_io_unmap(bc, ioh, ED_WD_IO_PORTS); + if (mapped_mem) + bus_mem_unmap(bc, memh, memsize); + } else { + /* XXX this is all "indirect" brokenness */ + sc->sc_bc = bc; + sc->sc_ioh = ioh; + sc->sc_memh = memh; + } + return (rv); } int ed_3com_iobase[] = {0x2e0, 0x2a0, 0x280, 0x250, 0x350, 0x330, 0x310, 0x300}; @@ -761,13 +812,22 @@ ed_find_3Com(sc, cf, ia) struct cfdata *cf; struct isa_attach_args *ia; { - int i; + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + bus_mem_handle_t memh; + int i, rv, mapped_mem = 0; u_int memsize; u_char isa16bit, sum, x; int ptr, asicbase, nicbase; - sc->asic_base = asicbase = ia->ia_iobase + ED_3COM_ASIC_OFFSET; - sc->nic_base = nicbase = ia->ia_iobase + ED_3COM_NIC_OFFSET; + bc = ia->ia_bc; + rv = 0; + + if (bus_io_map(bc, ia->ia_iobase, ED_WD_IO_PORTS, &ioh)) + return (0); + + sc->asic_base = asicbase = ED_3COM_ASIC_OFFSET; + sc->nic_base = nicbase = ED_3COM_NIC_OFFSET; /* * Verify that the kernel configured I/O address matches the board @@ -777,45 +837,46 @@ ed_find_3Com(sc, cf, ia) * board is there; after all, we are already talking it at that * address. */ - x = inb(asicbase + ED_3COM_BCFR); + x = bus_io_read_1(bc, ioh, asicbase + ED_3COM_BCFR); if (x == 0 || (x & (x - 1)) != 0) - return (0); + goto out; ptr = ffs(x) - 1; if (ia->ia_iobase != IOBASEUNK) { if (ia->ia_iobase != ed_3com_iobase[ptr]) { printf("%s: %s mismatch; kernel configured %x != board configured %x\n", "iobase", sc->sc_dev.dv_xname, ia->ia_iobase, ed_3com_iobase[ptr]); - return (0); + goto out; } } else - ia->ia_iobase = ed_3com_iobase[ptr]; + ia->ia_iobase = ed_3com_iobase[ptr]; /* XXX --thorpej */ - x = inb(asicbase + ED_3COM_PCFR); + x = bus_io_read_1(bc, ioh, asicbase + ED_3COM_PCFR); if (x == 0 || (x & (x - 1)) != 0) - return (0); + goto out; ptr = ffs(x) - 1; if (ia->ia_maddr != MADDRUNK) { if (ia->ia_maddr != ed_3com_maddr[ptr]) { printf("%s: %s mismatch; kernel configured %x != board configured %x\n", "maddr", sc->sc_dev.dv_xname, ia->ia_maddr, ed_3com_maddr[ptr]); - return (0); + goto out; } } else ia->ia_maddr = ed_3com_maddr[ptr]; #if 0 - x = inb(asicbase + ED_3COM_IDCFR) & ED_3COM_IDCFR_IRQ; + x = bus_io_read_1(bc, ioh, asicbase + ED_3COM_IDCFR) & + ED_3COM_IDCFR_IRQ; if (x == 0 || (x & (x - 1)) != 0) - return (0); + goto out; ptr = ffs(x) - 1; if (ia->ia_irq != IRQUNK) { if (ia->ia_irq != ed_3com_irq[ptr]) { printf("%s: irq mismatch; kernel configured %d != board configured %d\n", sc->sc_dev.dv_xname, ia->ia_irq, ed_3com_irq[ptr]); - return (0); + goto out; } } else ia->ia_irq = ed_3com_irq[ptr]; @@ -826,7 +887,8 @@ ed_find_3Com(sc, cf, ia) * sequence because it'll lock up if the cable isn't connected if we * don't. */ - outb(asicbase + ED_3COM_CR, ED_3COM_CR_RST | ED_3COM_CR_XSEL); + bus_io_write_1(bc, ioh, asicbase + ED_3COM_CR, + ED_3COM_CR_RST | ED_3COM_CR_XSEL); /* Wait for a while, then un-reset it. */ delay(50); @@ -836,7 +898,7 @@ ed_find_3Com(sc, cf, ia) * reset - it's important to set it again after the following outb * (this is done when we map the PROM below). */ - outb(asicbase + ED_3COM_CR, ED_3COM_CR_XSEL); + bus_io_write_1(bc, ioh, asicbase + ED_3COM_CR, ED_3COM_CR_XSEL); /* Wait a bit for the NIC to recover from the reset. */ delay(5000); @@ -858,42 +920,49 @@ ed_find_3Com(sc, cf, ia) * First, map ethernet address PROM over the top of where the NIC * registers normally appear. */ - outb(asicbase + ED_3COM_CR, ED_3COM_CR_EALO | ED_3COM_CR_XSEL); + bus_io_write_1(bc, ioh, asicbase + ED_3COM_CR, + ED_3COM_CR_EALO | ED_3COM_CR_XSEL); for (i = 0; i < ETHER_ADDR_LEN; ++i) - sc->sc_arpcom.ac_enaddr[i] = NIC_GET(nicbase, i); + sc->sc_arpcom.ac_enaddr[i] = NIC_GET(bc, ioh, nicbase, i); /* * Unmap PROM - select NIC registers. The proper setting of the * tranceiver is set in edinit so that the attach code is given a * chance to set the default based on a compile-time config option. */ - outb(asicbase + ED_3COM_CR, ED_3COM_CR_XSEL); + bus_io_write_1(bc, ioh, asicbase + ED_3COM_CR, ED_3COM_CR_XSEL); /* Determine if this is an 8bit or 16bit board. */ /* Select page 0 registers. */ - NIC_PUT(nicbase, ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STP); + NIC_PUT(bc, ioh, nicbase, ED_P0_CR, + ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STP); /* * Attempt to clear WTS bit. If it doesn't clear, then this is a * 16-bit board. */ - NIC_PUT(nicbase, ED_P0_DCR, 0); + NIC_PUT(bc, ioh, nicbase, ED_P0_DCR, 0); /* Select page 2 registers. */ - NIC_PUT(nicbase, ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_2 | ED_CR_STP); + NIC_PUT(bc, ioh, nicbase, + ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_2 | ED_CR_STP); /* The 3c503 forces the WTS bit to a one if this is a 16bit board. */ - if (NIC_GET(nicbase, ED_P2_DCR) & ED_DCR_WTS) + if (NIC_GET(bc, ioh, nicbase, ED_P2_DCR) & ED_DCR_WTS) isa16bit = 1; else isa16bit = 0; /* Select page 0 registers. */ - NIC_PUT(nicbase, ED_P2_CR, ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STP); + NIC_PUT(bc, ioh, nicbase, ED_P2_CR, + ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STP); - sc->mem_start = ISA_HOLE_VADDR(ia->ia_maddr); + if (bus_mem_map(bc, ia->ia_maddr, memsize, 0, &memh)) + goto out; + mapped_mem = 1; + sc->mem_start = 0; /* offset */ sc->mem_size = memsize; sc->mem_end = sc->mem_start + memsize; @@ -934,34 +1003,38 @@ ed_find_3Com(sc, cf, ia) * Initialize GA page start/stop registers. Probably only needed if * doing DMA, but what the Hell. */ - outb(asicbase + ED_3COM_PSTR, sc->rec_page_start); - outb(asicbase + ED_3COM_PSPR, sc->rec_page_stop); + bus_io_write_1(bc, ioh, asicbase + ED_3COM_PSTR, sc->rec_page_start); + bus_io_write_1(bc, ioh, asicbase + ED_3COM_PSPR, sc->rec_page_stop); /* Set IRQ. 3c503 only allows a choice of irq 3-5 or 9. */ switch (ia->ia_irq) { case 9: - outb(asicbase + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ2); + bus_io_write_1(bc, ioh, asicbase + ED_3COM_IDCFR, + ED_3COM_IDCFR_IRQ2); break; case 3: - outb(asicbase + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ3); + bus_io_write_1(bc, ioh, asicbase + ED_3COM_IDCFR, + ED_3COM_IDCFR_IRQ3); break; case 4: - outb(asicbase + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ4); + bus_io_write_1(bc, ioh, asicbase + ED_3COM_IDCFR, + ED_3COM_IDCFR_IRQ4); break; case 5: - outb(asicbase + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ5); + bus_io_write_1(bc, ioh, asicbase + ED_3COM_IDCFR, + ED_3COM_IDCFR_IRQ5); break; default: printf("%s: invalid irq configuration (%d) must be 3-5 or 9 for 3c503\n", sc->sc_dev.dv_xname, ia->ia_irq); - return (0); + goto out; } /* * Initialize GA configuration register. Set bank and enable shared * mem. */ - outb(asicbase + ED_3COM_GACFR, + bus_io_write_1(bc, ioh, asicbase + ED_3COM_GACFR, ED_3COM_GACFR_RSEL | ED_3COM_GACFR_MBS0); /* @@ -970,23 +1043,42 @@ ed_find_3Com(sc, cf, ia) * shared memory is disabled. We set them to 0xffff0...allegedly the * reset vector. */ - outb(asicbase + ED_3COM_VPTR2, 0xff); - outb(asicbase + ED_3COM_VPTR1, 0xff); - outb(asicbase + ED_3COM_VPTR0, 0x00); + bus_io_write_1(bc, ioh, asicbase + ED_3COM_VPTR2, 0xff); + bus_io_write_1(bc, ioh, asicbase + ED_3COM_VPTR1, 0xff); + bus_io_write_1(bc, ioh, asicbase + ED_3COM_VPTR0, 0x00); /* Zero memory and verify that it is clear. */ - bzero(sc->mem_start, memsize); + for (i = 0; i < memsize; ++i) + bus_mem_write_1(bc, memh, sc->mem_start + i, 0); for (i = 0; i < memsize; ++i) - if (sc->mem_start[i]) { + if (bus_mem_read_1(bc, memh, sc->mem_start + i)) { printf("%s: failed to clear shared memory at %x - check configuration\n", - sc->sc_dev.dv_xname, kvtop(sc->mem_start + i)); - return (0); + sc->sc_dev.dv_xname, + (ia->ia_maddr + sc->mem_start + i)); + goto out; } ia->ia_msize = memsize; ia->ia_iosize = ED_3COM_IO_PORTS; - return (1); + rv = 1; + + out: + /* + * XXX Sould always unmap, but we can't yet. + * XXX Need to squish "indirect" first. + */ + if (rv == 0) { + bus_io_unmap(bc, ioh, ED_3COM_IO_PORTS); + if (mapped_mem) + bus_mem_unmap(bc, memh, memsize); + } else { + /* XXX this is all "indirect" brokenness */ + sc->sc_bc = bc; + sc->sc_ioh = ioh; + sc->sc_memh = memh; + } + return (rv); } /* @@ -998,23 +1090,32 @@ ed_find_Novell(sc, cf, ia) struct cfdata *cf; struct isa_attach_args *ia; { + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + bus_mem_handle_t memh; u_int memsize, n; u_char romdata[16], isa16bit = 0, tmp; static u_char test_pattern[32] = "THIS is A memory TEST pattern"; u_char test_buffer[32]; - int asicbase, nicbase; + int rv, asicbase, nicbase; - sc->asic_base = asicbase = ia->ia_iobase + ED_NOVELL_ASIC_OFFSET; - sc->nic_base = nicbase = ia->ia_iobase + ED_NOVELL_NIC_OFFSET; + bc = ia->ia_bc; + rv = 0; + + if (bus_io_map(bc, ia->ia_iobase, ED_NOVELL_IO_PORTS, &ioh)) + return (0); + + sc->asic_base = asicbase = ED_NOVELL_ASIC_OFFSET; + sc->nic_base = nicbase = ED_NOVELL_NIC_OFFSET; /* XXX - do Novell-specific probe here */ /* Reset the board. */ #ifdef GWETHER - outb(asicbase + ED_NOVELL_RESET, 0); + bus_io_write_1(bc, ioh, asicbase + ED_NOVELL_RESET, 0); delay(200); #endif /* GWETHER */ - tmp = inb(asicbase + ED_NOVELL_RESET); + tmp = bus_io_read_1(bc, ioh, asicbase + ED_NOVELL_RESET); /* * I don't know if this is necessary; probably cruft leftover from @@ -1024,7 +1125,7 @@ ed_find_Novell(sc, cf, ia) * complete documentation on what the 'right' thing to do is...so we do * the invasive thing for now. Yuck.] */ - outb(asicbase + ED_NOVELL_RESET, tmp); + bus_io_write_1(bc, ioh, asicbase + ED_NOVELL_RESET, tmp); delay(5000); /* @@ -1033,13 +1134,14 @@ ed_find_Novell(sc, cf, ia) * XXX - this makes the probe invasive! ...Done against my better * judgement. -DLG */ - NIC_PUT(nicbase, ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STP); + NIC_PUT(bc, ioh, nicbase, ED_P0_CR, + ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STP); delay(5000); /* Make sure that we really have an 8390 based board. */ - if (!ed_probe_generic8390(nicbase)) - return (0); + if (!ed_probe_generic8390(bc, ioh, nicbase)) + goto out; sc->vendor = ED_VENDOR_NOVELL; sc->mem_shared = 0; @@ -1055,17 +1157,23 @@ ed_find_Novell(sc, cf, ia) * This prevents packets from being stored in the NIC memory when the * readmem routine turns on the start bit in the CR. */ - NIC_PUT(nicbase, ED_P0_RCR, ED_RCR_MON); + NIC_PUT(bc, ioh, nicbase, ED_P0_RCR, ED_RCR_MON); /* Temporarily initialize DCR for byte operations. */ - NIC_PUT(nicbase, ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS); + NIC_PUT(bc, ioh, nicbase, ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS); - NIC_PUT(nicbase, ED_P0_PSTART, 8192 >> ED_PAGE_SHIFT); - NIC_PUT(nicbase, ED_P0_PSTOP, 16384 >> ED_PAGE_SHIFT); + NIC_PUT(bc, ioh, nicbase, ED_P0_PSTART, 8192 >> ED_PAGE_SHIFT); + NIC_PUT(bc, ioh, nicbase, ED_P0_PSTOP, 16384 >> ED_PAGE_SHIFT); sc->isa16bit = 0; /* + * XXX indirect brokenness, used by ed_pio{read,write}mem() + */ + sc->sc_bc = bc; + sc->sc_ioh = ioh; + + /* * Write a test pattern in byte mode. If this fails, then there * probably isn't any memory at 8k - which likely means that the board * is an NE2000. @@ -1076,10 +1184,10 @@ ed_find_Novell(sc, cf, ia) if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) { /* not an NE1000 - try NE2000 */ - NIC_PUT(nicbase, ED_P0_DCR, + NIC_PUT(bc, ioh, nicbase, ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS); - NIC_PUT(nicbase, ED_P0_PSTART, 16384 >> ED_PAGE_SHIFT); - NIC_PUT(nicbase, ED_P0_PSTOP, 32768 >> ED_PAGE_SHIFT); + NIC_PUT(bc, ioh, nicbase, ED_P0_PSTART, 16384 >> ED_PAGE_SHIFT); + NIC_PUT(bc, ioh, nicbase, ED_P0_PSTOP, 32768 >> ED_PAGE_SHIFT); sc->isa16bit = 1; @@ -1091,7 +1199,7 @@ ed_find_Novell(sc, cf, ia) ed_pio_readmem(sc, 16384, test_buffer, sizeof(test_pattern)); if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) - return (0); /* not an NE2000 either */ + goto out; /* not an NE2000 either */ sc->type = ED_TYPE_NE2000; sc->type_str = "NE2000"; @@ -1103,7 +1211,7 @@ ed_find_Novell(sc, cf, ia) if (ia->ia_irq == IRQUNK) { printf("%s: %s does not have soft configuration\n", sc->sc_dev.dv_xname, sc->type_str); - return (0); + goto out; } /* 8k of memory plus an additional 8k if 16-bit. */ @@ -1117,7 +1225,7 @@ ed_find_Novell(sc, cf, ia) /* NIC memory doesn't start at zero on an NE board. */ /* The start address is tied to the bus width. */ - sc->mem_start = (caddr_t)(8192 + sc->isa16bit * 8192); + sc->mem_start = (8192 + sc->isa16bit * 8192); sc->tx_page_start = memsize >> ED_PAGE_SHIFT; #ifdef GWETHER @@ -1148,7 +1256,7 @@ ed_find_Novell(sc, cf, ia) if (mstart == 0) { printf("%s: cannot find start of RAM\n", sc->sc_dev.dv_xname); - return (0); + goto out; } /* Search for the end of RAM. */ @@ -1204,10 +1312,25 @@ ed_find_Novell(sc, cf, ia) #endif /* GWETHER */ /* Clear any pending interrupts that might have occurred above. */ - NIC_PUT(nicbase, ED_P0_ISR, 0xff); + NIC_PUT(bc, ioh, nicbase, ED_P0_ISR, 0xff); ia->ia_iosize = ED_NOVELL_IO_PORTS; - return (1); + rv = 1; + + out: + /* + * XXX Sould always unmap, but we can't yet. + * XXX Need to squish "indirect" first. + */ + if (rv == 0) + bus_io_unmap(bc, ioh, ED_NOVELL_IO_PORTS); + else { + /* XXX this is all "indirect" brokenness */ + sc->sc_bc = bc; + sc->sc_ioh = ioh; + sc->sc_memh = memh; + } + return (rv); } /* @@ -1218,12 +1341,20 @@ edattach(parent, self, aux) struct device *parent, *self; void *aux; { + bus_chipset_tag_t bc; + bus_io_handle_t ioh; struct ed_softc *sc = (void *)self; struct isa_attach_args *ia = aux; struct cfdata *cf = sc->sc_dev.dv_cfdata; struct ifnet *ifp = &sc->sc_arpcom.ac_if; int asicbase; + /* + * XXX Should re-map io and mem, but can't + * XXX until we squish "indirect" brokenness. + */ + bc = sc->sc_bc; /* XXX */ + ioh = sc->sc_ioh; /* XXX */ asicbase = sc->asic_base; @@ -1232,7 +1363,7 @@ edattach(parent, self, aux) /* Initialize ifnet structure. */ ifp->if_unit = sc->sc_dev.dv_unit; - ifp->if_name = edcd.cd_name; + ifp->if_name = ed_cd.cd_name; ifp->if_start = edstart; ifp->if_ioctl = edioctl; ifp->if_watchdog = edwatchdog; @@ -1251,7 +1382,8 @@ edattach(parent, self, aux) case ED_VENDOR_WD_SMC: if ((sc->type & ED_WD_SOFTCONFIG) == 0) break; - if ((inb(asicbase + ED_WD_IRR) & ED_WD_IRR_OUT2) == 0) + if ((bus_io_read_1(bc, ioh, asicbase + ED_WD_IRR) & + ED_WD_IRR_OUT2) == 0) ifp->if_flags |= IFF_LINK0; break; } @@ -1264,7 +1396,8 @@ edattach(parent, self, aux) ether_ifattach(ifp); /* Print additional info when attached. */ - printf(": address %s, ", ether_sprintf(sc->sc_arpcom.ac_enaddr)); + printf("\n%s: address %s, ", sc->sc_dev.dv_xname, + ether_sprintf(sc->sc_arpcom.ac_enaddr)); if (sc->type_str) printf("type %s ", sc->type_str); @@ -1293,8 +1426,8 @@ edattach(parent, self, aux) sizeof(struct ether_header)); #endif - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_NET, edintr, - sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_NET, edintr, sc, sc->sc_dev.dv_xname); sc->sc_sh = shutdownhook_establish((void (*)(void *))edstop, sc); } @@ -1320,18 +1453,22 @@ void edstop(sc) struct ed_softc *sc; { + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; int nicbase = sc->nic_base; int n = 5000; /* Stop everything on the interface, and select page 0 registers. */ - NIC_PUT(nicbase, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STP); + NIC_PUT(bc, ioh, nicbase, ED_P0_CR, + sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STP); /* * Wait for interface to enter stopped state, but limit # of checks to * 'n' (about 5ms). It shouldn't even take 5us on modern DS8390's, but * just in case it's an old one. */ - while (((NIC_GET(nicbase, ED_P0_ISR) & ED_ISR_RST) == 0) && --n); + while (((NIC_GET(bc, ioh, nicbase, + ED_P0_ISR) & ED_ISR_RST) == 0) && --n); } /* @@ -1342,7 +1479,7 @@ void edwatchdog(unit) int unit; { - struct ed_softc *sc = edcd.cd_devs[unit]; + struct ed_softc *sc = ed_cd.cd_devs[unit]; log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); ++sc->sc_arpcom.ac_if.if_oerrors; @@ -1357,6 +1494,8 @@ void edinit(sc) struct ed_softc *sc; { + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; struct ifnet *ifp = &sc->sc_arpcom.ac_if; int nicbase = sc->nic_base, asicbase = sc->asic_base; int i; @@ -1377,44 +1516,45 @@ edinit(sc) sc->txb_next_tx = 0; /* Set interface for page 0, remote DMA complete, stopped. */ - NIC_PUT(nicbase, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STP); + NIC_PUT(bc, ioh, nicbase, ED_P0_CR, + sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STP); if (sc->isa16bit) { /* * Set FIFO threshold to 8, No auto-init Remote DMA, byte * order=80x86, word-wide DMA xfers, */ - NIC_PUT(nicbase, ED_P0_DCR, + NIC_PUT(bc, ioh, nicbase, ED_P0_DCR, ED_DCR_FT1 | ED_DCR_WTS | ED_DCR_LS); } else { /* Same as above, but byte-wide DMA xfers. */ - NIC_PUT(nicbase, ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS); + NIC_PUT(bc, ioh, nicbase, ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS); } /* Clear remote byte count registers. */ - NIC_PUT(nicbase, ED_P0_RBCR0, 0); - NIC_PUT(nicbase, ED_P0_RBCR1, 0); + NIC_PUT(bc, ioh, nicbase, ED_P0_RBCR0, 0); + NIC_PUT(bc, ioh, nicbase, ED_P0_RBCR1, 0); /* Tell RCR to do nothing for now. */ - NIC_PUT(nicbase, ED_P0_RCR, ED_RCR_MON); + NIC_PUT(bc, ioh, nicbase, ED_P0_RCR, ED_RCR_MON); /* Place NIC in internal loopback mode. */ - NIC_PUT(nicbase, ED_P0_TCR, ED_TCR_LB0); + NIC_PUT(bc, ioh, nicbase, ED_P0_TCR, ED_TCR_LB0); /* Set lower bits of byte addressable framing to 0. */ if (sc->is790) - NIC_PUT(nicbase, 0x09, 0); + NIC_PUT(bc, ioh, nicbase, 0x09, 0); /* Initialize receive buffer ring. */ - NIC_PUT(nicbase, ED_P0_BNRY, sc->rec_page_start); - NIC_PUT(nicbase, ED_P0_PSTART, sc->rec_page_start); - NIC_PUT(nicbase, ED_P0_PSTOP, sc->rec_page_stop); + NIC_PUT(bc, ioh, nicbase, ED_P0_BNRY, sc->rec_page_start); + NIC_PUT(bc, ioh, nicbase, ED_P0_PSTART, sc->rec_page_start); + NIC_PUT(bc, ioh, nicbase, ED_P0_PSTOP, sc->rec_page_stop); /* * Clear all interrupts. A '1' in each bit position clears the * corresponding flag. */ - NIC_PUT(nicbase, ED_P0_ISR, 0xff); + NIC_PUT(bc, ioh, nicbase, ED_P0_ISR, 0xff); /* * Enable the following interrupts: receive/transmit complete, @@ -1422,31 +1562,34 @@ edinit(sc) * * Counter overflow and Remote DMA complete are *not* enabled. */ - NIC_PUT(nicbase, ED_P0_IMR, + NIC_PUT(bc, ioh, nicbase, ED_P0_IMR, ED_IMR_PRXE | ED_IMR_PTXE | ED_IMR_RXEE | ED_IMR_TXEE | ED_IMR_OVWE); /* Program command register for page 1. */ - NIC_PUT(nicbase, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_1 | ED_CR_STP); + NIC_PUT(bc, ioh, nicbase, ED_P0_CR, + sc->cr_proto | ED_CR_PAGE_1 | ED_CR_STP); /* Copy out our station address. */ for (i = 0; i < ETHER_ADDR_LEN; ++i) - NIC_PUT(nicbase, ED_P1_PAR0 + i, sc->sc_arpcom.ac_enaddr[i]); + NIC_PUT(bc, ioh, nicbase, ED_P1_PAR0 + i, + sc->sc_arpcom.ac_enaddr[i]); /* Set multicast filter on chip. */ ed_getmcaf(&sc->sc_arpcom, mcaf); for (i = 0; i < 8; i++) - NIC_PUT(nicbase, ED_P1_MAR0 + i, ((u_char *)mcaf)[i]); + NIC_PUT(bc, ioh, nicbase, ED_P1_MAR0 + i, ((u_char *)mcaf)[i]); /* * Set current page pointer to one page after the boundary pointer, as * recommended in the National manual. */ sc->next_packet = sc->rec_page_start + 1; - NIC_PUT(nicbase, ED_P1_CURR, sc->next_packet); + NIC_PUT(bc, ioh, nicbase, ED_P1_CURR, sc->next_packet); /* Program command register for page 0. */ - NIC_PUT(nicbase, ED_P1_CR, sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STP); + NIC_PUT(bc, ioh, nicbase, ED_P1_CR, + sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STP); i = ED_RCR_AB | ED_RCR_AM; if (ifp->if_flags & IFF_PROMISC) { @@ -1456,10 +1599,10 @@ edinit(sc) */ i |= ED_RCR_PRO | ED_RCR_AR | ED_RCR_SEP; } - NIC_PUT(nicbase, ED_P0_RCR, i); + NIC_PUT(bc, ioh, nicbase, ED_P0_RCR, i); /* Take interface out of loopback. */ - NIC_PUT(nicbase, ED_P0_TCR, 0); + NIC_PUT(bc, ioh, nicbase, ED_P0_TCR, 0); /* * If this is a 3Com board, the tranceiver must be software enabled @@ -1469,24 +1612,26 @@ edinit(sc) u_char x; case ED_VENDOR_3COM: if (ifp->if_flags & IFF_LINK0) - outb(asicbase + ED_3COM_CR, 0); + bus_io_write_1(bc, ioh, asicbase + ED_3COM_CR, 0); else - outb(asicbase + ED_3COM_CR, ED_3COM_CR_XSEL); + bus_io_write_1(bc, ioh, asicbase + ED_3COM_CR, + ED_3COM_CR_XSEL); break; case ED_VENDOR_WD_SMC: if ((sc->type & ED_WD_SOFTCONFIG) == 0) break; - x = inb(asicbase + ED_WD_IRR); + x = bus_io_read_1(bc, ioh, asicbase + ED_WD_IRR); if (ifp->if_flags & IFF_LINK0) x &= ~ED_WD_IRR_OUT2; else x |= ED_WD_IRR_OUT2; - outb(asicbase + ED_WD_IRR, x); + bus_io_write_1(bc, ioh, asicbase + ED_WD_IRR, x); break; } /* Fire up the interface. */ - NIC_PUT(nicbase, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); + NIC_PUT(bc, ioh, nicbase, ED_P0_CR, + sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); /* Set 'running' flag, and clear output active flag. */ ifp->if_flags |= IFF_RUNNING; @@ -1503,6 +1648,8 @@ static inline void ed_xmit(sc) struct ed_softc *sc; { + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; struct ifnet *ifp = &sc->sc_arpcom.ac_if; int nicbase = sc->nic_base; u_short len; @@ -1510,18 +1657,19 @@ ed_xmit(sc) len = sc->txb_len[sc->txb_next_tx]; /* Set NIC for page 0 register access. */ - NIC_PUT(nicbase, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); + NIC_PUT(bc, ioh, nicbase, ED_P0_CR, + sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); /* Set TX buffer start page. */ - NIC_PUT(nicbase, ED_P0_TPSR, sc->tx_page_start + + NIC_PUT(bc, ioh, nicbase, ED_P0_TPSR, sc->tx_page_start + sc->txb_next_tx * ED_TXBUF_SIZE); /* Set TX length. */ - NIC_PUT(nicbase, ED_P0_TBCR0, len); - NIC_PUT(nicbase, ED_P0_TBCR1, len >> 8); + NIC_PUT(bc, ioh, nicbase, ED_P0_TBCR0, len); + NIC_PUT(bc, ioh, nicbase, ED_P0_TBCR1, len >> 8); /* Set page 0, remote DMA complete, transmit packet, and *start*. */ - NIC_PUT(nicbase, ED_P0_CR, + NIC_PUT(bc, ioh, nicbase, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_0 | ED_CR_TXP | ED_CR_STA); /* Point to next transmit buffer slot and wrap if necessary. */ @@ -1546,11 +1694,13 @@ void edstart(ifp) struct ifnet *ifp; { - struct ed_softc *sc = edcd.cd_devs[ifp->if_unit]; + struct ed_softc *sc = ed_cd.cd_devs[ifp->if_unit]; + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; struct mbuf *m0, *m; - caddr_t buffer; + int buffer; int asicbase = sc->asic_base; - int len; + int len, i; if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) return; @@ -1578,7 +1728,8 @@ outloop: #endif /* txb_new points to next open buffer slot. */ - buffer = sc->mem_start + ((sc->txb_new * ED_TXBUF_SIZE) << ED_PAGE_SHIFT); + buffer = sc->mem_start + + ((sc->txb_new * ED_TXBUF_SIZE) << ED_PAGE_SHIFT); if (sc->mem_shared) { /* Special case setup for 16 bit boards... */ @@ -1590,7 +1741,8 @@ outloop: */ case ED_VENDOR_3COM: if (sc->isa16bit) - outb(asicbase + ED_3COM_GACFR, + bus_io_write_1(bc, ioh, + asicbase + ED_3COM_GACFR, ED_3COM_GACFR_RSEL); break; /* @@ -1599,17 +1751,18 @@ outloop: */ case ED_VENDOR_WD_SMC: if (sc->isa16bit) - outb(asicbase + ED_WD_LAAR, + bus_io_write_1(bc, ioh, asicbase + ED_WD_LAAR, sc->wd_laar_proto | ED_WD_LAAR_M16EN); - outb(asicbase + ED_WD_MSR, + bus_io_write_1(bc, ioh, asicbase + ED_WD_MSR, sc->wd_msr_proto | ED_WD_MSR_MENB); - (void) inb(0x84); - (void) inb(0x84); + (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ + (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ break; } for (m = m0; m != 0; m = m->m_next) { - bcopy(mtod(m, caddr_t), buffer, m->m_len); + ed_shared_writemem(sc, mtod(m, caddr_t), buffer, + m->m_len); buffer += m->m_len; } len = m0->m_pkthdr.len; @@ -1618,17 +1771,18 @@ outloop: switch (sc->vendor) { case ED_VENDOR_3COM: if (sc->isa16bit) - outb(asicbase + ED_3COM_GACFR, + bus_io_write_1(bc, ioh, + asicbase + ED_3COM_GACFR, ED_3COM_GACFR_RSEL | ED_3COM_GACFR_MBS0); break; case ED_VENDOR_WD_SMC: - outb(asicbase + ED_WD_MSR, + bus_io_write_1(bc, ioh, asicbase + ED_WD_MSR, sc->wd_msr_proto); if (sc->isa16bit) - outb(asicbase + ED_WD_LAAR, + bus_io_write_1(bc, ioh, asicbase + ED_WD_LAAR, sc->wd_laar_proto); - (void) inb(0x84); - (void) inb(0x84); + (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ + (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ break; } } else @@ -1657,16 +1811,19 @@ static inline void ed_rint(sc) struct ed_softc *sc; { + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; int nicbase = sc->nic_base; u_char boundary, current; u_short len; u_char nlen; struct ed_ring packet_hdr; - caddr_t packet_ptr; + int packet_ptr; loop: /* Set NIC to page 1 registers to get 'current' pointer. */ - NIC_PUT(nicbase, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_1 | ED_CR_STA); + NIC_PUT(bc, ioh, nicbase, ED_P0_CR, + sc->cr_proto | ED_CR_PAGE_1 | ED_CR_STA); /* * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e. @@ -1676,12 +1833,13 @@ loop: * until the logical beginning equals the logical end (or in other * words, until the ring-buffer is empty). */ - current = NIC_GET(nicbase, ED_P1_CURR); + current = NIC_GET(bc, ioh, nicbase, ED_P1_CURR); if (sc->next_packet == current) return; /* Set NIC to page 0 registers to update boundary register. */ - NIC_PUT(nicbase, ED_P1_CR, sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); + NIC_PUT(bc, ioh, nicbase, ED_P1_CR, + sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); do { /* Get pointer to this buffer's header structure. */ @@ -1693,7 +1851,8 @@ loop: * the NIC. */ if (sc->mem_shared) - packet_hdr = *(struct ed_ring *)packet_ptr; + ed_shared_readmem(sc, packet_ptr, (caddr_t)&packet_hdr, + sizeof(packet_hdr)); else ed_pio_readmem(sc, (long)packet_ptr, (caddr_t) &packet_hdr, sizeof(packet_hdr)); @@ -1761,7 +1920,7 @@ loop: boundary = sc->next_packet - 1; if (boundary < sc->rec_page_start) boundary = sc->rec_page_stop - 1; - NIC_PUT(nicbase, ED_P0_BNRY, boundary); + NIC_PUT(bc, ioh, nicbase, ED_P0_BNRY, boundary); } while (sc->next_packet != current); goto loop; @@ -1773,14 +1932,17 @@ edintr(arg) void *arg; { struct ed_softc *sc = arg; + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; struct ifnet *ifp = &sc->sc_arpcom.ac_if; int nicbase = sc->nic_base, asicbase = sc->asic_base; u_char isr; /* Set NIC to page 0 registers. */ - NIC_PUT(nicbase, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); + NIC_PUT(bc, ioh, nicbase, ED_P0_CR, + sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); - isr = NIC_GET(nicbase, ED_P0_ISR); + isr = NIC_GET(bc, ioh, nicbase, ED_P0_ISR); if (!isr) return (0); @@ -1791,14 +1953,15 @@ edintr(arg) * '1' to each bit position that was set. * (Writing a '1' *clears* the bit.) */ - NIC_PUT(nicbase, ED_P0_ISR, isr); + NIC_PUT(bc, ioh, nicbase, ED_P0_ISR, isr); /* * Handle transmitter interrupts. Handle these first because * the receiver will reset the board under some conditions. */ if (isr & (ED_ISR_PTX | ED_ISR_TXE)) { - u_char collisions = NIC_GET(nicbase, ED_P0_NCR) & 0x0f; + u_char collisions = NIC_GET(bc, ioh, nicbase, + ED_P0_NCR) & 0x0f; /* * Check for transmit error. If a TX completed with an @@ -1809,13 +1972,13 @@ edintr(arg) * course, with UDP we're screwed, but this is expected * when a network is heavily loaded. */ - (void) NIC_GET(nicbase, ED_P0_TSR); + (void) NIC_GET(bc, ioh, nicbase, ED_P0_TSR); if (isr & ED_ISR_TXE) { /* * Excessive collisions (16). */ - if ((NIC_GET(nicbase, ED_P0_TSR) & ED_TSR_ABT) - && (collisions == 0)) { + if ((NIC_GET(bc, ioh, nicbase, ED_P0_TSR) & + ED_TSR_ABT) && (collisions == 0)) { /* * When collisions total 16, the P0_NCR * will indicate 0, and the TSR_ABT is @@ -1907,25 +2070,32 @@ edintr(arg) */ if (sc->vendor == ED_VENDOR_WD_SMC) { if (sc->isa16bit) - outb(asicbase + ED_WD_LAAR, - sc->wd_laar_proto | ED_WD_LAAR_M16EN); - outb(asicbase + ED_WD_MSR, + bus_io_write_1(bc, ioh, + asicbase + ED_WD_LAAR, + sc->wd_laar_proto | + ED_WD_LAAR_M16EN); + bus_io_write_1(bc, ioh, + asicbase + ED_WD_MSR, sc->wd_msr_proto | ED_WD_MSR_MENB); - (void) inb(0x84); - (void) inb(0x84); + /* XXX */ + (void) bus_io_read_1(bc, ioh, 0x84); + (void) bus_io_read_1(bc, ioh, 0x84); } ed_rint(sc); /* Disable 16-bit access. */ if (sc->vendor == ED_VENDOR_WD_SMC) { - outb(asicbase + ED_WD_MSR, + bus_io_write_1(bc, ioh, + asicbase + ED_WD_MSR, sc->wd_msr_proto); if (sc->isa16bit) - outb(asicbase + ED_WD_LAAR, + bus_io_write_1(bc, ioh, + asicbase + ED_WD_LAAR, sc->wd_laar_proto); - (void) inb(0x84); - (void) inb(0x84); + /* XXX */ + (void) bus_io_read_1(bc, ioh, 0x84); + (void) bus_io_read_1(bc, ioh, 0x84); } } } @@ -1943,7 +2113,7 @@ edintr(arg) * set in the transmit routine, is *okay* - it is 'edge' * triggered from low to high). */ - NIC_PUT(nicbase, ED_P0_CR, + NIC_PUT(bc, ioh, nicbase, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); /* @@ -1952,12 +2122,12 @@ edintr(arg) * otherwise - resulting in an infinite loop. */ if (isr & ED_ISR_CNT) { - (void) NIC_GET(nicbase, ED_P0_CNTR0); - (void) NIC_GET(nicbase, ED_P0_CNTR1); - (void) NIC_GET(nicbase, ED_P0_CNTR2); + (void) NIC_GET(bc, ioh, nicbase, ED_P0_CNTR0); + (void) NIC_GET(bc, ioh, nicbase, ED_P0_CNTR1); + (void) NIC_GET(bc, ioh, nicbase, ED_P0_CNTR2); } - isr = NIC_GET(nicbase, ED_P0_ISR); + isr = NIC_GET(bc, ioh, nicbase, ED_P0_ISR); if (!isr) return (1); } @@ -1972,7 +2142,7 @@ edioctl(ifp, cmd, data) u_long cmd; caddr_t data; { - struct ed_softc *sc = edcd.cd_devs[ifp->if_unit]; + struct ed_softc *sc = ed_cd.cd_devs[ifp->if_unit]; register struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; @@ -2081,8 +2251,7 @@ edioctl(ifp, cmd, data) void edread(sc, buf, len) struct ed_softc *sc; - caddr_t buf; - int len; + int buf, len; { struct ifnet *ifp = &sc->sc_arpcom.ac_if; struct mbuf *m; @@ -2145,29 +2314,35 @@ ed_pio_readmem(sc, src, dst, amount) caddr_t dst; u_short amount; { + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; int nicbase = sc->nic_base; /* Select page 0 registers. */ - NIC_PUT(nicbase, ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STA); + NIC_PUT(bc, ioh, nicbase, ED_P0_CR, + ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STA); /* Round up to a word. */ if (amount & 1) ++amount; /* Set up DMA byte count. */ - NIC_PUT(nicbase, ED_P0_RBCR0, amount); - NIC_PUT(nicbase, ED_P0_RBCR1, amount >> 8); + NIC_PUT(bc, ioh, nicbase, ED_P0_RBCR0, amount); + NIC_PUT(bc, ioh, nicbase, ED_P0_RBCR1, amount >> 8); /* Set up source address in NIC mem. */ - NIC_PUT(nicbase, ED_P0_RSAR0, src); - NIC_PUT(nicbase, ED_P0_RSAR1, src >> 8); + NIC_PUT(bc, ioh, nicbase, ED_P0_RSAR0, src); + NIC_PUT(bc, ioh, nicbase, ED_P0_RSAR1, src >> 8); - NIC_PUT(nicbase, ED_P0_CR, ED_CR_RD0 | ED_CR_PAGE_0 | ED_CR_STA); + NIC_PUT(bc, ioh, nicbase, ED_P0_CR, + ED_CR_RD0 | ED_CR_PAGE_0 | ED_CR_STA); if (sc->isa16bit) - insw(sc->asic_base + ED_NOVELL_DATA, dst, amount / 2); + bus_io_read_multi_2(bc, ioh, sc->asic_base + ED_NOVELL_DATA, + dst, amount / 2); else - insb(sc->asic_base + ED_NOVELL_DATA, dst, amount); + bus_io_read_multi_1(bc, ioh, sc->asic_base + ED_NOVELL_DATA, + dst, amount); } /* @@ -2181,30 +2356,36 @@ ed_pio_writemem(sc, src, dst, len) u_short dst; u_short len; { + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; int nicbase = sc->nic_base; int maxwait = 100; /* about 120us */ /* Select page 0 registers. */ - NIC_PUT(nicbase, ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STA); + NIC_PUT(bc, ioh, nicbase, ED_P0_CR, + ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STA); /* Reset remote DMA complete flag. */ - NIC_PUT(nicbase, ED_P0_ISR, ED_ISR_RDC); + NIC_PUT(bc, ioh, nicbase, ED_P0_ISR, ED_ISR_RDC); /* Set up DMA byte count. */ - NIC_PUT(nicbase, ED_P0_RBCR0, len); - NIC_PUT(nicbase, ED_P0_RBCR1, len >> 8); + NIC_PUT(bc, ioh, nicbase, ED_P0_RBCR0, len); + NIC_PUT(bc, ioh, nicbase, ED_P0_RBCR1, len >> 8); /* Set up destination address in NIC mem. */ - NIC_PUT(nicbase, ED_P0_RSAR0, dst); - NIC_PUT(nicbase, ED_P0_RSAR1, dst >> 8); + NIC_PUT(bc, ioh, nicbase, ED_P0_RSAR0, dst); + NIC_PUT(bc, ioh, nicbase, ED_P0_RSAR1, dst >> 8); /* Set remote DMA write. */ - NIC_PUT(nicbase, ED_P0_CR, ED_CR_RD1 | ED_CR_PAGE_0 | ED_CR_STA); + NIC_PUT(bc, ioh, nicbase, ED_P0_CR, + ED_CR_RD1 | ED_CR_PAGE_0 | ED_CR_STA); if (sc->isa16bit) - outsw(sc->asic_base + ED_NOVELL_DATA, src, len / 2); + bus_io_write_multi_2(bc, ioh, sc->asic_base + ED_NOVELL_DATA, + src, len / 2); else - outsb(sc->asic_base + ED_NOVELL_DATA, src, len); + bus_io_write_multi_1(bc, ioh, sc->asic_base + ED_NOVELL_DATA, + src, len); /* * Wait for remote DMA complete. This is necessary because on the @@ -2213,8 +2394,8 @@ ed_pio_writemem(sc, src, dst, len) * waiting causes really bad things to happen - like the NIC * irrecoverably jamming the ISA bus. */ - while (((NIC_GET(nicbase, ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && - --maxwait); + while (((NIC_GET(bc, ioh, nicbase, ED_P0_ISR) & ED_ISR_RDC) != + ED_ISR_RDC) && --maxwait); } /* @@ -2227,6 +2408,8 @@ ed_pio_write_mbufs(sc, m, dst) struct mbuf *m; u_short dst; { + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; int nicbase = sc->nic_base, asicbase = sc->asic_base; u_short len; struct mbuf *mp; @@ -2235,21 +2418,23 @@ ed_pio_write_mbufs(sc, m, dst) len = m->m_pkthdr.len; /* Select page 0 registers. */ - NIC_PUT(nicbase, ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STA); + NIC_PUT(bc, ioh, nicbase, ED_P0_CR, + ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STA); /* Reset remote DMA complete flag. */ - NIC_PUT(nicbase, ED_P0_ISR, ED_ISR_RDC); + NIC_PUT(bc, ioh, nicbase, ED_P0_ISR, ED_ISR_RDC); /* Set up DMA byte count. */ - NIC_PUT(nicbase, ED_P0_RBCR0, len); - NIC_PUT(nicbase, ED_P0_RBCR1, len >> 8); + NIC_PUT(bc, ioh, nicbase, ED_P0_RBCR0, len); + NIC_PUT(bc, ioh, nicbase, ED_P0_RBCR1, len >> 8); /* Set up destination address in NIC mem. */ - NIC_PUT(nicbase, ED_P0_RSAR0, dst); - NIC_PUT(nicbase, ED_P0_RSAR1, dst >> 8); + NIC_PUT(bc, ioh, nicbase, ED_P0_RSAR0, dst); + NIC_PUT(bc, ioh, nicbase, ED_P0_RSAR1, dst >> 8); /* Set remote DMA write. */ - NIC_PUT(nicbase, ED_P0_CR, ED_CR_RD1 | ED_CR_PAGE_0 | ED_CR_STA); + NIC_PUT(bc, ioh, nicbase, ED_P0_CR, + ED_CR_RD1 | ED_CR_PAGE_0 | ED_CR_STA); /* * Transfer the mbuf chain to the NIC memory. @@ -2261,13 +2446,14 @@ ed_pio_write_mbufs(sc, m, dst) /* NE1000s are easy. */ for (; m != 0; m = m->m_next) { if (m->m_len) { - outsb(asicbase + ED_NOVELL_DATA, + bus_io_write_multi_1(bc, ioh, + asicbase + ED_NOVELL_DATA, mtod(m, u_char *), m->m_len); } } } else { /* NE2000s are a bit trickier. */ - u_char *data, savebyte[2]; + u_int8_t *data, savebyte[2]; int len, wantbyte; wantbyte = 0; @@ -2275,20 +2461,23 @@ ed_pio_write_mbufs(sc, m, dst) len = m->m_len; if (len == 0) continue; - data = mtod(m, u_char *); + data = mtod(m, u_int8_t *); /* Finish the last word. */ if (wantbyte) { savebyte[1] = *data; - outw(asicbase + ED_NOVELL_DATA, - *(u_short *)savebyte); + bus_io_write_2(bc, ioh, + asicbase + ED_NOVELL_DATA, + *(u_int16_t *)savebyte); data++; len--; wantbyte = 0; } /* Output contiguous words. */ - if (len > 1) - outsw(asicbase + ED_NOVELL_DATA, + if (len > 1) { + bus_io_write_multi_2(bc, ioh, + asicbase + ED_NOVELL_DATA, data, len >> 1); + } /* Save last byte, if necessary. */ if (len & 1) { data += len & ~1; @@ -2299,7 +2488,8 @@ ed_pio_write_mbufs(sc, m, dst) if (wantbyte) { savebyte[1] = 0; - outw(asicbase + ED_NOVELL_DATA, *(u_short *)savebyte); + bus_io_write_2(bc, ioh, asicbase + ED_NOVELL_DATA, + *(u_int16_t *)savebyte); } } @@ -2310,8 +2500,8 @@ ed_pio_write_mbufs(sc, m, dst) * waiting causes really bad things to happen - like the NIC * irrecoverably jamming the ISA bus. */ - while (((NIC_GET(nicbase, ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && - --maxwait); + while (((NIC_GET(bc, ioh, nicbase, ED_P0_ISR) & ED_ISR_RDC) != + ED_ISR_RDC) && --maxwait); if (!maxwait) { log(LOG_WARNING, @@ -2327,10 +2517,11 @@ ed_pio_write_mbufs(sc, m, dst) * Given a source and destination address, copy 'amount' of a packet from the * ring buffer into a linear destination buffer. Takes into account ring-wrap. */ -static inline caddr_t +static inline int ed_ring_copy(sc, src, dst, amount) struct ed_softc *sc; - caddr_t src, dst; + int src; + caddr_t dst; u_short amount; { u_short tmp_amount; @@ -2341,7 +2532,7 @@ ed_ring_copy(sc, src, dst, amount) /* Copy amount up to end of NIC memory. */ if (sc->mem_shared) - bcopy(src, dst, tmp_amount); + ed_shared_readmem(sc, src, dst, tmp_amount); else ed_pio_readmem(sc, (long)src, dst, tmp_amount); @@ -2351,7 +2542,7 @@ ed_ring_copy(sc, src, dst, amount) } if (sc->mem_shared) - bcopy(src, dst, amount); + ed_shared_readmem(sc, src, dst, amount); else ed_pio_readmem(sc, (long)src, dst, amount); @@ -2369,7 +2560,7 @@ ed_ring_copy(sc, src, dst, amount) struct mbuf * edget(sc, src, total_len) struct ed_softc *sc; - caddr_t src; + int src; u_short total_len; { struct ifnet *ifp = &sc->sc_arpcom.ac_if; @@ -2480,3 +2671,37 @@ ed_getmcaf(ac, af) } ifp->if_flags &= ~IFF_ALLMULTI; } + +void +ed_shared_writemem(sc, buf, card, len) + struct ed_softc *sc; + caddr_t buf; + int card, len; +{ + bus_chipset_tag_t bc = sc->sc_bc; + bus_mem_handle_t memh = sc->sc_memh; + u_int8_t *ptr = (u_int8_t *)buf; + int i; + + /* XXX should have bus_mem_copyout_{1,2,4,8}() */ + + for (i = 0; i < len; ++i) + bus_mem_write_1(bc, memh, card + i, ptr[i]); +} + +void +ed_shared_readmem(sc, card, buf, len) + struct ed_softc *sc; + caddr_t buf; + int card, len; +{ + bus_chipset_tag_t bc = sc->sc_bc; + bus_mem_handle_t memh = sc->sc_memh; + u_int8_t *ptr = (u_int8_t *)buf; + int i; + + /* XXX should have bus_mem_copyin_{1,2,4,8}() */ + + for (i = 0; i < len; ++i) + ptr[i] = bus_mem_read_1(bc, memh, card + i); +} diff --git a/sys/dev/isa/if_eg.c b/sys/dev/isa/if_eg.c index 3ecd3de9390..6a52e9d6f55 100644 --- a/sys/dev/isa/if_eg.c +++ b/sys/dev/isa/if_eg.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_eg.c,v 1.22 1996/01/10 18:21:52 hpeyerl Exp $ */ +/* $NetBSD: if_eg.c,v 1.24 1996/04/11 22:29:03 cgd Exp $ */ /* * Copyright (c) 1993 Dean Huxley <dean@fsa.ca> @@ -117,8 +117,12 @@ struct eg_softc { int egprobe __P((struct device *, void *, void *)); void egattach __P((struct device *, struct device *, void *)); -struct cfdriver egcd = { - NULL, "eg", egprobe, egattach, DV_IFNET, sizeof(struct eg_softc) +struct cfattach eg_ca = { + sizeof(struct eg_softc), egprobe, egattach +}; + +struct cfdriver eg_cd = { + NULL, "eg", DV_IFNET }; int egintr __P((void *)); @@ -398,7 +402,7 @@ egattach(parent, self, aux) /* Initialize ifnet structure. */ ifp->if_unit = sc->sc_dev.dv_unit; - ifp->if_name = egcd.cd_name; + ifp->if_name = eg_cd.cd_name; ifp->if_start = egstart; ifp->if_ioctl = egioctl; ifp->if_watchdog = egwatchdog; @@ -412,8 +416,8 @@ egattach(parent, self, aux) bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); #endif - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_NET, egintr, - sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_NET, egintr, sc, sc->sc_dev.dv_xname); } void @@ -490,7 +494,7 @@ void egstart(ifp) struct ifnet *ifp; { - register struct eg_softc *sc = egcd.cd_devs[ifp->if_unit]; + register struct eg_softc *sc = eg_cd.cd_devs[ifp->if_unit]; struct mbuf *m0, *m; caddr_t buffer; int len; @@ -729,7 +733,7 @@ egioctl(ifp, cmd, data) u_long cmd; caddr_t data; { - struct eg_softc *sc = egcd.cd_devs[ifp->if_unit]; + struct eg_softc *sc = eg_cd.cd_devs[ifp->if_unit]; struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; @@ -826,7 +830,7 @@ void egwatchdog(unit) int unit; { - struct eg_softc *sc = egcd.cd_devs[unit]; + struct eg_softc *sc = eg_cd.cd_devs[unit]; log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); sc->sc_arpcom.ac_if.if_oerrors++; diff --git a/sys/dev/isa/if_el.c b/sys/dev/isa/if_el.c index b7f889b7c22..ea751159744 100644 --- a/sys/dev/isa/if_el.c +++ b/sys/dev/isa/if_el.c @@ -1,5 +1,5 @@ -/* $OpenBSD: if_el.c,v 1.6 1996/03/20 01:00:48 mickey Exp $ */ -/* $NetBSD: if_el.c,v 1.34 1995/12/24 02:31:25 mycroft Exp $ */ +/* $OpenBSD: if_el.c,v 1.7 1996/04/21 22:23:48 deraadt Exp $ */ +/* $NetBSD: if_el.c,v 1.36 1996/04/11 22:29:07 cgd Exp $ */ /* * Copyright (c) 1994, Matthew E. Kimmel. Permission is hereby granted @@ -97,9 +97,12 @@ static inline void el_hardreset __P((struct el_softc *)); int elprobe __P((struct device *, void *, void *)); void elattach __P((struct device *, struct device *, void *)); -/* isa_driver structure for autoconf */ -struct cfdriver elcd = { - NULL, "el", elprobe, elattach, DV_IFNET, sizeof(struct el_softc) +struct cfattach el_ca = { + sizeof(struct el_softc), elprobe, elattach +}; + +struct cfdriver el_cd = { + NULL, "el", DV_IFNET }; /* @@ -186,7 +189,7 @@ elattach(parent, self, aux) /* Initialize ifnet structure. */ ifp->if_unit = sc->sc_dev.dv_unit; - ifp->if_name = elcd.cd_name; + ifp->if_name = el_cd.cd_name; ifp->if_start = elstart; ifp->if_ioctl = elioctl; ifp->if_watchdog = elwatchdog; @@ -206,8 +209,8 @@ elattach(parent, self, aux) bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); #endif - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_NET, elintr, - sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_NET, elintr, sc, sc->sc_dev.dv_xname); dprintf(("elattach() finished.\n")); } @@ -304,7 +307,7 @@ void elstart(ifp) struct ifnet *ifp; { - struct el_softc *sc = elcd.cd_devs[ifp->if_unit]; + struct el_softc *sc = el_cd.cd_devs[ifp->if_unit]; int iobase = sc->sc_iobase; struct mbuf *m, *m0; int s, i, off, retries; @@ -616,7 +619,7 @@ elioctl(ifp, cmd, data) u_long cmd; caddr_t data; { - struct el_softc *sc = elcd.cd_devs[ifp->if_unit]; + struct el_softc *sc = el_cd.cd_devs[ifp->if_unit]; struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; @@ -700,7 +703,7 @@ void elwatchdog(unit) int unit; { - struct el_softc *sc = elcd.cd_devs[unit]; + struct el_softc *sc = el_cd.cd_devs[unit]; log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); sc->sc_arpcom.ac_if.if_oerrors++; diff --git a/sys/dev/isa/if_ep.c b/sys/dev/isa/if_ep.c index 887bb575548..4102ad294e4 100644 --- a/sys/dev/isa/if_ep.c +++ b/sys/dev/isa/if_ep.c @@ -1,5 +1,5 @@ -/* $OpenBSD: if_ep.c,v 1.10 1996/04/18 23:47:40 niklas Exp $ */ -/* $NetBSD: if_ep.c,v 1.87 1996/02/19 20:18:40 christos Exp $ */ +/* $OpenBSD: if_ep.c,v 1.11 1996/04/21 22:23:52 deraadt Exp $ */ +/* $NetBSD: if_ep.c,v 1.90 1996/04/11 22:29:15 cgd Exp $ */ /* * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca> @@ -31,7 +31,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "pcmciabus.h" +/*#include "pcmciabus.h"*/ #include "bpfilter.h" #include <sys/param.h> @@ -119,8 +119,17 @@ struct ep_softc { static int epprobe __P((struct device *, void *, void *)); static void epattach __P((struct device *, struct device *, void *)); -struct cfdriver epcd = { - NULL, "ep", epprobe, epattach, DV_IFNET, sizeof(struct ep_softc) +/* XXX the following two structs should be different. */ +struct cfattach ep_isa_ca = { + sizeof(struct ep_softc), epprobe, epattach +}; + +struct cfattach ep_pci_ca = { + sizeof(struct ep_softc), epprobe, epattach +}; + +struct cfdriver ep_cd = { + NULL, "ep", DV_IFNET }; int epintr __P((void *)); @@ -326,9 +335,9 @@ epprobe(parent, match, aux) int k, k2; #if NPCI > 0 - extern struct cfdriver pcicd; + extern struct cfdriver pci_cd; - if (parent->dv_cfdata->cf_driver == &pcicd) { + if (parent->dv_cfdata->cf_driver == &pci_cd) { struct pci_attach_args *pa = (struct pci_attach_args *) aux; if (PCI_VENDORID(pa->pa_id) != PCI_VENDOR_3COM) @@ -497,7 +506,7 @@ epconfig(sc, conn) printf(" address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr)); ifp->if_unit = sc->sc_dev.dv_unit; - ifp->if_name = epcd.cd_name; + ifp->if_name = ep_cd.cd_name; ifp->if_start = epstart; ifp->if_ioctl = epioctl; ifp->if_watchdog = epwatchdog; @@ -523,9 +532,9 @@ epattach(parent, self, aux) struct ep_softc *sc = (void *)self; u_short conn = 0; #if NPCI > 0 - extern struct cfdriver pcicd; + extern struct cfdriver pci_cd; - if (parent->dv_cfdata->cf_driver == &pcicd) { + if (parent->dv_cfdata->cf_driver == &pci_cd) { struct pci_attach_args *pa = aux; int iobase; u_short i; @@ -536,7 +545,7 @@ epattach(parent, self, aux) } sc->bustype = EP_BUS_PCI; sc->ep_iobase = iobase; /* & 0xfffffff0 */ - i = pci_conf_read(pa->pa_tag, PCI_CONN); + i = pci_conf_read(pa->pa_bc, pa->pa_tag, PCI_CONN); /* * Bits 13,12,9 of the isa adapter are the same as bits @@ -565,16 +574,15 @@ epattach(parent, self, aux) #if NPCI > 0 - if (parent->dv_cfdata->cf_driver == &pcicd) { + if (parent->dv_cfdata->cf_driver == &pci_cd) { struct pci_attach_args *pa = aux; - pci_conf_write(pa->pa_tag, PCI_COMMAND_STATUS_REG, - pci_conf_read(pa->pa_tag, + pci_conf_write(pa->pa_bc, pa->pa_tag, PCI_COMMAND_STATUS_REG, + pci_conf_read(pa->pa_bc, pa->pa_tag, PCI_COMMAND_STATUS_REG) | PCI_COMMAND_MASTER_ENABLE); - sc->sc_ih = pci_map_int(pa->pa_tag, IPL_NET, epintr, sc, - sc->sc_dev.dv_xname); + sc->sc_ih = pci_map_int(pa->pa_tag, IPL_NET, epintr, sc); if (sc->sc_ih == NULL) { printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname); @@ -586,8 +594,8 @@ epattach(parent, self, aux) #endif { struct isa_attach_args *ia = aux; - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_NET, - epintr, sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, + IST_EDGE, IPL_NET, epintr, sc, sc->sc_dev.dv_xname); } } @@ -721,7 +729,7 @@ void epstart(ifp) struct ifnet *ifp; { - register struct ep_softc *sc = epcd.cd_devs[ifp->if_unit]; + register struct ep_softc *sc = ep_cd.cd_devs[ifp->if_unit]; struct mbuf *m, *m0; int sh, len, pad; @@ -1205,7 +1213,7 @@ epioctl(ifp, cmd, data) u_long cmd; caddr_t data; { - struct ep_softc *sc = epcd.cd_devs[ifp->if_unit]; + struct ep_softc *sc = ep_cd.cd_devs[ifp->if_unit]; struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; @@ -1315,7 +1323,7 @@ void epwatchdog(unit) int unit; { - struct ep_softc *sc = epcd.cd_devs[unit]; + struct ep_softc *sc = ep_cd.cd_devs[unit]; log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); ++sc->sc_arpcom.ac_if.if_oerrors; diff --git a/sys/dev/isa/if_fe.c b/sys/dev/isa/if_fe.c index 6201923066a..3c8a4f7ae91 100644 --- a/sys/dev/isa/if_fe.c +++ b/sys/dev/isa/if_fe.c @@ -227,8 +227,12 @@ void fe_loadmar __P((struct fe_softc *)); void fe_dump __P((int, struct fe_softc *)); #endif -struct cfdriver fecd = { - NULL, "fe", feprobe, feattach, DV_IFNET, sizeof(struct fe_softc) +struct cfattach fe_ca = { + sizeof(struct fe_softc), feprobe, feattach +}; + +struct cfdriver fe_cd = { + NULL, "fe", DV_IFNET }; /* Ethernet constants. To be defined in if_ehter.h? FIXME. */ @@ -993,7 +997,7 @@ feattach(parent, self, aux) /* Initialize ifnet structure. */ ifp->if_unit = sc->sc_dev.dv_unit; - ifp->if_name = fecd.cd_name; + ifp->if_name = fe_cd.cd_name; ifp->if_start = fe_start; ifp->if_ioctl = fe_ioctl; ifp->if_watchdog = fe_watchdog; @@ -1124,8 +1128,8 @@ feattach(parent, self, aux) bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); #endif - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_NET, feintr, - sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_NET, feintr, sc, sc->sc_dev.dv_xname); } /* @@ -1198,7 +1202,7 @@ void fe_watchdog(unit) int unit; { - struct fe_softc *sc = fecd.cd_devs[unit]; + struct fe_softc *sc = fe_cd.cd_devs[unit]; log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); #if FE_DEBUG >= 3 @@ -1420,7 +1424,7 @@ void fe_start(ifp) struct ifnet *ifp; { - struct fe_softc *sc = fecd.cd_devs[ifp->if_unit]; + struct fe_softc *sc = fe_cd.cd_devs[ifp->if_unit]; struct mbuf *m; #if FE_DEBUG >= 1 @@ -1679,7 +1683,9 @@ fe_tint(sc, tstat) */ ifp->if_opackets += sc->txb_sched; sc->txb_sched = 0; + } + if (sc->txb_sched == 0) { /* * The transmitter is no more active. * Reset output active flag and watchdog timer. @@ -1919,7 +1925,7 @@ fe_ioctl(ifp, command, data) u_long command; caddr_t data; { - struct fe_softc *sc = fecd.cd_devs[ifp->if_unit]; + struct fe_softc *sc = fe_cd.cd_devs[ifp->if_unit]; register struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; diff --git a/sys/dev/isa/if_ie.c b/sys/dev/isa/if_ie.c index 033d71b7bf3..49cd7b27064 100644 --- a/sys/dev/isa/if_ie.c +++ b/sys/dev/isa/if_ie.c @@ -1,5 +1,5 @@ -/* $OpenBSD: if_ie.c,v 1.6 1996/03/20 01:00:52 mickey Exp $ */ -/* $NetBSD: if_ie.c,v 1.45 1995/12/24 02:31:33 mycroft Exp $ */ +/* $OpenBSD: if_ie.c,v 1.7 1996/04/21 22:24:03 deraadt Exp $ */ +/* $NetBSD: if_ie.c,v 1.47 1996/04/11 22:29:27 cgd Exp $ */ /*- * Copyright (c) 1993, 1994, 1995 Charles Hannum. @@ -310,8 +310,12 @@ int in_ietint = 0; int ieprobe __P((struct device *, void *, void *)); void ieattach __P((struct device *, struct device *, void *)); -struct cfdriver iecd = { - NULL, "ie", ieprobe, ieattach, DV_IFNET, sizeof(struct ie_softc) +struct cfattach ie_ca = { + sizeof(struct ie_softc), ieprobe, ieattach +}; + +struct cfdriver ie_cd = { + NULL, "ie", DV_IFNET }; #define MK_24(base, ptr) ((caddr_t)((u_long)ptr - (u_long)base)) @@ -757,7 +761,7 @@ ieattach(parent, self, aux) struct ifnet *ifp = &sc->sc_arpcom.ac_if; ifp->if_unit = sc->sc_dev.dv_unit; - ifp->if_name = iecd.cd_name; + ifp->if_name = ie_cd.cd_name; ifp->if_start = iestart; ifp->if_ioctl = ieioctl; ifp->if_watchdog = iewatchdog; @@ -777,8 +781,8 @@ ieattach(parent, self, aux) sizeof(struct ether_header)); #endif - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_NET, ieintr, - sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_NET, ieintr, sc, sc->sc_dev.dv_xname); } /* @@ -789,7 +793,7 @@ void iewatchdog(unit) int unit; { - struct ie_softc *sc = iecd.cd_devs[unit]; + struct ie_softc *sc = ie_cd.cd_devs[unit]; log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); ++sc->sc_arpcom.ac_if.if_oerrors; @@ -1441,7 +1445,7 @@ void iestart(ifp) struct ifnet *ifp; { - struct ie_softc *sc = iecd.cd_devs[ifp->if_unit]; + struct ie_softc *sc = ie_cd.cd_devs[ifp->if_unit]; struct mbuf *m0, *m; u_char *buffer; u_short len; @@ -2111,7 +2115,7 @@ ieioctl(ifp, cmd, data) u_long cmd; caddr_t data; { - struct ie_softc *sc = iecd.cd_devs[ifp->if_unit]; + struct ie_softc *sc = ie_cd.cd_devs[ifp->if_unit]; struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; diff --git a/sys/dev/isa/if_le.c b/sys/dev/isa/if_le.c index 61c47031e92..b6016b092cd 100644 --- a/sys/dev/isa/if_le.c +++ b/sys/dev/isa/if_le.c @@ -1,5 +1,5 @@ -/* $OpenBSD: if_le.c,v 1.7 1996/03/20 01:00:54 mickey Exp $ */ -/* $NetBSD: if_le.c,v 1.38 1995/12/24 02:31:35 mycroft Exp $ */ +/* $OpenBSD: if_le.c,v 1.8 1996/04/21 22:24:09 deraadt Exp $ */ +/* $NetBSD: if_le.c,v 1.41 1996/04/11 22:29:34 cgd Exp $ */ /*- * Copyright (c) 1995 Charles M. Hannum. All rights reserved. @@ -83,7 +83,7 @@ char *card_type[] = {"unknown", "BICC Isolan", "NE2100", "DEPCA", "PCnet-ISA", "PCnet-PCI"}; -#define LE_SOFTC(unit) lecd.cd_devs[unit] +#define LE_SOFTC(unit) le_cd.cd_devs[unit] #define LE_DELAY(x) delay(x) int leprobe __P((struct device *, void *, void *)); @@ -96,8 +96,17 @@ int leintr __P((void *)); int leintredge __P((void *)); void leshutdown __P((void *)); -struct cfdriver lecd = { - NULL, "le", leprobe, leattach, DV_IFNET, sizeof(struct le_softc) +/* XXX the following two structs should be different. */ +struct cfattach le_isa_ca = { + sizeof(struct le_softc), leprobe, leattach +}; + +struct cfattach le_pci_ca = { + sizeof(struct le_softc), leprobe, leattach +}; + +struct cfdriver le_cd = { + NULL, "le", DV_IFNET }; integrate void @@ -128,10 +137,10 @@ leprobe(parent, match, aux) void *match, *aux; { struct le_softc *sc = match; - extern struct cfdriver isacd, pcicd; + extern struct cfdriver isa_cd, pci_cd; #if NISA > 0 - if (parent->dv_cfdata->cf_driver == &isacd) { + if (parent->dv_cfdata->cf_driver == &isa_cd) { struct isa_attach_args *ia = aux; if (bicc_probe(sc, ia)) @@ -144,7 +153,7 @@ leprobe(parent, match, aux) #endif #if NPCI > 0 - if (parent->dv_cfdata->cf_driver == &pcicd) { + if (parent->dv_cfdata->cf_driver == &pci_cd) { struct pci_attach_args *pa = aux; if (pa->pa_id == 0x20001022) @@ -313,10 +322,10 @@ leattach(parent, self, aux) void *aux; { struct le_softc *sc = (void *)self; - extern struct cfdriver isacd, pcicd; + extern struct cfdriver isa_cd, pci_cd; #if NPCI > 0 - if (parent->dv_cfdata->cf_driver == &pcicd) { + if (parent->dv_cfdata->cf_driver == &pci_cd) { struct pci_attach_args *pa = aux; int iobase; @@ -386,33 +395,34 @@ leattach(parent, self, aux) sc->sc_copyfrombuf = copyfrombuf_contig; sc->sc_zerobuf = zerobuf_contig; - sc->sc_arpcom.ac_if.if_name = lecd.cd_name; + sc->sc_arpcom.ac_if.if_name = le_cd.cd_name; leconfig(sc); printf("%s: type %s\n", sc->sc_dev.dv_xname, card_type[sc->sc_card]); #if NISA > 0 - if (parent->dv_cfdata->cf_driver == &isacd) { + if (parent->dv_cfdata->cf_driver == &isa_cd) { struct isa_attach_args *ia = aux; if (ia->ia_drq != DRQUNK) isa_dmacascade(ia->ia_drq); - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_NET, - leintredge, sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_NET, leintredge, sc, sc->sc_dev.dv_xname); } #endif #if NPCI > 0 - if (parent->dv_cfdata->cf_driver == &pcicd) { + if (parent->dv_cfdata->cf_driver == &pci_cd) { struct pci_attach_args *pa = aux; + pcireg_t csr; - pci_conf_write(pa->pa_tag, PCI_COMMAND_STATUS_REG, - pci_conf_read(pa->pa_tag, PCI_COMMAND_STATUS_REG) | - PCI_COMMAND_MASTER_ENABLE); + csr = pci_conf_read(pa->pa_bc, pa->pa_tag, + PCI_COMMAND_STATUS_REG); + pci_conf_write(pa->pa_bc, pa->pa_tag, PCI_COMMAND_STATUS_REG, + csr | PCI_COMMAND_MASTER_ENABLE); - sc->sc_ih = pci_map_int(pa->pa_tag, IPL_NET, leintr, sc, - sc->sc_dev.dv_xname); + sc->sc_ih = pci_map_int(pa->pa_tag, IPL_NET, leintr, sc); } #endif diff --git a/sys/dev/isa/isa.c b/sys/dev/isa/isa.c index 5f55324d434..fa14cc051ff 100644 --- a/sys/dev/isa/isa.c +++ b/sys/dev/isa/isa.c @@ -1,5 +1,5 @@ -/* $OpenBSD: isa.c,v 1.5 1996/04/18 23:47:41 niklas Exp $ */ -/* $NetBSD: isa.c,v 1.78 1996/03/08 20:36:21 cgd Exp $ */ +/* $OpenBSD: isa.c,v 1.6 1996/04/21 22:24:12 deraadt Exp $ */ +/* $NetBSD: isa.c,v 1.80 1996/04/11 22:25:44 cgd Exp $ */ /*- * Copyright (c) 1993, 1994 Charles Hannum. All rights reserved. @@ -36,6 +36,9 @@ #include <sys/conf.h> #include <sys/malloc.h> #include <sys/device.h> +#ifndef i386 /* XXX */ +#include <machine/intr.h> +#endif /* XXX */ #include <dev/isa/isareg.h> #include <dev/isa/isavar.h> @@ -43,8 +46,12 @@ int isamatch __P((struct device *, void *, void *)); void isaattach __P((struct device *, struct device *, void *)); -struct cfdriver isacd = { - NULL, "isa", isamatch, isaattach, DV_DULL, sizeof(struct isa_softc), 1 +struct cfattach isa_ca = { + sizeof(struct isa_softc), isamatch, isaattach +}; + +struct cfdriver isa_cd = { + NULL, "isa", DV_DULL, 1 }; int @@ -71,9 +78,11 @@ isaattach(parent, self, aux) struct isa_softc *sc = (struct isa_softc *)self; struct isabus_attach_args *iba = aux; + isa_attach_hook(parent, self, iba); printf("\n"); sc->sc_bc = iba->iba_bc; + sc->sc_ic = iba->iba_ic; TAILQ_INIT(&sc->sc_subdevs); config_scan(isascan, self); @@ -115,6 +124,7 @@ isascan(parent, match) panic("clone devices not supported on ISA bus"); ia.ia_bc = sc->sc_bc; + ia.ia_ic = sc->sc_ic; ia.ia_iobase = cf->cf_loc[0]; ia.ia_iosize = 0x666; ia.ia_maddr = cf->cf_loc[2]; @@ -122,7 +132,7 @@ isascan(parent, match) ia.ia_irq = cf->cf_loc[4] == 2 ? 9 : cf->cf_loc[4]; ia.ia_drq = cf->cf_loc[5]; - if ((*cf->cf_driver->cd_match)(parent, dev, &ia) > 0) + if ((*cf->cf_attach->ca_match)(parent, dev, &ia) > 0) config_attach(parent, dev, &ia, isaprint); else free(dev, M_DEVBUF); diff --git a/sys/dev/isa/isadma.c b/sys/dev/isa/isadma.c index 37a0795745a..a1d5778dda8 100644 --- a/sys/dev/isa/isadma.c +++ b/sys/dev/isa/isadma.c @@ -1,5 +1,5 @@ -/* $OpenBSD: isadma.c,v 1.3 1996/04/18 23:47:41 niklas Exp $ */ -/* $NetBSD: isadma.c,v 1.17 1996/03/01 04:35:27 mycroft Exp $ */ +/* $OpenBSD: isadma.c,v 1.4 1996/04/21 22:24:14 deraadt Exp $ */ +/* $NetBSD: isadma.c,v 1.18 1996/03/31 20:51:43 mycroft Exp $ */ #include <sys/param.h> #include <sys/systm.h> @@ -28,8 +28,9 @@ static struct dma_info dma_info[8]; static u_int8_t dma_finished; /* 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 +static int dmapageport[2][4] = { + {0x87, 0x83, 0x81, 0x82}, + {0x8f, 0x8b, 0x89, 0x8a} }; static u_int8_t dmamode[4] = { @@ -123,7 +124,7 @@ isadma_start(addr, nbytes, chan, flags) /* send start address */ waport = DMA1_CHN(chan); - outb(dmapageport[chan], di->phys[0].addr>>16); + outb(dmapageport[0][chan], di->phys[0].addr>>16); outb(waport, di->phys[0].addr); outb(waport, di->phys[0].addr>>8); @@ -144,7 +145,7 @@ isadma_start(addr, nbytes, chan, flags) /* send start address */ waport = DMA2_CHN(chan & 3); - outb(dmapageport[chan], di->phys[0].addr>>16); + outb(dmapageport[1][chan], di->phys[0].addr>>16); outb(waport, di->phys[0].addr>>1); outb(waport, di->phys[0].addr>>9); diff --git a/sys/dev/isa/isavar.h b/sys/dev/isa/isavar.h index 551375712f0..78b950248a9 100644 --- a/sys/dev/isa/isavar.h +++ b/sys/dev/isa/isavar.h @@ -1,5 +1,5 @@ -/* $OpenBSD: isavar.h,v 1.7 1996/04/18 23:47:43 niklas Exp $ */ -/* $NetBSD: isavar.h,v 1.20 1996/03/16 02:00:43 cgd Exp $ */ +/* $OpenBSD: isavar.h,v 1.8 1996/04/21 22:24:16 deraadt Exp $ */ +/* $NetBSD: isavar.h,v 1.21 1996/04/11 22:20:50 cgd Exp $ */ /* * Copyright (c) 1995 Chris G. Demetriou @@ -47,19 +47,36 @@ #include <sys/queue.h> #include <machine/bus.h> +/* + * Structures and definitions needed by the machine-dependent header. + */ +struct isabus_attach_args; + +#if (alpha + i386 != 1) +ERROR: COMPILING FOR UNSUPPORTED MACHINE, OR MORE THAN ONE. +#endif +#if alpha +#include <alpha/isa/isa_machdep.h> +#endif +#if i386 +#include <i386/isa/isa_machdep.h> +#endif + /* * ISA bus attach arguments */ struct isabus_attach_args { char *iba_busname; /* XXX should be common */ bus_chipset_tag_t iba_bc; /* XXX should be common */ + isa_chipset_tag_t iba_ic; }; /* * ISA driver attach arguments */ struct isa_attach_args { - bus_chipset_tag_t ia_bc; /* bus chipset tag */ + bus_chipset_tag_t ia_bc; + isa_chipset_tag_t ia_ic; int ia_iobase; /* base i/o address */ int ia_iosize; /* span of ports used */ @@ -92,7 +109,8 @@ struct isa_softc { TAILQ_HEAD(, isadev) sc_subdevs; /* list of all children */ - bus_chipset_tag_t sc_bc; /* bus chipset tag */ + bus_chipset_tag_t sc_bc; + isa_chipset_tag_t sc_ic; }; #define cf_iobase cf_loc[0] @@ -120,9 +138,6 @@ struct isa_softc { /* ISA interrupt sharing types */ void isascan __P((struct device *parent, void *match)); -void *isa_intr_establish __P((int intr, int type, int level, - int (*ih_fun)(void *), void *ih_arg, char *)); -void isa_intr_disestablish __P((void *handler)); char *isa_intr_typename __P((int type)); #ifdef NEWCONFIG diff --git a/sys/dev/isa/lpt.c b/sys/dev/isa/lpt.c index 3bcfd6ad241..24499ddbc45 100644 --- a/sys/dev/isa/lpt.c +++ b/sys/dev/isa/lpt.c @@ -1,5 +1,5 @@ -/* $OpenBSD: lpt.c,v 1.8 1996/04/18 23:47:43 niklas Exp $ */ -/* $NetBSD: lpt.c,v 1.32 1996/03/08 22:17:58 cgd Exp $ */ +/* $OpenBSD: lpt.c,v 1.9 1996/04/21 22:24:18 deraadt Exp $ */ +/* $NetBSD: lpt.c,v 1.37 1996/04/11 22:29:37 cgd Exp $ */ /* * Copyright (c) 1993, 1994 Charles Hannum. @@ -65,7 +65,11 @@ #include <sys/device.h> #include <sys/syslog.h> -#include <machine/cpu.h> +#ifdef i386 /* XXX */ +#include <machine/cpu.h> /* XXX */ +#else /* XXX */ +#include <machine/intr.h> +#endif /* XXX */ #include <machine/bus.h> #include <dev/isa/isavar.h> @@ -112,8 +116,12 @@ int lptprobe __P((struct device *, void *, void *)); void lptattach __P((struct device *, struct device *, void *)); int lptintr __P((void *)); -struct cfdriver lptcd = { - NULL, "lpt", lptprobe, lptattach, DV_TTY, sizeof(struct lpt_softc) +struct cfattach lpt_ca = { + sizeof(struct lpt_softc), lptprobe, lptattach +}; + +struct cfdriver lpt_cd = { + NULL, "lpt", DV_TTY }; #define LPTUNIT(s) (minor(s) & 0x1f) @@ -128,15 +136,19 @@ static int not_ready __P((u_char, struct lpt_softc *)); static void lptwakeup __P((void *arg)); static int pushbytes __P((struct lpt_softc *)); +int lpt_port_test __P((bus_chipset_tag_t, bus_io_handle_t, bus_io_addr_t, + bus_io_size_t, u_char, u_char)); + /* * Internal routine to lptprobe to do port tests of one byte value. */ int -lpt_port_test(ioh, off, data, mask, base) +lpt_port_test(bc, ioh, base, off, data, mask) + bus_chipset_tag_t bc; bus_io_handle_t ioh; - size_t off; + bus_io_addr_t base; + bus_io_size_t off; u_char data, mask; - u_long base; { int timeout; u_char temp; @@ -202,22 +214,22 @@ lptprobe(parent, match, aux) mask = 0xff; data = 0x55; /* Alternating zeros */ - if (!lpt_port_test(ioh, lpt_data, data, mask, base)) + if (!lpt_port_test(bc, ioh, base, lpt_data, data, mask)) ABORT; data = 0xaa; /* Alternating ones */ - if (!lpt_port_test(ioh, lpt_data, data, mask, base)) + if (!lpt_port_test(bc, ioh, base, lpt_data, data, mask)) ABORT; for (i = 0; i < CHAR_BIT; i++) { /* Walking zero */ data = ~(1 << i); - if (!lpt_port_test(ioh, lpt_data, data, mask, base)) + if (!lpt_port_test(bc, ioh, base, lpt_data, data, mask)) ABORT; } for (i = 0; i < CHAR_BIT; i++) { /* Walking one */ data = (1 << i); - if (!lpt_port_test(ioh, lpt_data, data, mask, base)) + if (!lpt_port_test(bc, ioh, base, lpt_data, data, mask)) ABORT; } @@ -261,8 +273,8 @@ lptattach(parent, self, aux) bus_io_write_1(bc, ioh, lpt_control, LPC_NINIT); if (ia->ia_irq != IRQUNK) - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_NONE, - lptintr, sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_TTY, lptintr, sc, sc->sc_dev.dv_xname); } /* @@ -282,9 +294,9 @@ lptopen(dev, flag) int error; int spin; - if (unit >= lptcd.cd_ndevs) + if (unit >= lpt_cd.cd_ndevs) return ENXIO; - sc = lptcd.cd_devs[unit]; + sc = lpt_cd.cd_devs[unit]; if (!sc) return ENXIO; @@ -386,12 +398,13 @@ lptwakeup(arg) /* * Close the device, and free the local line buffer. */ +int lptclose(dev, flag) dev_t dev; int flag; { int unit = LPTUNIT(dev); - struct lpt_softc *sc = lptcd.cd_devs[unit]; + struct lpt_softc *sc = lpt_cd.cd_devs[unit]; bus_chipset_tag_t bc = sc->sc_bc; bus_io_handle_t ioh = sc->sc_ioh; @@ -476,11 +489,12 @@ pushbytes(sc) * Copy a line from user space to a local buffer, then call putc to get the * chars moved to the output queue. */ +int lptwrite(dev, uio) dev_t dev; struct uio *uio; { - struct lpt_softc *sc = lptcd.cd_devs[LPTUNIT(dev)]; + struct lpt_softc *sc = lpt_cd.cd_devs[LPTUNIT(dev)]; size_t n; int error = 0; diff --git a/sys/dev/isa/mcd.c b/sys/dev/isa/mcd.c index 8fce277ec1d..cf5eeb3a812 100644 --- a/sys/dev/isa/mcd.c +++ b/sys/dev/isa/mcd.c @@ -1,5 +1,5 @@ -/* $OpenBSD: mcd.c,v 1.8 1996/03/20 01:00:56 mickey Exp $ */ -/* $NetBSD: mcd.c,v 1.45 1996/01/30 18:28:05 thorpej Exp $ */ +/* $OpenBSD: mcd.c,v 1.9 1996/04/21 22:24:21 deraadt Exp $ */ +/* $NetBSD: mcd.c,v 1.47 1996/04/11 22:29:43 cgd Exp $ */ /* * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. All rights reserved. @@ -178,8 +178,12 @@ int mcd_setlock __P((struct mcd_softc *, int)); int mcdprobe __P((struct device *, void *, void *)); void mcdattach __P((struct device *, struct device *, void *)); -struct cfdriver mcdcd = { - NULL, "mcd", mcdprobe, mcdattach, DV_DISK, sizeof(struct mcd_softc) +struct cfattach mcd_ca = { + sizeof(struct mcd_softc), mcdprobe, mcdattach +}; + +struct cfdriver mcd_cd = { + NULL, "mcd", DV_DISK }; void mcdgetdisklabel __P((struct mcd_softc *)); @@ -228,8 +232,8 @@ mcdattach(parent, self, aux) mcd_soft_reset(sc); - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_BIO, mcdintr, - sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_BIO, mcdintr, sc, sc->sc_dev.dv_xname); } /* @@ -279,9 +283,9 @@ mcdopen(dev, flag, fmt, p) struct mcd_softc *sc; unit = MCDUNIT(dev); - if (unit >= mcdcd.cd_ndevs) + if (unit >= mcd_cd.cd_ndevs) return ENXIO; - sc = mcdcd.cd_devs[unit]; + sc = mcd_cd.cd_devs[unit]; if (!sc) return ENXIO; @@ -379,7 +383,7 @@ mcdclose(dev, flag, fmt) dev_t dev; int flag, fmt; { - struct mcd_softc *sc = mcdcd.cd_devs[MCDUNIT(dev)]; + struct mcd_softc *sc = mcd_cd.cd_devs[MCDUNIT(dev)]; int part = MCDPART(dev); int error; @@ -415,7 +419,7 @@ void mcdstrategy(bp) struct buf *bp; { - struct mcd_softc *sc = mcdcd.cd_devs[MCDUNIT(bp->b_dev)]; + struct mcd_softc *sc = mcd_cd.cd_devs[MCDUNIT(bp->b_dev)]; int s; /* Test validity. */ @@ -548,7 +552,7 @@ mcdioctl(dev, cmd, addr, flag, p) int flag; struct proc *p; { - struct mcd_softc *sc = mcdcd.cd_devs[MCDUNIT(dev)]; + struct mcd_softc *sc = mcd_cd.cd_devs[MCDUNIT(dev)]; int error; MCD_TRACE("ioctl: cmd=0x%x\n", cmd, 0, 0, 0); diff --git a/sys/dev/isa/pas.c b/sys/dev/isa/pas.c index 0d0fe136538..4227615cb36 100644 --- a/sys/dev/isa/pas.c +++ b/sys/dev/isa/pas.c @@ -1,5 +1,5 @@ -/* $OpenBSD: pas.c,v 1.8 1996/04/18 23:47:44 niklas Exp $ */ -/* $NetBSD: pas.c,v 1.13 1996/03/01 04:08:43 mycroft Exp $ */ +/* $OpenBSD: pas.c,v 1.9 1996/04/21 22:24:23 deraadt Exp $ */ +/* $NetBSD: pas.c,v 1.15 1996/04/11 22:29:48 cgd Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -250,8 +250,12 @@ pasconf(int model, int sbbase, int sbirq, int sbdrq) int pasprobe __P((struct device *, void *, void *)); void pasattach __P((struct device *, struct device *, void *)); -struct cfdriver pascd = { - NULL, "pas", pasprobe, pasattach, DV_DULL, sizeof(struct pas_softc) +struct cfattach pas_ca = { + sizeof(struct pas_softc), pasprobe, pasattach +}; + +struct cfdriver pas_cd = { + NULL, "pas", DV_DULL }; /* @@ -431,8 +435,8 @@ pasattach(parent, self, aux) int err; sc->sc_iobase = iobase; - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_AUDIO, - sbdsp_intr, &sc->sc_sbdsp, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_AUDIO, sbdsp_intr, &sc->sc_sbdsp, sc->sc_dev.dv_xname); printf(" ProAudio Spectrum %s [rev %d] ", pasnames[sc->model], sc->rev); @@ -453,10 +457,10 @@ pasopen(dev, flags) struct pas_softc *sc; int unit = AUDIOUNIT(dev); - if (unit >= pascd.cd_ndevs) + if (unit >= pas_cd.cd_ndevs) return ENODEV; - sc = pascd.cd_devs[unit]; + sc = pas_cd.cd_devs[unit]; if (!sc) return ENXIO; diff --git a/sys/dev/isa/pss.c b/sys/dev/isa/pss.c index 909db507342..9e551882061 100644 --- a/sys/dev/isa/pss.c +++ b/sys/dev/isa/pss.c @@ -1,5 +1,5 @@ -/* $OpenBSD: pss.c,v 1.7 1996/03/20 01:00:59 mickey Exp $ */ -/* $NetBSD: pss.c,v 1.11 1995/12/24 02:31:45 mycroft Exp $ */ +/* $OpenBSD: pss.c,v 1.8 1996/04/21 22:24:26 deraadt Exp $ */ +/* $NetBSD: pss.c,v 1.13 1996/04/11 22:29:52 cgd Exp $ */ /* * Copyright (c) 1994 John Brezak @@ -238,20 +238,36 @@ static u_char wss_dma_bits[4] = {1, 2, 0, 3}; #define at_dma(flags, ptr, cc, chan) isa_dmastart(flags, ptr, cc, chan) #endif -struct cfdriver psscd = { - NULL, "pss", pssprobe, pssattach, DV_DULL, sizeof(struct pss_softc), 1 +struct cfattach pss_ca = { + sizeof(struct pss_softc), pssprobe, pssattach }; -struct cfdriver spcd = { - NULL, "sp", spprobe, spattach, DV_DULL, sizeof(struct ad1848_softc) +struct cfdriver pss_cd = { + NULL, "pss", DV_DULL, 1 }; -struct cfdriver mpucd = { - NULL, "mpu", mpuprobe, mpuattach, DV_DULL, sizeof(struct mpu_softc) +struct cfattach sp_ca = { + sizeof(struct ad1848_softc), spprobe, spattach }; -struct cfdriver pcdcd = { - NULL, "pcd", pcdprobe, pcdattach, DV_DULL, sizeof(struct cd_softc) +struct cfdriver sp_cd = { + NULL, "sp", DV_DULL +}; + +struct cfattach mpu_ca = { + sizeof(struct mpu_softc), mpuprobe, mpuattach +}; + +struct cfdriver mpu_cd = { + NULL, "mpu", DV_DULL +}; + +struct cfattach pcd_ca = { + sizeof(struct cd_softc), pcdprobe, pcdattach +}; + +struct cfdriver pcd_cd = { + NULL, "pcd", DV_DULL }; struct audio_device pss_device = { @@ -1005,13 +1021,13 @@ pssattach(parent, self, aux) #endif /* Setup interrupt handler for PSS */ - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_AUDIO, pssintr, - sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, IPL_AUDIO, + pssintr, sc, sc->sc_dev.dv_xname); vers = (inw(sc->sc_iobase+PSS_ID_VERS)&0xff) - 1; printf(": ESC614%c\n", (vers > 0)?'A'+vers:' '); - (void)config_found(self, NULL, NULL); + (void)config_found(self, ia->ia_ic, NULL); /* XXX */ sc->out_port = PSS_MASTER_VOL; @@ -1031,6 +1047,7 @@ spattach(parent, self, aux) { struct ad1848_softc *sc = (struct ad1848_softc *)self; struct cfdata *cf = (void *)sc->sc_dev.dv_cfdata; + isa_chipset_tag_t ic = aux; /* XXX */ int iobase = cf->cf_iobase; sc->sc_iobase = iobase; @@ -1040,8 +1057,8 @@ spattach(parent, self, aux) isa_establish(&sc->sc_id, &sc->sc_dev); #endif - sc->sc_ih = isa_intr_establish(cf->cf_irq, IST_EDGE, IPL_AUDIO, ad1848_intr, - sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ic, cf->cf_irq, IST_EDGE, IPL_AUDIO, + ad1848_intr, sc, sc->sc_dev.dv_xname); /* XXX might use pssprint func ?? */ printf(" port 0x%x-0x%x irq %d drq %d", @@ -1060,6 +1077,7 @@ mpuattach(parent, self, aux) { struct mpu_softc *sc = (struct mpu_softc *)self; struct cfdata *cf = (void *)sc->sc_dev.dv_cfdata; + isa_chipset_tag_t ic = aux; /* XXX */ int iobase = cf->cf_iobase; sc->sc_iobase = iobase; @@ -1068,8 +1086,8 @@ mpuattach(parent, self, aux) isa_establish(&sc->sc_id, &sc->sc_dev); #endif - sc->sc_ih = isa_intr_establish(cf->cf_irq, IST_EDGE, IPL_AUDIO, mpuintr, - sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ic, cf->cf_irq, IST_EDGE, IPL_AUDIO, + mpuintr, sc, sc->sc_dev.dv_xname); /* XXX might use pssprint func ?? */ printf(" port 0x%x-0x%x irq %d\n", @@ -1145,10 +1163,10 @@ spopen(dev, flags) struct ad1848_softc *sc; int unit = AUDIOUNIT(dev); - if (unit >= spcd.cd_ndevs) + if (unit >= sp_cd.cd_ndevs) return ENODEV; - sc = spcd.cd_devs[unit]; + sc = sp_cd.cd_devs[unit]; if (!sc) return ENXIO; diff --git a/sys/dev/isa/rtfps.c b/sys/dev/isa/rtfps.c index e0f7ef2abf4..1afdc1ccfda 100644 --- a/sys/dev/isa/rtfps.c +++ b/sys/dev/isa/rtfps.c @@ -1,5 +1,5 @@ -/* $OpenBSD: rtfps.c,v 1.7 1996/04/18 23:47:45 niklas Exp $ */ -/* $NetBSD: rtfps.c,v 1.17 1996/03/10 09:01:28 cgd Exp $ */ +/* $OpenBSD: rtfps.c,v 1.8 1996/04/21 22:24:28 deraadt Exp $ */ +/* $NetBSD: rtfps.c,v 1.21 1996/04/15 18:55:31 cgd Exp $ */ /* * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. @@ -36,7 +36,13 @@ #include <sys/param.h> #include <sys/device.h> +#include <sys/termios.h> +#ifdef i386 /* XXX */ +#include <machine/cpu.h> /* XXX */ +#else /* XXX */ +#include <machine/intr.h> +#endif /* XXX */ #include <machine/bus.h> #include <dev/isa/isavar.h> @@ -63,8 +69,12 @@ int rtfpsprobe(); void rtfpsattach(); int rtfpsintr __P((void *)); -struct cfdriver rtfpscd = { - NULL, "rtfps", rtfpsprobe, rtfpsattach, DV_TTY, sizeof(struct rtfps_softc) +struct cfattach rtfps_ca = { + sizeof(struct rtfps_softc), rtfpsprobe, rtfpsattach +}; + +struct cfdriver rtfps_cd = { + NULL, "rtfps", DV_TTY }; int @@ -176,20 +186,13 @@ rtfpsattach(parent, self, aux) ca.ca_iobase = sc->sc_iobase + i * COM_NPORTS; ca.ca_noien = 0; - /* mimic config_found(), but with special functionality */ - if ((match = config_search(NULL, self, &ca)) != NULL) { - subunit = match->cf_unit; /* can change if unit == * */ - config_attach(self, match, &ca, rtfpsprint); - sc->sc_slaves[i] = match->cf_driver->cd_devs[subunit]; + sc->sc_slaves[i] = config_found(self, &ca, rtfpsprint); + if (sc->sc_slaves[i] != NULL) sc->sc_alive |= 1 << i; - } else { - rtfpsprint(&ca, self->dv_xname); - printf(" not configured\n"); - } } - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_TTY, - rtfpsintr, sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_TTY, rtfpsintr, sc, sc->sc_dev.dv_xname); } int diff --git a/sys/dev/isa/sb.c b/sys/dev/isa/sb.c index 976eada8cc7..09fd816e061 100644 --- a/sys/dev/isa/sb.c +++ b/sys/dev/isa/sb.c @@ -1,5 +1,5 @@ -/* $OpenBSD: sb.c,v 1.8 1996/04/18 23:47:46 niklas Exp $ */ -/* $NetBSD: sb.c,v 1.32 1996/03/16 04:00:09 jtk Exp $ */ +/* $OpenBSD: sb.c,v 1.9 1996/04/21 22:24:30 deraadt Exp $ */ +/* $NetBSD: sb.c,v 1.34 1996/04/11 22:30:01 cgd Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -75,8 +75,18 @@ struct sb_softc { int sbprobe __P((struct device *, void *, void *)); void sbattach __P((struct device *, struct device *, void *)); -struct cfdriver sbcd = { - NULL, "sb", sbprobe, sbattach, DV_DULL, sizeof(struct sbdsp_softc) +struct cfattach sb_ca = { + sizeof(struct sbdsp_softc), sbprobe, sbattach +}; + +struct cfdriver sb_cd = { + NULL, "sb", DV_DULL +}; + +struct audio_device sb_device = { + "SoundBlaster", + "x", + "sb" }; int sbopen __P((dev_t, int)); @@ -264,8 +274,8 @@ sbattach(parent, self, aux) register int iobase = ia->ia_iobase; int err; - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_AUDIO, - sbdsp_intr, sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_AUDIO, sbdsp_intr, sc, sc->sc_dev.dv_xname); sbdsp_attach(sc); @@ -285,10 +295,10 @@ sbopen(dev, flags) struct sbdsp_softc *sc; int unit = AUDIOUNIT(dev); - if (unit >= sbcd.cd_ndevs) + if (unit >= sb_cd.cd_ndevs) return ENODEV; - sc = sbcd.cd_devs[unit]; + sc = sb_cd.cd_devs[unit]; if (!sc) return ENXIO; diff --git a/sys/dev/isa/seagate.c b/sys/dev/isa/seagate.c index ccb16aa9165..67e70d04696 100644 --- a/sys/dev/isa/seagate.c +++ b/sys/dev/isa/seagate.c @@ -303,8 +303,12 @@ int seaprobe __P((struct device *, void *, void *)); void seaattach __P((struct device *, struct device *, void *)); int seaprint __P((void *, char *)); -struct cfdriver seacd = { - NULL, "sea", seaprobe, seaattach, DV_DULL, sizeof(struct sea_softc) +struct cfattach sea_ca = { + sizeof(struct sea_softc), seaprobe, seaattach +}; + +struct cfdriver sea_cd = { + NULL, "sea", DV_DULL }; #ifdef SEA_DEBUGQUEUE @@ -438,8 +442,8 @@ seaattach(parent, self, aux) #ifdef NEWCONFIG isa_establish(&sea->sc_id, &sea->sc_deV); #endif - sea->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_BIO, seaintr, - sea, sc->sc_dev.dv_xname); + sea->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_BIO, seaintr, sea, sea->sc_dev.dv_xname); /* * ask the adapter what subunits are present @@ -685,8 +689,8 @@ sea_main() */ loop: done = 1; - for (unit = 0; unit < seacd.cd_ndevs; unit++) { - sea = seacd.cd_devs[unit]; + for (unit = 0; unit < sea_cd.cd_ndevs; unit++) { + sea = sea_cd.cd_devs[unit]; if (!sea) continue; s = splbio(); diff --git a/sys/dev/isa/ultra14f.c b/sys/dev/isa/ultra14f.c index 948a2966654..79464cc4d6c 100644 --- a/sys/dev/isa/ultra14f.c +++ b/sys/dev/isa/ultra14f.c @@ -1,5 +1,5 @@ -/* $OpenBSD: ultra14f.c,v 1.12 1996/04/18 23:47:50 niklas Exp $ */ -/* $NetBSD: ultra14f.c,v 1.62 1996/02/24 05:27:49 mycroft Exp $ */ +/* $OpenBSD: ultra14f.c,v 1.13 1996/04/21 22:24:36 deraadt Exp $ */ +/* $NetBSD: ultra14f.c,v 1.64 1996/04/11 22:30:20 cgd Exp $ */ /* * Copyright (c) 1994 Charles Hannum. All rights reserved. @@ -328,8 +328,12 @@ int uhaprobe __P((struct device *, void *, void *)); void uhaattach __P((struct device *, struct device *, void *)); int uhaprint __P((void *, char *)); -struct cfdriver uhacd = { - NULL, "uha", uhaprobe, uhaattach, DV_DULL, sizeof(struct uha_softc) +struct cfattach uha_ca = { + sizeof(struct uha_softc), uhaprobe, uhaattach +}; + +struct cfdriver uha_cd = { + NULL, "uha", DV_DULL }; /* @@ -608,8 +612,8 @@ uhaattach(parent, self, aux) #ifdef NEWCONFIG isa_establish(&uha->sc_id, &uha->sc_dev); #endif - uha->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_BIO, - uha->intr, uha, uha->sc_dev.dv_xname); + uha->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_BIO, uha->intr, uha, uha->sc_dev.dv_xname); /* * ask the adapter what subunits are present diff --git a/sys/dev/isa/wd.c b/sys/dev/isa/wd.c index 96fedd9de01..76267053725 100644 --- a/sys/dev/isa/wd.c +++ b/sys/dev/isa/wd.c @@ -1,5 +1,5 @@ -/* $OpenBSD: wd.c,v 1.9 1996/04/18 23:47:51 niklas Exp $ */ -/* $NetBSD: wd.c,v 1.146 1996/03/01 04:08:51 mycroft Exp $ */ +/* $OpenBSD: wd.c,v 1.10 1996/04/21 22:24:40 deraadt Exp $ */ +/* $NetBSD: wd.c,v 1.148 1996/04/11 22:30:31 cgd Exp $ */ /* * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. @@ -139,15 +139,23 @@ struct wdc_softc { int wdcprobe __P((struct device *, void *, void *)); void wdcattach __P((struct device *, struct device *, void *)); -struct cfdriver wdccd = { - NULL, "wdc", wdcprobe, wdcattach, DV_DULL, sizeof(struct wdc_softc) +struct cfattach wdc_ca = { + sizeof(struct wdc_softc), wdcprobe, wdcattach +}; + +struct cfdriver wdc_cd = { + NULL, "wdc", DV_DULL }; int wdprobe __P((struct device *, void *, void *)); void wdattach __P((struct device *, struct device *, void *)); -struct cfdriver wdcd = { - NULL, "wd", wdprobe, wdattach, DV_DISK, sizeof(struct wd_softc) +struct cfattach wd_ca = { + sizeof(struct wd_softc), wdprobe, wdattach +}; + +struct cfdriver wd_cd = { + NULL, "wd", DV_DISK }; void wdgetdisklabel __P((struct wd_softc *)); @@ -249,8 +257,8 @@ wdcattach(parent, self, aux) printf("\n"); - wdc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_BIO, wdcintr, - wdc, wdc->sc_dev.dv_xname); + wdc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_BIO, wdcintr, wdc, wdc->sc_dev.dv_xname); for (wa.wa_drive = 0; wa.wa_drive < 2; wa.wa_drive++) (void)config_found(self, (void *)&wa, wdprint); @@ -354,7 +362,7 @@ void wdstrategy(bp) struct buf *bp; { - struct wd_softc *wd = wdcd.cd_devs[WDUNIT(bp->b_dev)]; + struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(bp->b_dev)]; int s; /* Valid request? */ @@ -889,9 +897,9 @@ wdopen(dev, flag, fmt) int error; unit = WDUNIT(dev); - if (unit >= wdcd.cd_ndevs) + if (unit >= wd_cd.cd_ndevs) return ENXIO; - wd = wdcd.cd_devs[unit]; + wd = wd_cd.cd_devs[unit]; if (wd == 0) return ENXIO; @@ -963,7 +971,7 @@ wdclose(dev, flag, fmt) dev_t dev; int flag, fmt; { - struct wd_softc *wd = wdcd.cd_devs[WDUNIT(dev)]; + struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(dev)]; int part = WDPART(dev); int error; @@ -1308,7 +1316,7 @@ wdioctl(dev, cmd, addr, flag, p) int flag; struct proc *p; { - struct wd_softc *wd = wdcd.cd_devs[WDUNIT(dev)]; + struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(dev)]; int error; if ((wd->sc_flags & WDF_LOADED) == 0) @@ -1424,7 +1432,7 @@ wdsize(dev) if (wdopen(dev, 0, S_IFBLK) != 0) return -1; - wd = wdcd.cd_devs[WDUNIT(dev)]; + wd = wd_cd.cd_devs[WDUNIT(dev)]; part = WDPART(dev); if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) size = -1; @@ -1463,9 +1471,9 @@ wddump(dev, blkno, va, size) wddoingadump = 1; unit = WDUNIT(dev); - if (unit >= wdcd.cd_ndevs) + if (unit >= wd_cd.cd_ndevs) return ENXIO; - wd = wdcd.cd_devs[unit]; + wd = wd_cd.cd_devs[unit]; if (wd == 0) return ENXIO; @@ -1657,8 +1665,8 @@ wdcunwedge(wdc) (void) wdcreset(wdc); /* Schedule recalibrate for all drives on this controller. */ - for (unit = 0; unit < wdcd.cd_ndevs; unit++) { - struct wd_softc *wd = wdcd.cd_devs[unit]; + for (unit = 0; unit < wd_cd.cd_ndevs; unit++) { + struct wd_softc *wd = wd_cd.cd_devs[unit]; if (!wd || (void *)wd->sc_dev.dv_parent != wdc) continue; if (wd->sc_state > RECAL) diff --git a/sys/dev/isa/wd7000.c b/sys/dev/isa/wd7000.c deleted file mode 100644 index cd86dd0e8ef..00000000000 --- a/sys/dev/isa/wd7000.c +++ /dev/null @@ -1,747 +0,0 @@ -/* $NetBSD: wd7000.c,v 1.22 1995/08/12 20:31:32 mycroft Exp $ */ - -/* XXX THIS DRIVER IS BROKEN. IT WILL NOT EVEN COMPILE. */ - -/* - * UNFINISHED! UNFINISHED! UNFINISHED! UNFINISHED! UNFINISHED! UNFINISHED! - * - * deraadt@fsa.ca 93/04/02 - * - * I was writing this driver for a wd7000-ASC. Yeah, the "-ASC" not the - * "-FASST2". The difference is that the "-ASC" is missing scatter gather - * support. - * - * In any case, the real reason why I never finished it is because the - * motherboard I have has broken DMA. This card wants 8MHz 1 wait state - * operation, and my board munges about 30% of the words transferred. - * - * Hopefully someone can finish this for the wd7000-FASST2. It should be - * quite easy to do. Look at the Linux wd7000 device driver to see how - * scatter gather is done by the board, then look at one of the Adaptec - * drivers to finish off the job.. - */ -#include "wds.h" -#if NWDS > 0 - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/errno.h> -#include <sys/ioctl.h> -#include <sys/buf.h> -#include <sys/proc.h> -#include <sys/user.h> -#include <sys/dkbad.h> -#include <sys/disklabel.h> - -#include <scsi/scsi_all.h> -#include <scsi/scsiconf.h> - -#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 */ - -#define PHYSTOKV(x) ((x) + KERNBASE) -#define KVTOPHYS(x) vtophys(x) -#define PAGESIZ 4096 - - -/* WD7000 registers */ -#define WDS_STAT 0 /* read */ -#define WDS_IRQSTAT 1 /* read */ - -#define WDS_CMD 0 /* write */ -#define WDS_IRQACK 1 /* write */ -#define WDS_HCR 2 /* write */ - -/* WDS_STAT (read) defs */ -#define WDS_IRQ 0x80 -#define WDS_RDY 0x40 -#define WDS_REJ 0x20 -#define WDS_INIT 0x10 - -/* WDS_IRQSTAT (read) defs */ -#define WDSI_MASK 0xc0 -#define WDSI_ERR 0x00 -#define WDSI_MFREE 0x80 -#define WDSI_MSVC 0xc0 - -/* WDS_CMD (write) defs */ -#define WDSC_NOOP 0x00 -#define WDSC_INIT 0x01 -#define WDSC_DISUNSOL 0x02 -#define WDSC_ENAUNSOL 0x03 -#define WDSC_IRQMFREE 0x04 -#define WDSC_SCSIRESETSOFT 0x05 -#define WDSC_SCSIRESETHARD 0x06 -#define WDSC_MSTART(m) (0x80 + (m)) -#define WDSC_MMSTART(m) (0xc0 + (m)) - -/* WDS_HCR (write) defs */ -#define WDSH_IRQEN 0x08 -#define WDSH_DRQEN 0x04 -#define WDSH_SCSIRESET 0x02 -#define WDSH_ASCRESET 0x01 - -struct wds_cmd { - u_char cmd; - u_char targ; - struct scsi_generic scb; /*u_char scb[12];*/ - u_char stat; - u_char venderr; - u_char len[3]; - u_char data[3]; - u_char next[3]; - u_char write; - u_char xx[6]; -}; - -struct wds_req { - struct wds_cmd cmd; - struct wds_cmd sense; - struct scsi_xfer *sxp; - int busy, polled; - int done, ret, ombn; -}; - -#define WDSX_SCSICMD 0x00 -#define WDSX_OPEN_RCVBUF 0x80 -#define WDSX_RCV_CMD 0x81 -#define WDSX_RCV_DATA 0x82 -#define WDSX_RCV_DATASTAT 0x83 -#define WDSX_SND_DATA 0x84 -#define WDSX_SND_DATASTAT 0x85 -#define WDSX_SND_CMDSTAT 0x86 -#define WDSX_READINIT 0x88 -#define WDSX_READSCSIID 0x89 -#define WDSX_SETUNSOLIRQMASK 0x8a -#define WDSX_GETUNSOLIRQMASK 0x8b -#define WDSX_GETFIRMREV 0x8c -#define WDSX_EXECDIAG 0x8d -#define WDSX_SETEXECPARM 0x8e -#define WDSX_GETEXECPARM 0x8f - -struct wds_mb { - u_char stat; - u_char addr[3]; -}; -/* ICMB status value */ -#define ICMB_OK 0x01 -#define ICMB_OKERR 0x02 -#define ICMB_ETIME 0x04 -#define ICMB_ERESET 0x05 -#define ICMB_ETARCMD 0x06 -#define ICMB_ERESEL 0x80 -#define ICMB_ESEL 0x81 -#define ICMB_EABORT 0x82 -#define ICMB_ESRESET 0x83 -#define ICMB_EHRESET 0x84 - -struct wds_setup { - u_char cmd; - u_char scsi_id; - u_char buson_t; - u_char busoff_t; - u_char xx; - u_char mbaddr[3]; - u_char nomb; - u_char nimb; -}; - -#define WDS_NOMB 16 -#define WDS_NIMB 8 -#define MAXSIMUL 8 -struct wds { - int addr; - struct wds_req wdsr[MAXSIMUL]; - struct wds_mb ombs[WDS_NOMB], imbs[WDS_NIMB]; -} wds[NWDS]; - -static int wdsunit = 0; -int wds_debug = 0; - -void p2x(u_char *, u_long); -u_char *x2p(u_char *); -int wdsprobe(struct isa_device *); -void wds_minphys(struct buf *); -struct wds_req *wdsr_alloc(int); -int wds_scsi_cmd(struct scsi_xfer *); -long wds_adapter_info(int); -int wdsintr(int); -int wds_done(int, struct wds_cmd *, u_char); -int wdsattach(struct isa_device *); -int wds_init(struct isa_device *); -int wds_cmd(int, u_char *, int); -void wds_wait(int, int, int); - - -struct scsi_switch wds_switch[NWDS]; - -struct isa_driver wdsdriver = { - wdsprobe, - wdsattach, - "wds", -}; - - -void -flushcache(void) -{ - extern main(); - volatile char *p, c; - int i; - - for(p=(char *)main, i=0; i<256*1024; i++) - c = *p++; -} - -void -p2x(u_char *p, u_long x) -{ - p[0] = (x & 0x00ff0000) >> 16; - p[1] = (x & 0x0000ff00) >> 8; - p[2] = (x & 0x000000ff); -} - -u_char * -x2p(u_char *x) -{ - u_long q; - - q = ((x[0]<<16) & 0x00ff0000) + ((x[1]<<8) & 0x0000ff00) + (x[2] & 0x000000ff); - return (u_char *)q; -} - -int -wdsprobe(struct isa_device *dev) -{ - /*scsi_debug = PRINTROUTINES | TRACEOPENS | TRACEINTERRUPTS | - SHOWREQUESTS | SHOWSCATGATH | SHOWINQUIRY | SHOWCOMMANDS;*/ - - if (dev->id_parent) - return 1; - - if(wdsunit > NWDS) - return 0; - - dev->id_unit = wdsunit; - wds[wdsunit].addr = dev->id_iobase; - - if(wds_init(dev) != 0) - return 0; - wdsunit++; - return 8; -} - -void -wds_minphys(struct buf *bp) -{ - int base = (int)bp->b_data & (PAGESIZ-1); - - if (base + bp->b_bcount > PAGESIZ) - bp->b_bcount = PAGESIZ - base; - minphys(bp); -} - -struct wds_req * -wdsr_alloc(int unit) -{ - struct wds_req *r; - int x; - int i; - - r = NULL; - x = splbio(); - for(i=0; i<MAXSIMUL; i++) - if(wds[unit].wdsr[i].busy == 0) { - r = &wds[unit].wdsr[i]; - r->busy = 1; - break; - } - if(r == NULL) { - splx(x); - return NULL; - } - - r->ombn = -1; - for(i=0; i<WDS_NOMB; i++) - if(wds[unit].ombs[i].stat==0) { - wds[unit].ombs[i].stat = 1; - r->ombn = i; - break; - } - if(r->ombn == -1 ) { - r->busy = 0; - splx(x); - return NULL; - } - splx(x); - return r; -} - -int -wds_scsi_cmd(struct scsi_xfer *sxp) -{ - struct wds_req *r; - int unit = sxp->adapter; - int base; - u_char c, *p; - int i; - - base = wds[unit].addr; - - /*printf("scsi_cmd\n");*/ - - if( sxp->flags & SCSI_RESET) { - printf("reset!\n"); - return COMPLETE; - } - - r = wdsr_alloc(unit); - if(r==NULL) { - printf("no request slot available!\n"); - sxp->error = XS_DRIVER_STUFFUP; - return TRY_AGAIN_LATER; - } - r->done = 0; - r->sxp = sxp; - - printf("wds%d: target %d/%d req %8x flags %08x len %d: ", unit, - sxp->targ, sxp->lu, r, sxp->flags, sxp->cmdlen); - for(i=0, p=(u_char *)sxp->cmd; i<sxp->cmdlen; i++) - printf("%02x ", p[i]); - printf("\n"); - printf(" data %08x datalen %08x\n", sxp->data, sxp->datalen); - - if(sxp->flags & SCSI_DATA_UIO) { - printf("UIO!\n"); - sxp->error = XS_DRIVER_STUFFUP; - return TRY_AGAIN_LATER; - } - - p2x(&wds[unit].ombs[r->ombn].addr[0], KVTOPHYS(&r->cmd)); - printf("%08x/%08x mbox@%08x: %02x %02x %02x %02x\n", - &r->cmd, KVTOPHYS(&r->cmd), &wds[unit].ombs[0], - wds[unit].ombs[r->ombn].stat, wds[unit].ombs[r->ombn].addr[0], - wds[unit].ombs[r->ombn].addr[1], wds[unit].ombs[r->ombn].addr[2]); - - bzero(&r->cmd, sizeof r->cmd); - r->cmd.cmd = WDSX_SCSICMD; - r->cmd.targ = (sxp->targ << 5) | sxp->lu; - bcopy(sxp->cmd, &r->cmd.scb, sxp->cmdlen<12 ? sxp->cmdlen : 12); - p2x(&r->cmd.len[0], sxp->datalen); - p2x(&r->cmd.data[0], sxp->datalen ? KVTOPHYS(sxp->data) : 0); - r->cmd.write = (sxp->flags&SCSI_DATA_IN)? 0x80 : 0x00; - p2x(&r->cmd.next[0], KVTOPHYS(&r->sense)); - - bzero(&r->sense, sizeof r->sense); - r->sense.cmd = r->cmd.cmd; - r->sense.targ = r->cmd.targ; - r->sense.scb.opcode = REQUEST_SENSE; - p2x(&r->sense.data[0], KVTOPHYS(&sxp->sense)); - p2x(&r->sense.len[0], sizeof sxp->sense); - r->sense.write = 0x80; - - /*printf("wdscmd: "); - for(i=0, p=(u_char *)&r->cmd; i<sizeof r->cmd; i++) - printf("%02x ", p[i]); - printf("\n");*/ - - if(sxp->flags & SCSI_NOMASK) { - outb(base+WDS_HCR, WDSH_DRQEN); - r->polled = 1; - } else - r->polled = 0; - - c = WDSC_MSTART(r->ombn); - flushcache(); - if( wds_cmd(base, &c, sizeof c) != 0) { - printf("wds%d: unable to start outgoing mbox\n", unit); - r->busy = 0; - /* XXX need to free mailbox */ - return TRY_AGAIN_LATER; - } - - delay(10000); - /*printf("%08x/%08x mbox: %02x %02x %02x %02x\n", &r->cmd, KVTOPHYS(&r->cmd), - wds[unit].ombs[r->ombn].stat, wds[unit].ombs[r->ombn].addr[0], - wds[unit].ombs[r->ombn].addr[1], wds[unit].ombs[r->ombn].addr[2]);*/ - - if(sxp->flags & SCSI_NOMASK) { -repoll: printf("wds%d: polling.", unit); - i = 0; - while( (inb(base+WDS_STAT) & WDS_IRQ) == 0) { - printf("."); - delay(10000); - if(++i == 10) { - printf("failed %02x\n", inb(base+WDS_IRQSTAT)); - /*r->busy = 0;*/ - sxp->error = XS_TIMEOUT; - return HAD_ERROR; - } - } - flushcache(); - printf("got one!\n"); - wdsintr(unit); - if(r->done) { - r->sxp->flags |= ITSDONE; - if(r->sxp->when_done) - (*r->sxp->when_done)(r->sxp->done_arg, - r->sxp->done_arg2); - r->busy = 0; - return r->ret; - } - goto repoll; - } - - outb(base+WDS_HCR, WDSH_IRQEN|WDSH_DRQEN); - printf("wds%d: successfully queued\n", unit); - return SUCCESSFULLY_QUEUED; -} - -long -wds_adapter_info(int unit) -{ - return 1; -} - -int -wdsintr(int unit) -{ - struct wds_cmd *pc, *vc; - struct wds_mb *in; - u_char stat; - u_char c; - - /*printf("stat=%02x\n", inb(wds[unit].addr + WDS_STAT));*/ - delay(1000); - c = inb(wds[unit].addr + WDS_IRQSTAT); - printf("wdsintr: %02x\n", c); - if( (c&WDSI_MASK) == WDSI_MSVC) { - delay(1000); - c = c & ~WDSI_MASK; - flushcache(); - in = &wds[unit].imbs[c]; - - printf("incoming mailbox %02x@%08x: ", c, in); - printf("%02x %02x %02x %02x\n", - in->stat, in->addr[0], in->addr[1], in->addr[2]); - pc = (struct wds_cmd *)x2p(&in->addr[0]); - vc = (struct wds_cmd *)PHYSTOKV(pc); - stat = in->stat; - printf("p=%08x v=%08x stat %02x\n", pc, vc, stat); - wds_done(unit, vc, stat); - in->stat = 0; - - outb(wds[unit].addr + WDS_IRQACK, 0xff); - } - return 1; -} - -int -wds_done(int unit, struct wds_cmd *c, u_char stat) -{ - struct wds_req *r; - int i; - - r = (struct wds_req *)NULL; - for(i=0; i<MAXSIMUL; i++) - if( c == &wds[unit].wdsr[i].cmd ) { - /*printf("found at req slot %d\n", i);*/ - r = &wds[unit].wdsr[i]; - break; - } - if(r == (struct wds_req *)NULL) { - printf("failed to find request!\n"); - return 1; - } - - printf("wds%d: cmd %8x stat %2x/%2x %2x/%2x\n", unit, c, - r->cmd.stat, r->cmd.venderr, r->sense.stat, r->sense.venderr); - - r->done = 1; - /* XXX need to free mailbox */ - r->ret = HAD_ERROR; - switch(r->cmd.stat) { - case ICMB_OK: - /*XXX r->sxp->sense.valid = 0; - r->sxp->error = 0;*/ - r->ret = COMPLETE; - break; - case ICMB_OKERR: - printf("scsi err %02x\n", c->venderr); - /*XXX r->sxp->sense.error_code = c->venderr; - r->sxp->sense.valid = 1;*/ - r->ret = COMPLETE; - break; - case ICMB_ETIME: - r->sxp->error = XS_TIMEOUT; - r->ret = HAD_ERROR; - break; - case ICMB_ERESET: - case ICMB_ETARCMD: - case ICMB_ERESEL: - case ICMB_ESEL: - case ICMB_EABORT: - case ICMB_ESRESET: - case ICMB_EHRESET: - r->sxp->error = XS_DRIVER_STUFFUP; - r->ret = HAD_ERROR; - break; - } - if(r->polled==0) { - r->sxp->flags |= ITSDONE; - if(r->sxp->when_done) - (*r->sxp->when_done)(r->sxp->done_arg, r->sxp->done_arg2); - r->busy = 0; - } - return 0; -} - -int -wds_getvers(int unit) -{ - struct wds_req *r; - int base; - u_char c, *p; - int i; - - base = wds[unit].addr; - - /*printf("scsi_cmd\n");*/ - - r = wdsr_alloc(unit); - if(r==NULL) { - printf("wds%d: no request slot available!\n", unit); - return -1; - } - r->done = 0; - r->sxp = NULL; - - printf("wds%d: getvers req %8x\n", unit, r); - - p2x(&wds[unit].ombs[r->ombn].addr[0], KVTOPHYS(&r->cmd)); - printf("%08x/%08x mbox@%08x: %02x %02x %02x %02x\n", - &r->cmd, KVTOPHYS(&r->cmd), &wds[unit].ombs[0], - wds[unit].ombs[r->ombn].stat, wds[unit].ombs[r->ombn].addr[0], - wds[unit].ombs[r->ombn].addr[1], wds[unit].ombs[r->ombn].addr[2]); - - bzero(&r->cmd, sizeof r->cmd); - r->cmd.cmd = WDSX_GETFIRMREV; - r->cmd.write = 0x80; - - printf("wdscmd: "); - for(i=0, p=(u_char *)&r->cmd; i<sizeof r->cmd; i++) - printf("%02x ", p[i]); - printf("\n"); - - outb(base+WDS_HCR, WDSH_DRQEN); - r->polled = 1; - - c = WDSC_MSTART(r->ombn); - flushcache(); - if( wds_cmd(base, &c, sizeof c) != 0) { - printf("wds%d: unable to start outgoing mbox\n", unit); - r->busy = 0; - /* XXX need to free mailbox */ - return -1; - } - - delay(10000); - /*printf("%08x/%08x mbox: %02x %02x %02x %02x\n", &r->cmd, KVTOPHYS(&r->cmd), - wds[unit].ombs[r->ombn].stat, wds[unit].ombs[r->ombn].addr[0], - wds[unit].ombs[r->ombn].addr[1], wds[unit].ombs[r->ombn].addr[2]);*/ - - while(1) { - printf("wds%d: polling.", unit); - i = 0; - while( (inb(base+WDS_STAT) & WDS_IRQ) == 0) { - printf("."); - delay(10000); - if(++i == 10) { - printf("failed %02x\n", inb(base+WDS_IRQSTAT)); - /*r->busy = 0;*/ - return -1; - } - } - flushcache(); - printf("got one!\n"); - wdsintr(unit); - if(r->done) { - printf("wds%d: version %02x %02x\n", unit, - r->cmd.targ, r->cmd.scb.opcode); - r->busy = 0; - return 0; - } - } -} - -int -wdsattach(struct isa_device *dev) -{ - int masunit; - static int firstswitch[NWDS]; - static u_long versprobe /* max 32 controllers */ - int r; - - if (!dev->id_parent) - return 1; - masunit = dev->id_parent->id_unit; - - if( !(versprobe & (1<<masunit))) { - versprobe |= (1<<masunit); - if(wds_getvers(masunit)==-1) - printf("wds%d: getvers failed\n", masunit); - } - - if (!firstswitch[masunit]) { - firstswitch[masunit] = 1; - wds_switch[masunit].name = "wds"; - wds_switch[masunit].scsi_cmd = wds_scsi_cmd; - wds_switch[masunit].scsi_minphys = wdsminphys; - wds_switch[masunit].open_target_lu = 0; - wds_switch[masunit].close_target_lu = 0; - wds_switch[masunit].adapter_info = wds_adapter_info; - for (r = 0; r < 8; r++) { - wds_switch[masunit].empty[r] = 0; - wds_switch[masunit].used[r] = 0; - wds_switch[masunit].printed[r] = 0; - } - } - r = scsi_attach(masunit, &wds_switch[masunit], &dev->id_physid, - &dev->id_unit, dev->id_flags); - return r; -} - -int -wds_init(struct isa_device *dev) -{ - struct wds_setup init; - int base; - u_char *p, c; - int unit, i; - - unit = dev->id_unit; - base = wds[unit].addr; - - /* - * Sending a command causes the CMDRDY bit to clear. - */ - c = inb(base+WDS_STAT); - for(i=0; i<4; i++) - if( (inb(base+WDS_STAT) & WDS_RDY) != 0) { - goto ready; - delay(10); - } - return 1; - -ready: - outb(base+WDS_CMD, WDSC_NOOP); - if( inb(base+WDS_STAT) & WDS_RDY) - return 1; - - /* - * the controller exists. reset and init. - */ - outb(base+WDS_HCR, WDSH_SCSIRESET|WDSH_ASCRESET); - delay(3); - outb(base+WDS_HCR, WDSH_DRQEN); - delay(20000); - -#if 1 - outb(0xd6, 0xc3); - outb(0xd4, 0x03); -#else - isa_dmacascade(dev->id_drq); -#endif - - if( (inb(base+WDS_STAT) & (WDS_RDY)) != WDS_RDY) { - printf("wds%d: waiting for controller to become ready", unit); - for(i=0; i<6; i++) { - if( (inb(base+WDS_STAT) & (WDS_RDY)) == WDS_RDY) - break; - printf("."); - delay(10000); - } - if( (inb(base+WDS_STAT) & (WDS_RDY)) != WDS_RDY) { - printf("failed\n"); - return 1; - } - } - - bzero(&init, sizeof init); - init.cmd = WDSC_INIT; - init.scsi_id = 0; - init.buson_t = 24; - init.busoff_t = 48; - p2x(&init.mbaddr[0], KVTOPHYS(&wds[unit].ombs[0])); - init.xx = 0; - init.nomb = WDS_NOMB; - init.nimb = WDS_NIMB; - - /*p = (u_char *)&init; - printf("wds%d: %08x %08x init: ", unit, - &wds[unit].ombs[0], KVTOPHYS(&wds[unit].ombs[0])); - for(i=0; i<sizeof init; i++) - printf("%02x ", p[i]); - printf("\n");*/ - - wds_wait(base+WDS_STAT, WDS_RDY, WDS_RDY); - flushcache(); - if( wds_cmd(base, (u_char *)&init, sizeof init) != 0) { - printf("wds%d: wds_cmd failed\n", unit); - return 1; - } - wds_wait(base+WDS_STAT, WDS_INIT, WDS_INIT); - - wds_wait(base+WDS_STAT, WDS_RDY, WDS_RDY); - c = WDSC_DISUNSOL; - if( wds_cmd(base, &c, sizeof c) != 0) { - printf("wds%d: wds_cmd failed\n", unit); - return 1; - } - - return 0; -} - -int -wds_cmd(int base, u_char *p, int l) -{ - int i; - u_char c; - - i = 0; - while(i < l) { - while( ((c=inb(base+WDS_STAT)) & WDS_RDY) == 0) - ; - - outb(base+WDS_CMD, *p); - - while( ((c=inb(base+WDS_STAT)) & WDS_RDY) == 0) - ; - - if(c & WDS_REJ) - return 1; - p++; - i++; - } - while( ((c=inb(base+WDS_STAT)) & WDS_RDY) == 0) - ; - if(c & WDS_REJ) - return 1; - /*printf("wds_cmd: %02x\n", inb(base+WDS_STAT));*/ - return 0; -} - -void -wds_wait(int reg, int mask, int val) -{ - while( (inb(reg) & mask) != val) - ; -} - -#endif diff --git a/sys/dev/isa/wds.c b/sys/dev/isa/wds.c new file mode 100644 index 00000000000..c102f7008af --- /dev/null +++ b/sys/dev/isa/wds.c @@ -0,0 +1,1306 @@ +/* $NetBSD: wds.c,v 1.4 1996/04/11 22:30:38 cgd Exp $ */ + +#define WDSDIAG +#define integrate + +/* + * XXX + * sense data + * aborts + * resets + */ + +/* + * Copyright (c) 1994, 1995 Julian Highfield. All rights reserved. + * Portions copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Julian Highfield. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This driver is for the WD7000 family of SCSI controllers: + * the WD7000-ASC, a bus-mastering DMA controller, + * the WD7000-FASST2, an -ASC with new firmware and scatter-gather, + * and the WD7000-ASE, which was custom manufactured for Apollo + * workstations and seems to include an -ASC as well as floppy + * and ESDI interfaces. + * + * Loosely based on Theo Deraadt's unfinished attempt. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <sys/proc.h> +#include <sys/user.h> + +#include <machine/pio.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> + +#include <dev/isa/isavar.h> +#include <dev/isa/isadmavar.h> +#include <dev/isa/wdsreg.h> + +#ifndef DDB +#define Debugger() panic("should call debugger here (wds.c)") +#endif /* ! DDB */ + +#define WDS_MBX_SIZE 16 + +#define WDS_SCB_MAX 32 +#define SCB_HASH_SIZE 32 /* hash table size for phystokv */ +#define SCB_HASH_SHIFT 9 +#define SCB_HASH(x) ((((long)(x))>>SCB_HASH_SHIFT) & (SCB_HASH_SIZE - 1)) + +#define wds_nextmbx(wmb, mbx, mbio) \ + if ((wmb) == &(mbx)->mbio[WDS_MBX_SIZE - 1]) \ + (wmb) = &(mbx)->mbio[0]; \ + else \ + (wmb)++; + +struct wds_mbx { + struct wds_mbx_out mbo[WDS_MBX_SIZE]; + struct wds_mbx_in mbi[WDS_MBX_SIZE]; + struct wds_mbx_out *cmbo; /* Collection Mail Box out */ + struct wds_mbx_out *tmbo; /* Target Mail Box out */ + struct wds_mbx_in *tmbi; /* Target Mail Box in */ +}; + +#define KVTOPHYS(x) vtophys(x) + +struct wds_softc { + struct device sc_dev; + struct isadev sc_id; + void *sc_ih; + + int sc_iobase; + int sc_irq, sc_drq; + + int sc_revision; + + struct wds_mbx sc_mbx; +#define wmbx (&sc->sc_mbx) + struct wds_scb *sc_scbhash[SCB_HASH_SIZE]; + TAILQ_HEAD(, wds_scb) sc_free_scb, sc_waiting_scb; + int sc_numscbs, sc_mbofull; + int sc_scsi_dev; + struct scsi_link sc_link; /* prototype for subdevs */ +}; + +/* Define the bounce buffer length... */ +#define BUFLEN (64*1024) +/* ..and how many there are. One per device! Non-FASST boards need these. */ +#define BUFCNT 8 +/* The macro for deciding whether the board needs a buffer. */ +#define NEEDBUFFER(sc) (sc->sc_revision < 0x800) + +struct wds_buf { + u_char data[BUFLEN]; + int busy; + TAILQ_ENTRY(wds_buf) chain; +} wds_buffer[BUFCNT]; + +TAILQ_HEAD(, wds_buf) wds_free_buffer; + +integrate void wds_wait __P((int, int, int)); +int wds_cmd __P((int, u_char *, int)); +integrate void wds_finish_scbs __P((struct wds_softc *)); +int wdsintr __P((void *)); +integrate void wds_reset_scb __P((struct wds_softc *, struct wds_scb *)); +void wds_free_scb __P((struct wds_softc *, struct wds_scb *)); +void wds_free_buf __P((struct wds_softc *, struct wds_buf *)); +integrate void wds_init_scb __P((struct wds_softc *, struct wds_scb *)); +struct wds_scb *wds_get_scb __P((struct wds_softc *, int, int)); +struct wds_buf *wds_get_buf __P((struct wds_softc *, int)); +struct wds_scb *wds_scb_phys_kv __P((struct wds_softc *, u_long)); +void wds_queue_scb __P((struct wds_softc *, struct wds_scb *)); +void wds_collect_mbo __P((struct wds_softc *)); +void wds_start_scbs __P((struct wds_softc *)); +void wds_done __P((struct wds_softc *, struct wds_scb *, u_char)); +int wds_find __P((struct isa_attach_args *, struct wds_softc *)); +void wds_init __P((struct wds_softc *)); +void wds_inquire_setup_information __P((struct wds_softc *)); +void wdsminphys __P((struct buf *)); +int wds_scsi_cmd __P((struct scsi_xfer *)); +void wds_sense __P((struct wds_softc *, struct wds_scb *)); +int wds_poll __P((struct wds_softc *, struct scsi_xfer *, int)); +int wds_ipoll __P((struct wds_softc *, struct wds_scb *, int)); +void wds_timeout __P((void *)); + +struct scsi_adapter wds_switch = { + wds_scsi_cmd, + wdsminphys, + 0, + 0, +}; + +/* the below structure is so we have a default dev struct for our link struct */ +struct scsi_device wds_dev = { + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ +}; + +int wdsprobe __P((struct device *, void *, void *)); +void wdsattach __P((struct device *, struct device *, void *)); +int wdsprint __P((void *, char *)); + +struct cfattach wds_ca = { + sizeof(struct wds_softc), wdsprobe, wdsattach +}; + +struct cfdriver wds_cd = { + NULL, "wds", DV_DULL +}; + +#define WDS_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */ + +integrate void +wds_wait(port, mask, val) + int port; + int mask; + int val; +{ + + while ((inb(port) & mask) != val) + ; +} + +/* + * Write a command to the board's I/O ports. + */ +int +wds_cmd(iobase, ibuf, icnt) + int iobase; + u_char *ibuf; + int icnt; +{ + u_char c; + + wds_wait(iobase + WDS_STAT, WDSS_RDY, WDSS_RDY); + + while (icnt--) { + outb(iobase + WDS_CMD, *ibuf++); + wds_wait(iobase + WDS_STAT, WDSS_RDY, WDSS_RDY); + c = inb(iobase + WDS_STAT); + if (c & WDSS_REJ) + return 1; + } + + return 0; +} + +/* + * Check for the presence of a WD7000 SCSI controller. + */ +int +wdsprobe(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + register struct isa_attach_args *ia = aux; + +#ifdef NEWCONFIG + if (ia->ia_iobase == IOBASEUNK) + return 0; +#endif + + /* See if there is a unit at this location. */ + if (wds_find(ia, NULL) != 0) + return 0; + + ia->ia_msize = 0; + ia->ia_iosize = 8; + return 1; +} + +int +wdsprint(aux, name) + void *aux; + char *name; +{ + + if (name != NULL) + printf("%s: scsibus ", name); + return UNCONF; +} + +/* + * Attach all available units. + */ +void +wdsattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct isa_attach_args *ia = aux; + struct wds_softc *sc = (void *)self; + + if (wds_find(ia, sc) != 0) + panic("wdsattach: wds_find of %s failed", self->dv_xname); + sc->sc_iobase = ia->ia_iobase; + + if (sc->sc_drq != DRQUNK) + isa_dmacascade(sc->sc_drq); + + wds_init(sc); + TAILQ_INIT(&sc->sc_free_scb); + TAILQ_INIT(&sc->sc_waiting_scb); + wds_inquire_setup_information(sc); + + /* + * fill in the prototype scsi_link. + */ + sc->sc_link.adapter_softc = sc; + sc->sc_link.adapter_target = sc->sc_scsi_dev; + sc->sc_link.adapter = &wds_switch; + sc->sc_link.device = &wds_dev; + /* XXX */ + /* I don't think the -ASE can handle openings > 1. */ + /* It gives Vendor Error 26 whenever I try it. */ + sc->sc_link.openings = 1; + +#ifdef NEWCONFIG + 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, wdsintr, sc, sc->sc_dev.dv_xname); + + /* + * ask the adapter what subunits are present + */ + config_found(self, &sc->sc_link, wdsprint); +} + +integrate void +wds_finish_scbs(sc) + struct wds_softc *sc; +{ + struct wds_mbx_in *wmbi; + struct wds_scb *scb; + int i; + + wmbi = wmbx->tmbi; + + if (wmbi->stat == WDS_MBI_FREE) { + for (i = 0; i < WDS_MBX_SIZE; i++) { + if (wmbi->stat != WDS_MBI_FREE) { + printf("%s: mbi not in round-robin order\n", + sc->sc_dev.dv_xname); + goto AGAIN; + } + wds_nextmbx(wmbi, wmbx, mbi); + } +#ifdef WDSDIAGnot + printf("%s: mbi interrupt with no full mailboxes\n", + sc->sc_dev.dv_xname); +#endif + return; + } + +AGAIN: + do { + scb = wds_scb_phys_kv(sc, phystol(wmbi->scb_addr)); + if (!scb) { + printf("%s: bad mbi scb pointer; skipping\n", + sc->sc_dev.dv_xname); + goto next; + } + +#ifdef WDSDEBUG + if (wds_debug) { + u_char *cp = &scb->scsi_cmd; + printf("op=%x %x %x %x %x %x\n", + cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); + printf("stat %x for mbi addr = 0x%08x, ", + wmbi->stat, wmbi); + printf("scb addr = 0x%x\n", scb); + } +#endif /* WDSDEBUG */ + + untimeout(wds_timeout, scb); + wds_done(sc, scb, wmbi->stat); + + next: + wmbi->stat = WDS_MBI_FREE; + wds_nextmbx(wmbi, wmbx, mbi); + } while (wmbi->stat != WDS_MBI_FREE); + + wmbx->tmbi = wmbi; +} + +/* + * Process an interrupt. + */ +int +wdsintr(arg) + void *arg; +{ + struct wds_softc *sc = arg; + int iobase = sc->sc_iobase; + u_char sts; + + struct wds_mbx_in *in; + struct wds_scb *scb; + u_char stat, c; + + /* Was it really an interrupt from the board? */ + if ((inb(iobase + WDS_STAT) & WDSS_IRQ) == 0) + return 0; + + /* Get the interrupt status byte. */ + c = inb(iobase + WDS_IRQSTAT) & WDSI_MASK; + + /* Acknowledge (which resets) the interrupt. */ + outb(iobase + WDS_IRQACK, 0x00); + + switch (c) { + case WDSI_MSVC: + wds_finish_scbs(sc); + break; + + case WDSI_MFREE: + wds_start_scbs(sc); + break; + + default: + printf("%s: unrecognized interrupt type %02x", c); + break; + } + + return 1; +} + +integrate void +wds_reset_scb(sc, scb) + struct wds_softc *sc; + struct wds_scb *scb; +{ + + scb->flags = 0; +} + +/* + * Free the command structure, the outgoing mailbox and the data buffer. + */ +void +wds_free_scb(sc, scb) + struct wds_softc *sc; + struct wds_scb *scb; +{ + int s; + + if (scb->buf != 0) { + wds_free_buf(sc, scb->buf); + scb->buf = 0; + } + + s = splbio(); + + wds_reset_scb(sc, scb); + TAILQ_INSERT_HEAD(&sc->sc_free_scb, scb, chain); + + /* + * If there were none, wake anybody waiting for one to come free, + * starting with queued entries. + */ + if (scb->chain.tqe_next == 0) + wakeup(&sc->sc_free_scb); + + splx(s); +} + +void +wds_free_buf(sc, buf) + struct wds_softc *sc; + struct wds_buf *buf; +{ + int s; + + s = splbio(); + + buf->busy = 0; + TAILQ_INSERT_HEAD(&wds_free_buffer, buf, chain); + + /* + * If there were none, wake anybody waiting for one to come free, + * starting with queued entries. + */ + if (buf->chain.tqe_next == 0) + wakeup(&wds_free_buffer); + + splx(s); +} + +integrate void +wds_init_scb(sc, scb) + struct wds_softc *sc; + struct wds_scb *scb; +{ + int hashnum; + + bzero(scb, sizeof(struct wds_scb)); + /* + * put in the phystokv hash table + * Never gets taken out. + */ + scb->hashkey = KVTOPHYS(scb); + hashnum = SCB_HASH(scb->hashkey); + scb->nexthash = sc->sc_scbhash[hashnum]; + sc->sc_scbhash[hashnum] = scb; + wds_reset_scb(sc, scb); +} + +/* + * Get a free scb + * + * If there are none, see if we can allocate a new one. If so, put it in + * the hash table too otherwise either return an error or sleep. + */ +struct wds_scb * +wds_get_scb(sc, flags, needbuffer) + struct wds_softc *sc; + int flags; + int needbuffer; +{ + struct wds_scb *scb; + int s; + + s = splbio(); + + /* + * If we can and have to, sleep waiting for one to come free + * but only if we can't allocate a new one. + */ + for (;;) { + scb = sc->sc_free_scb.tqh_first; + if (scb) { + TAILQ_REMOVE(&sc->sc_free_scb, scb, chain); + break; + } + if (sc->sc_numscbs < WDS_SCB_MAX) { + scb = (struct wds_scb *) malloc(sizeof(struct wds_scb), + M_TEMP, M_NOWAIT); + if (!scb) { + printf("%s: can't malloc scb\n", + sc->sc_dev.dv_xname); + goto out; + } + wds_init_scb(sc, scb); + sc->sc_numscbs++; + break; + } + if ((flags & SCSI_NOSLEEP) != 0) + goto out; + tsleep(&sc->sc_free_scb, PRIBIO, "wdsscb", 0); + } + + scb->flags |= SCB_ALLOC; + + if (needbuffer) { + scb->buf = wds_get_buf(sc, flags); + if (scb->buf == 0) + wds_free_scb(sc, scb); + scb = 0; + } + +out: + splx(s); + return (scb); +} + +struct wds_buf * +wds_get_buf(sc, flags) + struct wds_softc *sc; + int flags; +{ + struct wds_buf *buf; + int s; + + s = splbio(); + + for (;;) { + buf = wds_free_buffer.tqh_first; + if (buf) { + TAILQ_REMOVE(&wds_free_buffer, buf, chain); + break; + } + if ((flags & SCSI_NOSLEEP) != 0) + goto out; + tsleep(&wds_free_buffer, PRIBIO, "wdsbuf", 0); + } + + buf->busy = 1; + +out: + splx(s); + return (buf); +} + +struct wds_scb * +wds_scb_phys_kv(sc, scb_phys) + struct wds_softc *sc; + u_long scb_phys; +{ + int hashnum = SCB_HASH(scb_phys); + struct wds_scb *scb = sc->sc_scbhash[hashnum]; + + while (scb) { + if (scb->hashkey == scb_phys) + break; + /* XXX Check to see if it matches the sense command block. */ + if (scb->hashkey == (scb_phys - sizeof(struct wds_cmd))) + break; + scb = scb->nexthash; + } + return scb; +} + +/* + * Queue a SCB to be sent to the controller, and send it if possible. + */ +void +wds_queue_scb(sc, scb) + struct wds_softc *sc; + struct wds_scb *scb; +{ + + TAILQ_INSERT_TAIL(&sc->sc_waiting_scb, scb, chain); + wds_start_scbs(sc); +} + +/* + * Garbage collect mailboxes that are no longer in use. + */ +void +wds_collect_mbo(sc) + struct wds_softc *sc; +{ + struct wds_mbx_out *wmbo; /* Mail Box Out pointer */ + struct wds_scb *scb; + + wmbo = wmbx->cmbo; + + while (sc->sc_mbofull > 0) { + if (wmbo->cmd != WDS_MBO_FREE) + break; + +#ifdef WDSDIAG + scb = wds_scb_phys_kv(sc, phystol(wmbo->scb_addr)); + scb->flags &= ~SCB_SENDING; +#endif + + --sc->sc_mbofull; + wds_nextmbx(wmbo, wmbx, mbo); + } + + wmbx->cmbo = wmbo; +} + +/* + * Send as many SCBs as we have empty mailboxes for. + */ +void +wds_start_scbs(sc) + struct wds_softc *sc; +{ + int iobase = sc->sc_iobase; + struct wds_mbx_out *wmbo; /* Mail Box Out pointer */ + struct wds_scb *scb; + int i; + u_char c; + + wmbo = wmbx->tmbo; + + while (scb = sc->sc_waiting_scb.tqh_first) { + if (sc->sc_mbofull >= WDS_MBX_SIZE) { + wds_collect_mbo(sc); + if (sc->sc_mbofull >= WDS_MBX_SIZE) { + c = WDSC_IRQMFREE; + wds_cmd(iobase, &c, sizeof c); + break; + } + } + + TAILQ_REMOVE(&sc->sc_waiting_scb, scb, chain); +#ifdef WDSDIAG + scb->flags |= SCB_SENDING; +#endif + + /* Link scb to mbo. */ + if (scb->flags & SCB_SENSE) + ltophys(KVTOPHYS(&scb->sense), wmbo->scb_addr); + else + ltophys(KVTOPHYS(&scb->cmd), wmbo->scb_addr); + /* XXX What about aborts? */ + wmbo->cmd = WDS_MBO_START; + + /* Tell the card to poll immediately. */ + c = WDSC_MSTART(wmbo - wmbx->mbo); + wds_cmd(sc->sc_iobase, &c, sizeof c); + + if ((scb->flags & SCB_POLLED) == 0) + timeout(wds_timeout, scb, (scb->timeout * hz) / 1000); + + next: + ++sc->sc_mbofull; + wds_nextmbx(wmbo, wmbx, mbo); + } + + wmbx->tmbo = wmbo; +} + +/* + * Process the result of a SCSI command. + */ +void +wds_done(sc, scb, stat) + struct wds_softc *sc; + struct wds_scb *scb; + u_char stat; +{ + struct scsi_xfer *xs = scb->xs; + int i, x; + + /* XXXXX */ + + /* Don't release the SCB if it was an internal command. */ + if (xs == 0) { + scb->flags |= SCB_DONE; + return; + } + + /* Sense handling. */ + if (xs->error == XS_SENSE) { + bcopy(&scb->sense_data, &xs->sense, sizeof (struct scsi_sense_data)); + } else { + if (xs->error == XS_NOERROR) { + /* If all went well, or an error is acceptable. */ + if (stat == WDS_MBI_OK) { + /* OK, set the result */ + xs->resid = 0; + } else { + /* Check the mailbox status. */ + switch (stat) { + case WDS_MBI_OKERR: + /* SCSI error recorded in scb, counts as WDS_MBI_OK */ + switch (scb->cmd.venderr) { + case 0x00: + printf("%s: Is this an error?\n", sc->sc_dev.dv_xname); + xs->error = XS_DRIVER_STUFFUP; /* Experiment */ + break; + case 0x01: + /*printf("%s: OK, see SCSI error field.\n", sc->sc_dev.dv_xname);*/ + if (scb->cmd.stat == SCSI_CHECK) { + /* Do sense. */ + wds_sense (sc, scb); + return; + } else if (scb->cmd.stat == SCSI_BUSY) { + xs->error = XS_BUSY; + } + break; + case 0x40: + /*printf("%s: DMA underrun!\n", sc->sc_dev.dv_xname);*/ + /* Hits this if the target returns fewer that datalen bytes (eg my CD-ROM, + which returns a short version string, or if DMA is turned off etc. */ + xs->resid = 0; + break; + default: + printf("%s: VENDOR ERROR %02x, scsi %02x\n", sc->sc_dev.dv_xname, scb->cmd.venderr, scb->cmd.stat); + xs->error = XS_DRIVER_STUFFUP; /* Experiment */ + break; + } + break; + case WDS_MBI_ETIME: + /* + * The documentation isn't clear on + * what conditions might generate this, + * but selection timeouts are the only + * one I can think of. + */ + xs->error = XS_SELTIMEOUT; + break; + case WDS_MBI_ERESET: + case WDS_MBI_ETARCMD: + case WDS_MBI_ERESEL: + case WDS_MBI_ESEL: + case WDS_MBI_EABORT: + case WDS_MBI_ESRESET: + case WDS_MBI_EHRESET: + xs->error = XS_DRIVER_STUFFUP; + break; + } + } + } /* else sense */ + + if (NEEDBUFFER(sc) && xs->datalen) { + if (xs->flags & SCSI_DATA_IN) + bcopy(scb->buf->data, xs->data, xs->datalen); + } + } /* XS_NOERROR */ + + wds_free_scb(sc, scb); + xs->flags |= ITSDONE; + scsi_done(xs); +} + +int +wds_find(ia, sc) + struct isa_attach_args *ia; + struct wds_softc *sc; +{ + int iobase = ia->ia_iobase; + u_char c; + int i; + + /* XXXXX */ + + /* + * Sending a command causes the CMDRDY bit to clear. + */ + c = inb(iobase + WDS_STAT); + for (i = 0; i < 4; i++) + if ((inb(iobase+WDS_STAT) & WDSS_RDY) != 0) { + goto ready; + delay(10); + } + return 1; + +ready: + outb(iobase + WDS_CMD, WDSC_NOOP); + if (inb(iobase + WDS_STAT) & WDSS_RDY) + return 1; + + outb(iobase + WDS_HCR, WDSH_SCSIRESET|WDSH_ASCRESET); + delay(10000); + outb(iobase + WDS_HCR, 0x00); + delay(500000); + wds_wait(iobase + WDS_STAT, WDSS_RDY, WDSS_RDY); + if (inb(iobase + WDS_IRQSTAT) != 1) + if (inb(iobase + WDS_IRQSTAT) != 7) + printf("%s: failed reset!!! %2x\n", sc->sc_dev.dv_xname, inb(iobase + WDS_IRQSTAT)); + + if ((inb(iobase + WDS_STAT) & (WDSS_RDY)) != WDSS_RDY) { + printf("%s: waiting for controller to become ready.", sc->sc_dev.dv_xname); + for (i = 0; i < 20; i++) { + if ((inb(iobase + WDS_STAT) & (WDSS_RDY)) == WDSS_RDY) + break; + printf("."); + delay(10000); + } + if ((inb(iobase + WDS_STAT) & (WDSS_RDY)) != WDSS_RDY) { + printf(" failed\n"); + return 1; + } + printf("\n"); + } + + if (sc != NULL) { + /* XXX Can we do this better? */ + /* who are we on the scsi bus? */ + sc->sc_scsi_dev = 7; + + sc->sc_iobase = iobase; + sc->sc_irq = ia->ia_irq; + sc->sc_drq = ia->ia_drq; + } + + return 0; +} + +/* + * Initialise the board and driver. + */ +void +wds_init(sc) + struct wds_softc *sc; +{ + int iobase = sc->sc_iobase; + struct wds_setup init; + u_char c; + int i; + + /* + * Set up initial mail box for round-robin operation. + */ + for (i = 0; i < WDS_MBX_SIZE; i++) { + wmbx->mbo[i].cmd = WDS_MBO_FREE; + wmbx->mbi[i].stat = WDS_MBO_FREE; + } + wmbx->cmbo = wmbx->tmbo = &wmbx->mbo[0]; + wmbx->tmbi = &wmbx->mbi[0]; + sc->sc_mbofull = 0; + + /* Clear the buffers. */ + TAILQ_INIT(&wds_free_buffer); + for (i = 0; i < BUFCNT; i++) { + wds_buffer[i].busy = 0; + TAILQ_INSERT_HEAD(&wds_free_buffer, &wds_buffer[i], chain); + } + + init.opcode = WDSC_INIT; + init.scsi_id = sc->sc_scsi_dev; + /* Record scsi id of controller for use in scsi_attach */ + sc->sc_scsi_dev = init.scsi_id; + init.buson_t = 48; + init.busoff_t = 24; + init.xx = 0; + ltophys(KVTOPHYS(wmbx), init.mbaddr); + init.nomb = init.nimb = WDS_MBX_SIZE; + wds_cmd(iobase, (u_char *)&init, sizeof init); + + wds_wait(iobase + WDS_STAT, WDSS_INIT, WDSS_INIT); + + c = WDSC_DISUNSOL; + wds_cmd(iobase, &c, sizeof c); + + outb(iobase + WDS_HCR, WDSH_DRQEN); +} + +/* + * Read the board's firmware revision information. + */ +void +wds_inquire_setup_information(sc) + struct wds_softc *sc; +{ + struct wds_scb *scb; + int iobase; + u_char *j; + int s; + + iobase = sc->sc_iobase; + + if ((scb = wds_get_scb(sc, SCSI_NOSLEEP, 0)) == NULL) { + printf("%s: no request slot available in getvers()!\n", sc->sc_dev.dv_xname); + return; + } + scb->xs = NULL; + scb->timeout = 40; + + bzero(&scb->cmd, sizeof scb->cmd); + scb->cmd.write = 0x80; + scb->cmd.opcode = WDSX_GETFIRMREV; + + /* Will poll card, await result. */ + outb(iobase + WDS_HCR, WDSH_DRQEN); + scb->flags |= SCB_POLLED; + + s = splbio(); + wds_queue_scb(sc, scb); + splx(s); + + if (wds_ipoll(sc, scb, scb->timeout)) + goto out; + + /* Print the version number. */ + printf(": version %x.%02x ", scb->cmd.targ, scb->cmd.scb.opcode); + sc->sc_revision = (scb->cmd.targ << 8) | scb->cmd.scb.opcode; + /* Print out the version string. */ + j = 2 + &(scb->cmd.targ); + while ((*j >= 32) && (*j < 128)) { + printf("%c", *j); + j++; + } + +out: + printf("\n"); + wds_free_scb(sc, scb); +} + +void +wdsminphys(bp) + struct buf *bp; +{ + + if (bp->b_bcount > ((WDS_NSEG - 1) << PGSHIFT)) + bp->b_bcount = ((WDS_NSEG - 1) << PGSHIFT); + minphys(bp); +} + +/* + * Send a SCSI command. + */ +int +wds_scsi_cmd(xs) + struct scsi_xfer *xs; +{ + struct scsi_link *sc_link = xs->sc_link; + struct wds_softc *sc = sc_link->adapter_softc; + struct wds_scb *scb; + struct wds_scat_gath *sg; + int seg; + u_long thiskv, thisphys, nextphys; + int bytes_this_seg, bytes_this_page, datalen, flags; + struct iovec *iovp; + int s; + + int iobase; + + iobase = sc->sc_iobase; + + if (xs->flags & SCSI_RESET) { + /* XXX Fix me! */ + printf("%s: reset!\n", sc->sc_dev.dv_xname); + wds_init(sc); + return COMPLETE; + } + + flags = xs->flags; + if ((scb = wds_get_scb(sc, flags, NEEDBUFFER(sc))) == NULL) { + xs->error = XS_DRIVER_STUFFUP; + return TRY_AGAIN_LATER; + } + scb->xs = xs; + scb->timeout = xs->timeout; + + if (xs->flags & SCSI_DATA_UIO) { + /* XXX Fix me! */ + /* Let's not worry about UIO. There isn't any code for the * + * non-SG boards anyway! */ + printf("%s: UIO is untested and disabled!\n", sc->sc_dev.dv_xname); + goto bad; + } + + /* Zero out the command structure. */ + bzero(&scb->cmd, sizeof scb->cmd); + bcopy(xs->cmd, &scb->cmd.scb, xs->cmdlen < 12 ? xs->cmdlen : 12); + + /* Set up some of the command fields. */ + scb->cmd.targ = (xs->sc_link->target << 5) | xs->sc_link->lun; + + /* NOTE: cmd.write may be OK as 0x40 (disable direction checking) + * on boards other than the WD-7000V-ASE. Need this for the ASE: + */ + scb->cmd.write = (xs->flags & SCSI_DATA_IN) ? 0x80 : 0x00; + + if (!NEEDBUFFER(sc) && xs->datalen) { + sg = scb->scat_gath; + seg = 0; +#ifdef TFS + if (flags & SCSI_DATA_UIO) { + iovp = ((struct uio *)xs->data)->uio_iov; + datalen = ((struct uio *)xs->data)->uio_iovcnt; + xs->datalen = 0; + while (datalen && seg < WDS_NSEG) { + ltophys(iovp->iov_base, sg->seg_addr); + ltophys(iovp->iov_len, sg->seg_len); + xs->datalen += iovp->iov_len; + SC_DEBUGN(sc_link, SDEV_DB4, ("UIO(0x%x@0x%x)", + iovp->iov_len, iovp->iov_base)); + sg++; + iovp++; + seg++; + datalen--; + } + } else +#endif /* TFS */ + { + /* + * Set up the scatter-gather block. + */ + SC_DEBUG(sc_link, SDEV_DB4, + ("%d @0x%x:- ", xs->datalen, xs->data)); + + datalen = xs->datalen; + thiskv = (int)xs->data; + thisphys = KVTOPHYS(xs->data); + + while (datalen && seg < WDS_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++; + } + } + /* 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: wds_scsi_cmd, more than %d dma segs\n", + sc->sc_dev.dv_xname, WDS_NSEG); + goto bad; + } + scb->cmd.opcode = WDSX_SCSISG; + ltophys(KVTOPHYS(scb->scat_gath), scb->cmd.data); + ltophys(seg * sizeof(struct wds_scat_gath), scb->cmd.len); + } else if (xs->datalen > 0) { + /* The board is an ASC or ASE. Do not use scatter/gather. */ + if (xs->datalen > BUFLEN) { + printf("%s: wds_scsi_cmd, I/O too large for bounce buffer\n", + sc->sc_dev.dv_xname); + goto bad; + } + if (xs->flags & SCSI_DATA_OUT) + bcopy(xs->data, scb->buf->data, xs->datalen); + else + bzero(scb->buf->data, xs->datalen); + scb->cmd.opcode = WDSX_SCSICMD; + ltophys(KVTOPHYS(scb->buf->data), scb->cmd.data); + ltophys(xs->datalen, scb->cmd.len); + } else { + scb->cmd.opcode = WDSX_SCSICMD; + ltophys(0, scb->cmd.data); + ltophys(0, scb->cmd.len); + } + + scb->cmd.stat = 0x00; + scb->cmd.venderr = 0x00; + ltophys(0, scb->cmd.link); + + /* XXX Do we really want to do this? */ + if (flags & SCSI_POLL) { + /* Will poll card, await result. */ + outb(iobase + WDS_HCR, WDSH_DRQEN); + scb->flags |= SCB_POLLED; + } else { + /* Will send command, let interrupt routine handle result. */ + outb(iobase + WDS_HCR, WDSH_IRQEN | WDSH_DRQEN); + } + + s = splbio(); + wds_queue_scb(sc, scb); + splx(s); + + if ((flags & SCSI_POLL) == 0) + return SUCCESSFULLY_QUEUED; + + if (wds_poll(sc, xs, scb->timeout)) { + wds_timeout(scb); + if (wds_poll(sc, xs, scb->timeout)) + wds_timeout(scb); + } + return COMPLETE; + +bad: + xs->error = XS_DRIVER_STUFFUP; + wds_free_scb(sc, scb); + return COMPLETE; +} + +/* + * Send a sense request. + */ +void +wds_sense(sc, scb) + struct wds_softc *sc; + struct wds_scb *scb; +{ + struct scsi_xfer *xs = scb->xs; + struct scsi_sense *ss = (void *)&scb->sense.scb; + int s; + u_char c; + int i; + + /* XXXXX */ + + /* Send sense request SCSI command. */ + xs->error = XS_SENSE; + scb->flags |= SCB_SENSE; + + /* First, save the return values */ + if (NEEDBUFFER(sc) && xs->datalen) { + if (xs->flags & SCSI_DATA_IN) + bcopy(scb->buf->data, xs->data, xs->datalen); + } + + /* Next, setup a request sense command block */ + bzero(ss, sizeof(*ss)); + ss->opcode = REQUEST_SENSE; + ss->byte2 = xs->sc_link->lun << 5; + ss->length = sizeof(struct scsi_sense_data); + + /* Set up some of the command fields. */ + scb->sense.targ = scb->cmd.targ; + scb->sense.write = 0x80; + scb->sense.opcode = WDSX_SCSICMD; + ltophys(KVTOPHYS(&scb->sense_data), scb->sense.data); + ltophys(sizeof(struct scsi_sense_data), scb->sense.len); + + s = splbio(); + wds_queue_scb(sc, scb); + splx(s); + + /* + * There's no reason for us to poll here. There are two cases: + * 1) If it's a polling operation, then we're called from the interrupt + * handler, and we return and continue polling. + * 2) If it's an interrupt-driven operation, then it gets completed + * later on when the REQUEST SENSE finishes. + */ +} + +/* + * Poll a particular unit, looking for a particular scb + */ +int +wds_poll(sc, xs, count) + struct wds_softc *sc; + struct scsi_xfer *xs; + int count; +{ + int iobase = sc->sc_iobase; + + /* timeouts are in msec, so we loop in 1000 usec cycles */ + while (count) { + /* + * If we had interrupts enabled, would we + * have got an interrupt? + */ + if (inb(iobase + WDS_STAT) & WDSS_IRQ) + wdsintr(sc); + if (xs->flags & ITSDONE) + return 0; + delay(1000); /* only happens in boot so ok */ + count--; + } + return 1; +} + +/* + * Poll a particular unit, looking for a particular scb + */ +int +wds_ipoll(sc, scb, count) + struct wds_softc *sc; + struct wds_scb *scb; + int count; +{ + int iobase = sc->sc_iobase; + + /* timeouts are in msec, so we loop in 1000 usec cycles */ + while (count) { + /* + * If we had interrupts enabled, would we + * have got an interrupt? + */ + if (inb(iobase + WDS_STAT) & WDSS_IRQ) + wdsintr(sc); + if (scb->flags & SCB_DONE) + return 0; + delay(1000); /* only happens in boot so ok */ + count--; + } + return 1; +} + +void +wds_timeout(arg) + void *arg; +{ + struct wds_scb *scb = arg; + struct scsi_xfer *xs = scb->xs; + struct scsi_link *sc_link = xs->sc_link; + struct wds_softc *sc = sc_link->adapter_softc; + int s; + + sc_print_addr(sc_link); + printf("timed out"); + + s = splbio(); + +#ifdef WDSDIAG + /* + * If The scb's mbx is not free, then the board has gone south? + */ + wds_collect_mbo(sc); + if (scb->flags & SCB_SENDING) { + printf("%s: not taking commands!\n", sc->sc_dev.dv_xname); + Debugger(); + } +#endif + + /* + * If it has been through before, then + * a previous abort has failed, don't + * try abort again + */ + if (scb->flags & SCB_ABORT) { + /* abort timed out */ + printf(" AGAIN\n"); + /* XXX Must reset! */ + } else { + /* abort the operation that has timed out */ + printf("\n"); + scb->xs->error = XS_TIMEOUT; + scb->timeout = WDS_ABORT_TIMEOUT; + scb->flags |= SCB_ABORT; + wds_queue_scb(sc, scb); + } + + splx(s); +} diff --git a/sys/dev/isa/wdsreg.h b/sys/dev/isa/wdsreg.h new file mode 100644 index 00000000000..e4f7bdafce7 --- /dev/null +++ b/sys/dev/isa/wdsreg.h @@ -0,0 +1,147 @@ +typedef u_char physaddr[3]; +typedef u_char physlen[3]; +#define ltophys _lto3b +#define phystol _3btol + +/* WD7000 registers */ +#define WDS_STAT 0 /* read */ +#define WDS_IRQSTAT 1 /* read */ + +#define WDS_CMD 0 /* write */ +#define WDS_IRQACK 1 /* write */ +#define WDS_HCR 2 /* write */ + +/* WDS_STAT (read) defs */ +#define WDSS_IRQ 0x80 +#define WDSS_RDY 0x40 +#define WDSS_REJ 0x20 +#define WDSS_INIT 0x10 + +/* WDS_IRQSTAT (read) defs */ +#define WDSI_MASK 0xc0 +#define WDSI_ERR 0x00 +#define WDSI_MFREE 0x80 +#define WDSI_MSVC 0xc0 + +/* WDS_CMD (write) defs */ +#define WDSC_NOOP 0x00 +#define WDSC_INIT 0x01 +#define WDSC_DISUNSOL 0x02 +#define WDSC_ENAUNSOL 0x03 +#define WDSC_IRQMFREE 0x04 +#define WDSC_SCSIRESETSOFT 0x05 +#define WDSC_SCSIRESETHARD 0x06 +#define WDSC_MSTART(m) (0x80 + (m)) +#define WDSC_MMSTART(m) (0xc0 + (m)) + +/* WDS_HCR (write) defs */ +#define WDSH_IRQEN 0x08 +#define WDSH_DRQEN 0x04 +#define WDSH_SCSIRESET 0x02 +#define WDSH_ASCRESET 0x01 + +#define WDS_NSEG 17 + +struct wds_scat_gath { + physlen seg_len; + physaddr seg_addr; +}; + +struct wds_cmd { + u_char opcode; + u_char targ; + struct scsi_generic scb; + u_char stat; + u_char venderr; + physlen len; + physaddr data; + physaddr link; + u_char write; + u_char xx[6]; +}; + +struct wds_scb { + struct wds_cmd cmd; + struct wds_cmd sense; + + struct wds_scat_gath scat_gath[WDS_NSEG]; + struct scsi_sense_data sense_data; + + TAILQ_ENTRY(wds_scb) chain; + struct wds_scb *nexthash; + long hashkey; + struct scsi_xfer *xs; + int flags; +#define SCB_ALLOC 0x01 +#define SCB_ABORT 0x02 +#ifdef WDSDIAG +#define SCB_SENDING 0x04 +#endif +#define SCB_POLLED 0x08 +#define SCB_SENSE 0x10 +#define SCB_DONE 0x20 /* for internal commands only */ +#define SCB_BUFFER 0x40 + int timeout; + + struct wds_buf *buf; +}; + +#define WDSX_SCSICMD 0x00 +#define WDSX_SCSISG 0x01 +#define WDSX_OPEN_RCVBUF 0x80 +#define WDSX_RCV_CMD 0x81 +#define WDSX_RCV_DATA 0x82 +#define WDSX_RCV_DATASTAT 0x83 +#define WDSX_SND_DATA 0x84 +#define WDSX_SND_DATASTAT 0x85 +#define WDSX_SND_CMDSTAT 0x86 +#define WDSX_READINIT 0x88 +#define WDSX_READSCSIID 0x89 +#define WDSX_SETUNSOLIRQMASK 0x8a +#define WDSX_GETUNSOLIRQMASK 0x8b +#define WDSX_GETFIRMREV 0x8c +#define WDSX_EXECDIAG 0x8d +#define WDSX_SETEXECPARM 0x8e +#define WDSX_GETEXECPARM 0x8f + +struct wds_mbx_out { + u_char cmd; + physaddr scb_addr; +}; + +struct wds_mbx_in { + u_char stat; + physaddr scb_addr; +}; + +/* + * mbo.cmd values + */ +#define WDS_MBO_FREE 0x0 /* MBO entry is free */ +#define WDS_MBO_START 0x1 /* MBO activate entry */ + +/* + * mbi.stat values + */ +#define WDS_MBI_FREE 0x00 /* MBI entry is free */ +#define WDS_MBI_OK 0x01 /* completed without error */ +#define WDS_MBI_OKERR 0x02 /* completed with error */ +#define WDS_MBI_ETIME 0x04 +#define WDS_MBI_ERESET 0x05 +#define WDS_MBI_ETARCMD 0x06 +#define WDS_MBI_ERESEL 0x80 +#define WDS_MBI_ESEL 0x81 +#define WDS_MBI_EABORT 0x82 +#define WDS_MBI_ESRESET 0x83 +#define WDS_MBI_EHRESET 0x84 + +struct wds_setup { + u_char opcode; + u_char scsi_id; + u_char buson_t; + u_char busoff_t; + u_char xx; + physaddr mbaddr; + u_char nomb; + u_char nimb; +}; diff --git a/sys/dev/isa/wss.c b/sys/dev/isa/wss.c index 6080334ede5..ba0b2fb7df2 100644 --- a/sys/dev/isa/wss.c +++ b/sys/dev/isa/wss.c @@ -1,5 +1,5 @@ -/* $OpenBSD: wss.c,v 1.7 1996/03/20 01:01:06 mickey Exp $ */ -/* $NetBSD: wss.c,v 1.9 1996/02/16 08:18:36 mycroft Exp $ */ +/* $OpenBSD: wss.c,v 1.8 1996/04/21 22:24:49 deraadt Exp $ */ +/* $NetBSD: wss.c,v 1.11 1996/04/11 22:30:46 cgd Exp $ */ /* * Copyright (c) 1994 John Brezak @@ -165,8 +165,12 @@ struct audio_hw_if wss_hw_if = { int wssprobe __P((struct device *, void *, void *)); void wssattach __P((struct device *, struct device *, void *)); -struct cfdriver wsscd = { - NULL, "wss", wssprobe, wssattach, DV_DULL, sizeof(struct wss_softc) +struct cfattach wss_ca = { + sizeof(struct wss_softc), wssprobe, wssattach +}; + +struct cfdriver wss_cd = { + NULL, "wss", DV_DULL }; /* @@ -250,8 +254,8 @@ wssattach(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_AUDIO, ad1848_intr, - &sc->sc_ad1848, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, IPL_AUDIO, + ad1848_intr, &sc->sc_ad1848, sc->sc_dev.dv_xname); ad1848_attach(&sc->sc_ad1848); @@ -306,10 +310,10 @@ wssopen(dev, flags) struct wss_softc *sc; int unit = AUDIOUNIT(dev); - if (unit >= wsscd.cd_ndevs) + if (unit >= wss_cd.cd_ndevs) return ENODEV; - sc = wsscd.cd_devs[unit]; + sc = wss_cd.cd_devs[unit]; if (!sc) return ENXIO; diff --git a/sys/dev/isa/wt.c b/sys/dev/isa/wt.c index 8fe5e81811f..70e051a7694 100644 --- a/sys/dev/isa/wt.c +++ b/sys/dev/isa/wt.c @@ -1,5 +1,5 @@ -/* $OpenBSD: wt.c,v 1.7 1996/04/18 23:47:52 niklas Exp $ */ -/* $NetBSD: wt.c,v 1.29 1996/03/01 04:08:40 mycroft Exp $ */ +/* $OpenBSD: wt.c,v 1.8 1996/04/21 22:24:52 deraadt Exp $ */ +/* $NetBSD: wt.c,v 1.31 1996/04/11 22:30:49 cgd Exp $ */ /* * Streamer tape driver. @@ -168,8 +168,12 @@ int wtprobe __P((struct device *, void *, void *)); void wtattach __P((struct device *, struct device *, void *)); int wtintr __P((void *sc)); -struct cfdriver wtcd = { - NULL, "wt", wtprobe, wtattach, DV_TAPE, sizeof(struct wt_softc) +struct cfattach wt_ca = { + sizeof(struct wt_softc), wtprobe, wtattach +}; + +struct cfdriver wt_cd = { + NULL, "wt", DV_TAPE }; /* @@ -250,8 +254,8 @@ wtattach(parent, self, aux) sc->flags = TPSTART; /* tape is rewound */ sc->dens = -1; /* unknown density */ - sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_BIO, wtintr, - sc, sc->sc_dev.dv_xname); + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_BIO, wtintr, sc, sc->sc_dev.dv_xname); } int @@ -287,9 +291,9 @@ wtopen(dev, flag) struct wt_softc *sc; int error; - if (unit >= wtcd.cd_ndevs) + if (unit >= wt_cd.cd_ndevs) return ENXIO; - sc = wtcd.cd_devs[unit]; + sc = wt_cd.cd_devs[unit]; if (!sc) return ENXIO; @@ -372,7 +376,7 @@ wtclose(dev) dev_t dev; { int unit = minor(dev) & T_UNIT; - struct wt_softc *sc = wtcd.cd_devs[unit]; + struct wt_softc *sc = wt_cd.cd_devs[unit]; /* If rewind is pending, do nothing */ if (sc->flags & TPREW) @@ -426,7 +430,7 @@ wtioctl(dev, cmd, addr, flag) int flag; { int unit = minor(dev) & T_UNIT; - struct wt_softc *sc = wtcd.cd_devs[unit]; + struct wt_softc *sc = wt_cd.cd_devs[unit]; int error, count, op; switch (cmd) { @@ -526,7 +530,7 @@ wtstrategy(bp) struct buf *bp; { int unit = minor(bp->b_dev) & T_UNIT; - struct wt_softc *sc = wtcd.cd_devs[unit]; + struct wt_softc *sc = wt_cd.cd_devs[unit]; int s; bp->b_resid = bp->b_bcount; |