diff options
author | gibbs <gibbs@FreeBSD.org> | 1998-09-15 10:40:55 +0000 |
---|---|---|
committer | gibbs <gibbs@FreeBSD.org> | 1998-09-15 10:40:55 +0000 |
commit | 79200df6729d1afbc24596e05c0bee54a2544616 (patch) | |
tree | 454f8a346e1e8ffbde91ed6c5a172835b1d7d78c /sys/i386 | |
parent | 4035fc4bcc3a3a3a921bfaa090dd3f7f02b9737a (diff) | |
download | FreeBSD-src-79200df6729d1afbc24596e05c0bee54a2544616.zip FreeBSD-src-79200df6729d1afbc24596e05c0bee54a2544616.tar.gz |
Obsoleted by CAM.
Diffstat (limited to 'sys/i386')
-rw-r--r-- | sys/i386/isa/aha1542.c | 1851 | ||||
-rw-r--r-- | sys/i386/scsi/93cx6.c | 181 | ||||
-rw-r--r-- | sys/i386/scsi/93cx6.h | 93 | ||||
-rw-r--r-- | sys/i386/scsi/advansys.c | 783 | ||||
-rw-r--r-- | sys/i386/scsi/advansys.h | 50 | ||||
-rw-r--r-- | sys/i386/scsi/aic7xxx.c | 3867 | ||||
-rw-r--r-- | sys/i386/scsi/aic7xxx.h | 403 | ||||
-rw-r--r-- | sys/i386/scsi/bt.c | 1583 | ||||
-rw-r--r-- | sys/i386/scsi/btreg.h | 149 |
9 files changed, 0 insertions, 8960 deletions
diff --git a/sys/i386/isa/aha1542.c b/sys/i386/isa/aha1542.c deleted file mode 100644 index b5f17a6..0000000 --- a/sys/i386/isa/aha1542.c +++ /dev/null @@ -1,1851 +0,0 @@ -/* - * (Mostly) 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. - * - * $Id: aha1542.c,v 1.78 1998/06/21 14:53:07 bde Exp $ - */ - -/* - * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 - */ - -#include "aha.h" -#include "opt_tune_1542.h" - -#include <sys/param.h> -#include <sys/buf.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/systm.h> - -#include <machine/clock.h> -#include <machine/stdarg.h> - -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> - -#include <vm/vm.h> -#include <vm/pmap.h> - -#include <i386/isa/isa_device.h> - -/************************** board definitions *******************************/ - -/* - * I/O Port Interface - */ - -#define AHA_BASE aha->aha_base -#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 */ - -struct aha_cmd_buf { - u_char byte[16]; -}; - -/* - * 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 */ - -struct aha_mbx { - struct aha_mbx_out { - unsigned char cmd; - unsigned char ccb_addr[3]; - } mbo[AHA_MBX_SIZE]; - struct aha_mbx_in { - unsigned char stat; - unsigned char ccb_addr[3]; - } mbi[AHA_MBX_SIZE]; -}; - -/* - * 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 */ - -#define AHA_MBI_TGT_NO_CCB 0x10 /* Target received, no CCB ready */ - -/* 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_ccb { - unsigned char opcode; - unsigned char lun:3; - unsigned char data_in:1; /* must be 0 */ - unsigned char data_out:1; /* must be 0 */ - unsigned char target:3; - unsigned char scsi_cmd_length; - unsigned char req_sense_length; - unsigned char data_length[3]; - unsigned char data_addr[3]; - unsigned char link_addr[3]; - unsigned char link_id; - unsigned char host_stat; - unsigned char target_stat; - unsigned char reserved[2]; - struct scsi_generic scsi_cmd; - struct scsi_sense_data scsi_sense; - struct aha_scat_gath { - unsigned char seg_len[3]; - unsigned char seg_addr[3]; - } scat_gath[AHA_NSEG]; - struct aha_ccb *next; - struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ - struct aha_mbx_out *mbx; /* pointer to mail box */ - int flags; -#define CCB_FREE 0 -#define CCB_ACTIVE 1 -#define CCB_ABORTED 2 -}; - -/* - * 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 */ - -#define AHA_INIT_RESID_CCB 0x03 /* SCSI Initiator CCB */ -#define AHA_INIT_SG_RESID_CCB 0x04 /* SCSI initiator with scatter gather */ - -/* - * 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 */ - /* 0x20 (' ') = BusLogic 545, but it gets - the command wrong, only returns - one byte */ - /* 0x31 ('1') = AHA-1540 */ - /* 0x41 ('A') = AHA-1540A/1542A/1542B */ - /* 0x42 ('B') = AHA-1640 */ - /* 0x43 ('C') = AHA-1542C */ - /* 0x44 ('D') = AHA-1542CF */ - /* 0x45 ('E') = AHA-1542CF, BIOS v2.01 */ - /* 0x46 ('F') = AHA-1542CP, "Plug'nPlay" */ - 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***************/ - -#define PHYSTOKV(x) ((intptr_t)(((long int)(x)) ^ aha->kv_phys_xor)) -#define KVTOPHYS(x) vtophys(x) -#define AHA_DMA_PAGES AHA_NSEG - -#define PAGESIZ 4096 - -#ifdef AHADEBUG -int aha_debug = 1; -#endif /*AHADEBUG */ - -static struct aha_data { - int aha_base; /* base port for each board */ - /* - * xor this with a physaddr to get a kv addr and visa versa - * for items in THIS STRUCT only. - * Used to get the CCD's physical and kv addresses from each - * other. - */ - long int kv_phys_xor; - struct aha_mbx aha_mbx; /* all the mailboxes */ - struct aha_ccb *aha_ccb_free; /* the next free ccb */ - struct aha_ccb aha_ccb[AHA_MBX_SIZE]; /* all the CCBs */ - int unit; /* unit number */ - int aha_int; /* irq level */ - int aha_dma; /* DMA req channel */ - int aha_scsi_dev; /* scsi bus address */ - int flags; - - /* We use different op codes for different revs of the board - * if we think residual codes will work. - */ - short init_opcode; /* Command to use for initiator */ - short sg_opcode; /* Command to use for scatter/gather */ - struct scsi_link sc_link; /* prototype for subdevs */ -} *ahadata[NAHA]; - -static u_int32_t aha_adapter_info __P((int unit)); -static int ahaattach __P((struct isa_device *dev)); -#ifdef TUNE_1542 -static int aha_bus_speed_check __P((struct aha_data *aha, int speed)); -static int aha_set_bus_speed __P((struct aha_data *aha)); -#endif -static int aha_cmd __P((struct aha_data *aha, int icnt, int ocnt, int wait, - u_char *retval, u_char opcode, ...)); -static void aha_done __P((struct aha_data *aha, struct aha_ccb *ccb)); -static int aha_escape __P((struct scsi_xfer *xs, struct aha_ccb *ccb)); -static void aha_free_ccb __P((struct aha_data *aha, struct aha_ccb *ccb, - int flags)); -static struct aha_ccb * - aha_get_ccb __P((struct aha_data *aha, int flags)); -static int aha_init __P((struct aha_data *aha)); -static void ahaminphys __P((struct buf *bp)); -static int aha_poll __P((struct aha_data *aha, struct scsi_xfer *xs, - struct aha_ccb *ccb)); -static int ahaprobe __P((struct isa_device *dev)); -static int32_t aha_scsi_cmd __P((struct scsi_xfer *xs)); -static timeout_t - aha_timeout; -static char *board_rev __P((struct aha_data *aha, int type)); -static int physcontig __P((int kv, int len)); -static void put_host_stat __P((int host_stat)); - -static struct scsi_adapter aha_switch = -{ - aha_scsi_cmd, - ahaminphys, - 0, - 0, - aha_adapter_info, - "aha", - { 0, 0 } -}; - -/* the below structure is so we have a default dev struct for out link struct */ -static 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 */ - "aha", - 0, - { 0, 0 } -}; - -struct isa_driver ahadriver = -{ - ahaprobe, - ahaattach, - "aha" -}; - -static int ahaunit = 0; - -#define aha_abortmbx(mbx) \ - (mbx)->cmd = AHA_MBO_ABORT; \ - outb(AHA_CMD_DATA_PORT, AHA_START_SCSI); -#define aha_startmbx(mbx) \ - (mbx)->cmd = AHA_MBO_START; \ - outb(AHA_CMD_DATA_PORT, AHA_START_SCSI); - -#define AHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */ - -/* - * aha_cmd(struct aha_data *aha,icnt, ocnt,wait, retval, opcode, ...) - * 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, etc - * ... : parameters to the command specified by opcode - * - * 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. - * - */ -static int -#ifdef __STDC__ -aha_cmd(struct aha_data *aha, int icnt, int ocnt, int wait, u_char *retval, - u_char opcode, ... ) -#else -aha_cmd(aha, icnt, ocnt, wait, retval, opcode, va_alist) - struct aha_data *aha, - int icnt, - int ocnt, - int wait, - u_char *retval, - u_char opcode, - va_dcl -#endif -{ - va_list ap; - u_char oc; - u_char data; - register int 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("aha%d: aha_cmd, host not idle(0x%x)\n", - aha->unit, 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. - */ - va_start(ap, opcode); - for(data = opcode; icnt >=0; icnt--, data = (u_char)va_arg(ap, int)) { - 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 == 0) { - printf("aha%d: aha_cmd, cmd/data port full\n", - aha->unit); - outb(AHA_CTRL_STAT_PORT, AHA_SRST); - return (ENXIO); - } - outb(AHA_CMD_DATA_PORT, data); - } - /* - * 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 == 0) { - printf("aha%d: aha_cmd, cmd/data port empty %d\n", - aha->unit, ocnt); - 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 == 0) { - printf("aha%d: aha_cmd, host not finished(0x%x)\n", - aha->unit, 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 - */ -static int -ahaprobe(dev) - struct isa_device *dev; -{ - int unit = ahaunit; - struct aha_data *aha; - - /* - * find unit and check we have that many defined - */ - if (unit >= NAHA) { - printf("aha%d: unit number too high\n", unit); - return 0; - } - dev->id_unit = unit; - - /* - * a quick safety check so we can be sleazy later - */ - if (sizeof(struct aha_data) > PAGESIZ) { - printf("aha struct > pagesize\n"); - return 0; - } - /* - * Allocate a storage area for us - */ - if (ahadata[unit]) { - printf("aha%d: memory already allocated\n", unit); - return 0; - } - aha = malloc(sizeof(struct aha_data), M_TEMP, M_NOWAIT); - if (!aha) { - printf("aha%d: cannot malloc!\n", unit); - return 0; - } - bzero(aha, sizeof(struct aha_data)); - ahadata[unit] = aha; - aha->unit = unit; - aha->aha_base = dev->id_iobase; - - /* - * Try initialise a unit at this location - * sets up dma and bus speed, loads aha->aha_int - */ - if (aha_init(aha) != 0) { - ahadata[unit] = NULL; - free(aha, M_TEMP); - return 0; - } - /* - * Calculate the xor product of the aha struct's - * physical and virtual address. This allows us - * to change addresses within the structure - * from physical to virtual easily, as long as - * the structure is less than 1 page in size. - * This is used to recognise CCBs which are in - * this struct and which are refered to by the - * hardware using physical addresses. - * (assumes malloc returns a chunk that doesn't - * span pages) - * eventually use the hash table in aha1742.c - */ - aha->kv_phys_xor = (intptr_t) aha ^ (KVTOPHYS(aha)); - - /* - * If it's there, put in it's interrupt vectors - */ - dev->id_irq = (1 << aha->aha_int); - dev->id_drq = aha->aha_dma; - ahaunit++; - return 0x4; -} - -/* - * Attach all the sub-devices we can find - */ -static int -ahaattach(dev) - struct isa_device *dev; -{ - int unit = dev->id_unit; - struct aha_data *aha = ahadata[unit]; - struct scsibus_data *scbus; - - /* - * fill in the prototype scsi_link. - */ - aha->sc_link.adapter_unit = unit; - aha->sc_link.adapter_targ = aha->aha_scsi_dev; - aha->sc_link.adapter_softc = aha; - aha->sc_link.adapter = &aha_switch; - aha->sc_link.device = &aha_dev; - aha->sc_link.flags = aha->flags;; - - /* - * Prepare the scsibus_data area for the upperlevel - * scsi code. - */ - scbus = scsi_alloc_bus(); - if(!scbus) - return 0; - scbus->adapter_link = &aha->sc_link; - - /* - * ask the adapter what subunits are present - */ - scsi_attachdevs(scbus); - - return 1; -} - -/* - * Return some information to the caller about the adapter and its - * capabilities. - */ -static u_int32_t -aha_adapter_info(unit) - int unit; -{ - return (2); /* 2 outstanding requests at a time per device */ -} - -/* - * Catch an interrupt from the adaptor - */ -void -ahaintr(unit) - int unit; -{ - unsigned char stat; - register int i; - struct aha_data *aha = ahadata[unit]; - -#ifdef AHADEBUG - printf("ahaintr "); -#endif /*AHADEBUG */ - /* - * First acknowledge the interrupt, Then if it's not telling about - * a completed operation just return. - */ - stat = inb(AHA_INTR_PORT); - outb(AHA_CTRL_STAT_PORT, AHA_IRST); - if (!(stat & AHA_MBIF)) - return; -#ifdef AHADEBUG - printf("mbxin "); -#endif /*AHADEBUG */ - /* - * If it IS then process the completed operation - */ - for (i = 0; i < AHA_MBX_SIZE; i++) { - struct aha_mbx_in *mbi = aha->aha_mbx.mbi + i; - - if (mbi->stat != AHA_MBI_FREE) { - struct aha_ccb *ccb = - (struct aha_ccb *)PHYSTOKV(scsi_3btou(mbi->ccb_addr)); - - stat = mbi->stat; - - switch (stat) { - case AHA_MBI_OK: - break; - - case AHA_MBI_ABORT: -#ifdef AHADEBUG - if (aha_debug) - printf("abort"); -#endif /*AHADEBUG */ - ccb->host_stat = AHA_ABORTED; - break; - - case AHA_MBI_TGT_NO_CCB: - /* We enabled target mode and received a SEND - * or RECEIVE command from the initiator, but - * we don't have any CCB registered to handle the command. - * At this point it would be nice to wakeup a - * process sleeping on this event via an ioctl, - * returning whether it is a SEND or RECEIVE and the - * required length. - * However, I want to look at the CAM documentation before - * I start extending the API at all. - */ -#ifdef NOISE_WHEN_TGT_NO_CDB - printf("Target received, but no CCB ready.\n"); - printf("Initiator & lun: %02x\n", mbi->ccb_addr[0]); - printf("Max data length: %06x\n", - (mbi->ccb_addr[1] << 16) | (mbi->ccb_addr[2] << 8) - + 255); -#endif -#ifdef AHADEBUG - if (aha_debug) - printf("target-no-ccb"); -#endif /*AHADEBUG */ - ccb = 0; - break; - - case AHA_MBI_UNKNOWN: - ccb = 0; -#ifdef AHADEBUG - if (aha_debug) - printf("unknown ccb for abort "); -#endif /*AHADEBUG */ - /* may have missed it */ - /* no such ccb known for abort */ - - case AHA_MBI_ERROR: - /* XXX ccb is still set up? Driver fails without it? */ - break; - - default: - panic("Impossible mbxi status"); - - } -#ifdef AHADEBUG - if (aha_debug && ccb && stat != AHA_MBI_OK) { - u_char *cp; - cp = (u_char *) (&(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[%d]\n" - ,mbi->stat, i); - printf("addr = 0x%x\n", ccb); - } -#endif /*AHADEBUG */ - if (ccb) { - untimeout(aha_timeout, (caddr_t)ccb, - ccb->xfer->timeout_ch); - aha_done(aha, ccb); - } - mbi->stat = AHA_MBI_FREE; - } - } -} - -/* - * A ccb (and hence a mbx-out) is put onto the - * free list. - */ -static void -aha_free_ccb(aha, ccb, flags) - struct aha_data *aha; - struct aha_ccb *ccb; - int flags; -{ - unsigned int opri = 0; - - if (!(flags & SCSI_NOMASK)) - opri = splbio(); - - ccb->next = aha->aha_ccb_free; - aha->aha_ccb_free = ccb; - ccb->flags = CCB_FREE; - /* - * If there were none, wake anybody waiting for - * one to come free, starting with queued entries - */ - if (!ccb->next) { - wakeup((caddr_t)&aha->aha_ccb_free); - } - if (!(flags & SCSI_NOMASK)) - splx(opri); -} - -/* - * Get a free ccb (and hence mbox-out entry) - */ -static struct aha_ccb * -aha_get_ccb(aha, flags) - struct aha_data *aha; - int flags; -{ - unsigned opri = 0; - struct aha_ccb *rc; - - if (!(flags & SCSI_NOMASK)) - opri = splbio(); - /* - * If we can and have to, sleep waiting for one - * to come free - */ - while ((!(rc = aha->aha_ccb_free)) && (!(flags & SCSI_NOSLEEP))) { - tsleep((caddr_t)&aha->aha_ccb_free, PRIBIO, "ahaccb", 0); - } - if (rc) { - aha->aha_ccb_free = aha->aha_ccb_free->next; - rc->flags = CCB_ACTIVE; - } - if (!(flags & SCSI_NOMASK)) - splx(opri); - return (rc); -} - -static void -put_host_stat(int host_stat) -{ - int i; - - struct { int host_stat; char *text; } tab[] = { - { AHA_OK, "Cmd ok" }, - { AHA_LINK_OK, "Link cmd ok" }, - { AHA_LINK_IT, "Link cmd ok + int" }, - { AHA_SEL_TIMEOUT, "Selection time out" }, - { AHA_OVER_UNDER, "Data over/under run" }, - { AHA_BUS_FREE, "Bus dropped at unexpected time" }, - { AHA_INV_BUS, "Invalid bus phase/sequence" }, - { AHA_BAD_MBO, "Incorrect MBO cmd" }, - { AHA_BAD_CCB, "Incorrect ccb opcode" }, - { AHA_BAD_LINK, "Not same values of LUN for links" }, - { AHA_INV_TARGET, "Invalid target direction" }, - { AHA_CCB_DUP, "Duplicate CCB received" }, - { AHA_INV_CCB, "Invalid CCB or segment list" }, - { AHA_ABORTED, "Software abort" }, - }; - - for (i = 0; i < (int)(sizeof(tab) / sizeof(tab[0])); i++) { - if (tab[i].host_stat == host_stat) { - printf("%s\n", tab[i].text); - return; - } - } - - printf("Unknown host_stat %02x\n", host_stat); -} - -/* - * 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 - */ -static void -aha_done(aha, ccb) - struct aha_data *aha; - struct aha_ccb *ccb; -{ - struct scsi_sense_data *s1, *s2; - struct scsi_xfer *xs = ccb->xfer; - - 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)) { - printf("aha%d: exiting but not in use!\n", aha->unit); -#ifdef DIAGNOSTIC - panic("aha1542 exiting but not in use"); -#endif - } - xs->status = ccb->target_stat; - xs->resid = 0; - - if (((ccb->host_stat != AHA_OK) || (ccb->target_stat != SCSI_OK)) - && ((xs->flags & SCSI_ERR_OK) == 0)) { - /* - * We have an error, that we cannot ignore. - */ - s1 = (struct scsi_sense_data *) (((char *) (&ccb->scsi_cmd)) - + ccb->scsi_cmd_length); - s2 = &(xs->sense); - - if (ccb->host_stat) { - SC_DEBUG(xs->sc_link, SDEV_DB3, ("host err 0x%x\n", - ccb->host_stat)); - switch (ccb->host_stat) { - case AHA_ABORTED: - xs->error = XS_TIMEOUT; - break; - case AHA_SEL_TIMEOUT: - xs->error = XS_SELTIMEOUT; - break; - - case AHA_OVER_UNDER: /* Over run / under run */ - switch(ccb->opcode) - { - case AHA_TARGET_CCB: - xs->resid = xs->datalen - scsi_3btoi(ccb->data_length); - xs->flags |= SCSI_RESID_VALID; - if (xs->resid <= 0) - xs->error = XS_LENGTH; - break; - - case AHA_INIT_RESID_CCB: - case AHA_INIT_SG_RESID_CCB: - xs->resid = scsi_3btoi(ccb->data_length); - xs->flags |= SCSI_RESID_VALID; - if (xs->resid <= 0) - xs->error = XS_LENGTH; - break; - - default: - xs->error = XS_LENGTH; - } - break; - - default: /* Other scsi protocol messes */ - xs->error = XS_DRIVER_STUFFUP; - printf("aha%d: ", aha->unit); - put_host_stat(ccb->host_stat); - } - } else { - SC_DEBUG(xs->sc_link, SDEV_DB3, ("target err 0x%x\n", - ccb->target_stat)); - switch (ccb->target_stat) { - case 0x02: - /* structure copy!!!!! */ - *s2 = *s1; - xs->error = XS_SENSE; - break; - case 0x08: - xs->error = XS_BUSY; - break; - default: - printf("aha%d:target_stat%x\n", - aha->unit, ccb->target_stat); - xs->error = XS_DRIVER_STUFFUP; - } - } - } - - xs->flags |= ITSDONE; - aha_free_ccb(aha, ccb, xs->flags); - scsi_done(xs); -} - -/* Macro to determine that a rev is potentially a new valid one - * so that the driver doesn't keep breaking on new revs as it - * did for the CF and CP. - */ -#define PROBABLY_NEW_BOARD(REV) (REV > 0x43 && REV < 0x56) - -static char *board_rev(struct aha_data *aha, int type) -{ - switch(type) - { - case 0x20: return "Buslogic 545?"; - case 0x31: return "AHA-1540"; - case 0x41: return "AHA-154x[AB]"; - case 0x42: return "AHA-1640"; - case 0x43: return "AHA-1542C"; - case 0x44: return "AHA-1542CF"; - case 0x45: return "AHA-1542CF BIOS v2.01"; - case 0x46: return "AHA-1542CP"; - - default: - - - if (PROBABLY_NEW_BOARD(type)) - { - printf("aha%d: Assuming type %02x is a new board.\n", - aha->unit, type); - return "New Adaptec rev?"; - } - - printf("aha%d: type %02x is an unknown board.\n", - aha->unit, type); - return "Unknown board"; - } -} - -/* - * Start the board, ready for normal operation - */ -static int -aha_init(aha) - struct aha_data *aha; -{ - char *desc; - unsigned char ad[3]; - volatile int i, sts; - struct aha_config conf; - struct aha_inquire inquire; - struct aha_extbios extbios; - - /* Assume that residual codes don't work. If they - * do we enable that after we figure out what kind of - * board it is. - */ - aha->init_opcode = AHA_INITIATOR_CCB; - aha->sg_opcode = AHA_INIT_SCAT_GATH_CCB; - - /* - * 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 */ - } -#ifdef AHADEBUG - printf("aha_init: AHA_RESET_TIMEOUT went to %d\n", i); -#endif /* AHADEBUG */ - if (i == 0) { -#ifdef AHADEBUG - if (aha_debug) - printf("aha_init: No answer from 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 AHA_INQUIRE - * command fails, blatter about it, nuke the boardid so the 1542C - * stuff gets skipped over, and reset the board again. - */ - if(aha_cmd(aha, 0, sizeof(inquire), 1, - (u_char *)&inquire, AHA_INQUIRE)) { - /* - * Blah.. not a real adaptec board!!! - * Seems that the Buslogic 545S and the DTC3290 both get - * this wrong. - */ - printf ("aha%d: not a REAL adaptec board, may cause warnings\n", - aha->unit); - inquire.boardid = 0; - 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 */ - } -#ifdef AHADEBUG - printf("aha_init2: AHA_RESET_TIMEOUT went to %d\n", i); -#endif /* AHADEBUG */ - if (i == 0) { -#ifdef AHADEBUG - if (aha_debug) - printf("aha_init2: No answer from board\n"); -#endif /*AHADEBUG */ - return (ENXIO); - } - } -#ifdef AHADEBUG - printf("aha%d: inquire %x, %x, %x, %x\n", - aha->unit, - inquire.boardid, inquire.spec_opts, - inquire.revision_1, inquire.revision_2); -#endif /* AHADEBUG */ - - aha->flags = SDEV_BOUNCE; - -#define PRVERBOSE(x) if (bootverbose) printf x - - /* - * If we are a new type of 1542 board (anything newer than a 1542C) - * then disable the extended bios so that the - * mailbox interface is unlocked. - * This is also true for the 1542B Version 3.20. First Adaptec - * board that supports >1Gb drives. - * No need to check the extended bios flags as some of the - * extensions that cause us problems are not flagged in that byte. - */ - desc = board_rev(aha, inquire.boardid); - - PRVERBOSE( ("aha%d: Rev %02x (%s) V%c.%c", - aha->unit, inquire.boardid, desc, inquire.revision_1, - inquire.revision_2) ); - - if (PROBABLY_NEW_BOARD(inquire.boardid) || - (inquire.boardid == 0x41 - && inquire.revision_1 == 0x31 && inquire.revision_2 == 0x34)) { - aha_cmd(aha, 0, sizeof(extbios), 0, - (u_char *)&extbios, AHA_EXT_BIOS); -#ifdef AHADEBUG - printf("aha%d: extended bios flags %x\n", aha->unit, extbios.flags); -#endif /* AHADEBUG */ - - PRVERBOSE( (", enabling mailbox") ); - - aha_cmd(aha, 2, 0, 0, 0, AHA_MBX_ENABLE, - 0, extbios.mailboxlock); - } - - /* Which boards support residuals? Some early 1542A's apparently - * don't. The 1542B with V0.5 of the software does, so I've - * arbitrarily set that as the earliest rev. - */ - if (PROBABLY_NEW_BOARD(inquire.boardid) || - (inquire.boardid == 0x41 - && (inquire.revision_1 > '0' || inquire.revision_2 >= '5'))) { - - PRVERBOSE( (", enabling residuals") ); - - aha->init_opcode = AHA_INIT_RESID_CCB; - aha->sg_opcode = AHA_INIT_SG_RESID_CCB; - } - - /* Which boards support target operations? The 1542C completely - * locks up the SCSI bus if you enable them. I'm only sure - * about the B, which was sold in the OEM market as a target - * board. - */ - if (inquire.boardid == 0x41) { - PRVERBOSE( (", target ops") ); - aha->flags |= SDEV_TARGET_OPS; - } - - PRVERBOSE( ("\n") ); - - /* - * setup dma channel from jumpers and save int - * level - */ - PRVERBOSE(("aha%d: reading board settings, ", aha->unit)); - - if (inquire.boardid == 0x20) { - DELAY(1000); /* for Bustek 545 */ - } - - aha_cmd(aha, 0, sizeof(conf), 0, (u_char *)&conf, AHA_CONF_GET); - switch (conf.chan) { - case CHAN0: - outb(0x0b, 0x0c); - outb(0x0a, 0x00); - aha->aha_dma = 0; - break; - case CHAN5: - outb(0xd6, 0xc1); - outb(0xd4, 0x01); - aha->aha_dma = 5; - break; - case CHAN6: - outb(0xd6, 0xc2); - outb(0xd4, 0x02); - aha->aha_dma = 6; - break; - case CHAN7: - outb(0xd6, 0xc3); - outb(0xd4, 0x03); - aha->aha_dma = 7; - break; - default: - printf("aha%d: illegal dma jumper setting\n", aha->unit); - return (EIO); - } - - PRVERBOSE( ("dma=%d ", aha->aha_dma) ); - - switch (conf.intr) { - case INT9: - aha->aha_int = 9; - break; - case INT10: - aha->aha_int = 10; - break; - case INT11: - aha->aha_int = 11; - break; - case INT12: - aha->aha_int = 12; - break; - case INT14: - aha->aha_int = 14; - break; - case INT15: - aha->aha_int = 15; - break; - default: - printf("aha%d: illegal int jumper setting\n", aha->unit); - return (EIO); - } - - PRVERBOSE( ("int=%d ", aha->aha_int) ); - - /* who are we on the scsi bus? */ - aha->aha_scsi_dev = conf.scsi_dev; - - PRVERBOSE( ("id=%d ", aha->aha_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); - -#ifdef TUNE_1542 - /* - * Initialize memory transfer speed - * Not compiled in by default because it breaks some machines - */ - if (!(aha_set_bus_speed(aha))) { - return (EIO); - } -#else - PRVERBOSE( (" (bus speed defaulted)\n") ); -#endif /*TUNE_1542*/ - /* - * Initialize mail box - */ - scsi_uto3b(KVTOPHYS(&aha->aha_mbx), ad); - - aha_cmd(aha, 4, 0, 0, 0, AHA_MBX_INIT, - AHA_MBX_SIZE, - ad[0], - ad[1], - ad[2]); - - /* - * link the ccb's with the mbox-out entries and - * into a free-list - * this is a kludge but it works - */ - for (i = 0; i < AHA_MBX_SIZE; i++) { - aha->aha_ccb[i].next = aha->aha_ccb_free; - aha->aha_ccb_free = &aha->aha_ccb[i]; - aha->aha_ccb_free->flags = CCB_FREE; - aha->aha_ccb_free->mbx = &aha->aha_mbx.mbo[i]; - scsi_uto3b(KVTOPHYS(aha->aha_ccb_free), aha->aha_mbx.mbo[i].ccb_addr); - } - /* - * Note that we are going and return (to probe) - */ - return 0; -} - -static void -ahaminphys(bp) - struct buf *bp; -{ -/* aha seems to explode with 17 segs (64k may require 17 segs) */ -/* on old boards so use a max of 16 segs if you have problems here */ - if (bp->b_bcount > ((AHA_NSEG - 1) * PAGESIZ)) { - bp->b_bcount = ((AHA_NSEG - 1) * PAGESIZ); - } -} - -static int -aha_escape(xs, ccb) - struct scsi_xfer *xs; - struct aha_ccb *ccb; -{ - int ret = 0; - int s; - - if (xs->cmd) - { - switch(xs->cmd->opcode) - { - case SCSI_OP_RESET: - ccb->opcode = AHA_RESET_CCB; - ret = 0; - break; - - case SCSI_OP_TARGET: - s= splbio(); - aha_cmd((struct aha_data *)xs->sc_link->adapter_softc, - 2, 0, 0, 0, AHA_TARGET_EN, - (int)xs->cmd->bytes[0], (int)1); - splx(s); - ret = COMPLETE; - break; - - default: - ret = ESCAPE_NOT_SUPPORTED; - break; - } - } - else - { - ccb->opcode = AHA_RESET_CCB; - ret = 0; - } - - return ret; -} - -#define physdb(ARG) (void)(ARG) - -/* physcontig: Scan forward from a KV and return length to the - * end of physically contiguous addresses. This belongs in - * i386/.../something_or_other.c - * XXX: Find the right thing in the kernel. - */ -static int physcontig(int kv, int len) -{ - int len_was = len; - u_long kvl = (u_long)kv; - - int phys_len; - u_long phys, prev_phys; - - prev_phys = KVTOPHYS(kvl); - - /* We go at least to the end of this page: - */ - phys_len = PAGESIZ - (prev_phys & (PAGESIZ - 1)); - len -= phys_len; - kvl += phys_len; - prev_phys &= ~(PAGESIZ - 1); - - while (len > 0) - { - phys = KVTOPHYS(kvl); - - if (phys != prev_phys + PAGESIZ) - { - physdb(("phys %08x != prev_phys %08x + PAGESIZ\n", - phys, prev_phys)); - - break; - } - - prev_phys = phys; - kvl += PAGESIZ; - len -= PAGESIZ; - } - - phys_len = (len < 0) ? len_was : (len_was - len); - - physdb(("physcontig(%08x, %d) = %d\n", kv, len_was, phys_len)); - - return phys_len; -} -/* - * start a scsi operation given the command and - * the data address. Also needs the unit, target - * and lu - */ -static int32_t -aha_scsi_cmd(xs) - struct scsi_xfer *xs; -{ - struct scsi_link *sc_link = xs->sc_link; - struct aha_data *aha; - struct aha_ccb *ccb; - struct aha_scat_gath *sg; - int seg; /* scatter gather seg being worked on */ - int thiskv; - int thisphys, nextphys; - int bytes_this_seg, bytes_this_page, datalen, flags; - int s; - - aha = (struct aha_data *)sc_link->adapter_softc; - - SC_DEBUG(xs->sc_link, SDEV_DB2, ("aha_scsi_cmd\n")); - /* - * get a ccb (mbox-out) 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 (!(ccb = aha_get_ccb(aha, flags))) { - xs->error = XS_DRIVER_STUFFUP; - return (TRY_AGAIN_LATER); - } - if (ccb->mbx->cmd != AHA_MBO_FREE) - printf("aha%d: MBO %02x and not %02x (free)\n", - aha->unit, ccb->mbx->cmd, AHA_MBO_FREE); - - /* - * Put all the arguments for the xfer in the ccb - */ - ccb->xfer = xs; - if (flags & SCSI_RESET) { - ccb->opcode = AHA_RESET_CCB; - } else { - /* can't use S/G if zero length */ - ccb->opcode = (xs->datalen ? - aha->sg_opcode - : aha->init_opcode); - } - ccb->target = sc_link->target; - ccb->data_out = 0; - ccb->data_in = 0; - ccb->lun = sc_link->lun; - ccb->scsi_cmd_length = xs->cmdlen; - - /* Some devices (e.g, Microtek ScanMaker II) - * fall on the ground if you ask for anything but - * an exact number of sense bytes (wiping out the - * sense data) - * XXX: This was lost at some point in scsi_ioctl.c. - */ - ccb->req_sense_length = (xs->req_sense_length) - ? xs->req_sense_length - : sizeof(ccb->scsi_sense); - - /* XXX: I propose we move the reset handling into the escape - * handling. - */ - if (flags & SCSI_RESET) { - flags |= SCSI_ESCAPE; - xs->cmd->opcode = SCSI_OP_RESET; - } - - /* Set up the CCB. For an escape function, the escape hook may - * set it up for us. - */ - - if (flags & SCSI_ESCAPE) { - int ret; - ret = aha_escape(xs, ccb); - if (ret) - return ret; - } - else if (flags & SCSI_TARGET) - { - ccb->opcode = AHA_TARGET_CCB; - - /* These must be set up for target mode: - */ - if (flags & SCSI_DATA_IN) - ccb->data_in = 1; - if (flags & SCSI_DATA_OUT) - ccb->data_out = 1; - } - else - { - ccb->opcode = (xs->datalen? /* can't use S/G if zero length */ - AHA_INIT_SCAT_GATH_CCB - :AHA_INITIATOR_CCB); - } - - switch(ccb->opcode) - { - case AHA_TARGET_CCB: - if (xs->data) - scsi_uto3b(KVTOPHYS((int)xs->data), ccb->data_addr); - else - scsi_uto3b(0, ccb->data_addr); - - /* For non scatter-gather I/O (and Target mode doesn't do - * scatter-gather) we need to truncate the transfer - * at the first non consecutive physical address. - */ - scsi_uto3b(physcontig((int)xs->data, xs->datalen), ccb->data_length); - break; - - /* This should be folded in with TARGET_CCB once - * physcontig is debugged. - */ - case AHA_INITIATOR_CCB: - case AHA_INIT_RESID_CCB: - - if (xs->data) - scsi_uto3b(KVTOPHYS((int)xs->data), ccb->data_addr); - else - scsi_uto3b(0, ccb->data_addr); - - scsi_uto3b(xs->datalen, ccb->data_length); - break; - - case AHA_RESET_CCB: - scsi_uto3b(0, ccb->data_addr); - scsi_uto3b(0, ccb->data_length); - break; - - case AHA_INIT_SCAT_GATH_CCB: - case AHA_INIT_SG_RESID_CCB: - scsi_uto3b(KVTOPHYS(ccb->scat_gath), ccb->data_addr ); - sg = ccb->scat_gath ; - seg = 0; -#ifdef TFS_ONLY - if (flags & SCSI_DATA_UIO) { - iovp = ((struct uio *) xs->data)->uio_iov; - datalen = ((struct uio *) xs->data)->uio_iovcnt; - while ((datalen) && (seg < AHA_NSEG)) { - scsi_uto3b(iovp->iov_base, sg->seg_addr); - scsi_uto3b(iovp->iov_len, sg->seg_len); - SC_DEBUGN(xs->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 - */ - - SC_DEBUG(xs->sc_link, SDEV_DB4, - ("%ld @%p:- ", xs->datalen, xs->data)); - datalen = xs->datalen; - thiskv = (int) xs->data; - thisphys = KVTOPHYS(thiskv); - - while ((datalen) && (seg < AHA_NSEG)) { - bytes_this_seg = 0; - - /* put in the base address */ - scsi_uto3b(thisphys, sg->seg_addr); - - SC_DEBUGN(xs->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("aha%d: DMA beyond" - " end Of ISA: 0x%x\n", - aha->unit, thisphys); - xs->error = XS_DRIVER_STUFFUP; - aha_free_ccb(aha, ccb, flags); - return (HAD_ERROR); - } - /** how far to the end of the page ***/ - nextphys = (thisphys & (~(PAGESIZ - 1))) - + PAGESIZ; - 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 & (~(PAGESIZ - 1))) - + PAGESIZ; - if (datalen) - thisphys = KVTOPHYS(thiskv); - } - /* - * next page isn't contiguous, finish the seg - */ - SC_DEBUGN(xs->sc_link, SDEV_DB4, - ("(0x%x)", bytes_this_seg)); - scsi_uto3b(bytes_this_seg, sg->seg_len); - sg++; - seg++; - } - } - scsi_uto3b(seg * sizeof(struct aha_scat_gath), ccb->data_length); - SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n")); - - if (datalen) { /* there's still data, must have run out of segs! */ - printf("aha%d: aha_scsi_cmd, more than %d DMA segs\n", - aha->unit, AHA_NSEG); - xs->error = XS_DRIVER_STUFFUP; - aha_free_ccb(aha, ccb, flags); - return (HAD_ERROR); - } - break; - - default: - printf("aha_scsi_cmd%d: Illegal CCB opcode.\n", aha->unit); - xs->error = XS_DRIVER_STUFFUP; - aha_free_ccb(aha,ccb,flags); - return HAD_ERROR; - } - - scsi_uto3b(0, ccb->link_addr); - /* - * Put the scsi command in the ccb and start it - */ - if (!(flags & SCSI_ESCAPE)) - bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmd_length); - if (!(flags & SCSI_NOMASK)) { - s = splbio(); /* stop instant timeouts */ - xs->timeout_ch = timeout(aha_timeout, (caddr_t)ccb, - (xs->timeout * hz) / 1000); - aha_startmbx(ccb->mbx); - /* - * Usually return SUCCESSFULLY QUEUED - */ - splx(s); - SC_DEBUG(xs->sc_link, SDEV_DB3, ("sent\n")); - return (SUCCESSFULLY_QUEUED); - } - aha_startmbx(ccb->mbx); - SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd sent, waiting\n")); - - /* - * If we can't use interrupts, poll on completion - */ - return (aha_poll(aha, xs, ccb)); /* only during boot */ -} - -/* - * Poll a particular unit, looking for a particular xs - */ -static int -aha_poll(aha, xs, ccb) - struct aha_data *aha; - struct scsi_xfer *xs; - struct aha_ccb *ccb; -{ - int count = xs->timeout; - u_char stat; - - /*timeouts are in msec, so we loop in 1000uSec cycles */ - while (count) { - /* - * If we had interrupts enabled, would we - * have got an interrupt? - */ - stat = inb(AHA_INTR_PORT); - if (stat & AHA_ANY_INTR) { - ahaintr(aha->unit); - } - if (xs->flags & ITSDONE) { - break; - } - DELAY(1000); /* only happens in boot so ok */ - count--; - } - if (count == 0) { - /* - * We timed out, so call the timeout handler - * manually, accout for the fact that the - * clock is not running yet by taking out the - * clock queue entry it makes - */ - aha_timeout((caddr_t)ccb); - - /* - * because we are polling, - * take out the timeout entry aha_timeout made - */ - untimeout(aha_timeout, (caddr_t)ccb, ccb->xfer->timeout_ch); - count = 2000; - while (count) { - /* - * Once again, wait for the int bit - */ - stat = inb(AHA_INTR_PORT); - if (stat & AHA_ANY_INTR) { - ahaintr(aha->unit); - } - if (xs->flags & ITSDONE) { - break; - } - DELAY(1000); /* only happens in boot so ok */ - count--; - } - if (count == 0) { - /* - * We timed out again.. this is bad - * Notice that this time there is no - * clock queue entry to remove - */ - aha_timeout((caddr_t)ccb); - } - } - if (xs->error) - return (HAD_ERROR); - return (COMPLETE); - -} - -#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 -{ - char arg; - int nsecs; -}aha_bus_speeds[] = -{ - {0x88,100}, - {0x99,150}, - {0xaa,200}, - {0xbb,250}, - {0xcc,300}, - {0xdd,350}, - {0xee,400}, - {0xff,450} -}; - -static int -aha_set_bus_speed(aha) - struct aha_data *aha; -{ - int speed; - int lastworking; - int retval,retval2; - - lastworking = -1; - speed = 7; - while (1) { - retval = aha_bus_speed_check(aha,speed); - if(retval != 0) { - lastworking = speed; - } - if((retval == 0) || (speed == 0)) { - if(lastworking == -1) { - printf("No working bus speed for aha154X\n"); - return 0; - } - printf("%d nSEC ok, using " - ,aha_bus_speeds[lastworking].nsecs); - if(lastworking == 7) { /* is slowest already */ - printf("marginal "); - } else { - lastworking++; - } - retval2 = aha_bus_speed_check(aha,lastworking); - if(retval2 == 0) { - printf("test retry failed.. aborting.\n"); - return 0; - } - printf("%d nSEC\n",retval2); - return retval2 ; - - } - speed--; - } -} - -/* - * 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 HAD_ERROR. - */ -static char aha_test_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz!@"; - -u_char aha_scratch_buf[256]; - -static int -aha_bus_speed_check(aha, speed) - struct aha_data *aha; - int speed; -{ - int numspeeds = sizeof(aha_bus_speeds) / sizeof(struct bus_speed); - int loopcount; - u_char ad[3]; - - /* - * Check we have such an entry - */ - if (speed >= numspeeds) - return (HAD_ERROR); /* illegal speed */ - - /* - * 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 - * its address. Read it onto the board - */ - scsi_uto3b(KVTOPHYS(aha_scratch_buf), ad); - for(loopcount = 2000;loopcount;loopcount--) - { - strcpy(aha_scratch_buf, aha_test_string); - - 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); /* 54 bytes transfered by test */ - - aha_cmd(aha, 3, 0, 0, 0, AHA_READ_FIFO, ad[0], ad[1], ad[2]); - - /* - * Compare the original data and the final data and - * return the correct value depending upon the result - */ - if (strcmp(aha_test_string, aha_scratch_buf)) - return 0; /* failed test */ - } - /* copy succeded assume speed ok */ - - return (aha_bus_speeds[speed].nsecs); - -} -#endif /*TUNE_1542*/ - -static void -aha_timeout(void *arg1) -{ - struct aha_ccb * ccb = (struct aha_ccb *)arg1; - int s = splbio(); - struct aha_data *aha; - - aha = (struct aha_data *)ccb->xfer->sc_link->adapter_softc; - sc_print_addr(ccb->xfer->sc_link); - printf("timed out "); - - /* - * If The ccb's mbx is not free, then - * the board has gone south - */ - if (ccb->mbx->cmd != AHA_MBO_FREE) { - printf("\nadapter not taking commands.. frozen?!\n"); -#ifdef DIAGNOSTIC - panic("aha1542 frozen"); -#endif - } - /* - * 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->xfer->retries = 0; /* I MEAN IT ! */ - ccb->host_stat = AHA_ABORTED; - aha_done(aha, ccb); - } else { - /* abort the operation that has timed out */ - printf("\n"); - aha_abortmbx(ccb->mbx); - /* 4 secs for the abort */ - ccb->xfer->timeout_ch = timeout(aha_timeout, - (caddr_t)ccb, 4 * hz); - ccb->flags = CCB_ABORTED; - } splx(s); -} diff --git a/sys/i386/scsi/93cx6.c b/sys/i386/scsi/93cx6.c deleted file mode 100644 index 6a1ecb1..0000000 --- a/sys/i386/scsi/93cx6.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Interface for the 93C66/56/46/26/06 serial eeprom parts. - * - * Copyright (c) 1995, 1996 Daniel M. Eischen - * 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 immediately at the beginning of the file, without modification, - * 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. Absolutely no warranty of function or purpose is made by the author - * Daniel M. Eischen. - * 4. Modifications may be freely made to this file if the above conditions - * are met. - * - * $Id: 93cx6.c,v 1.10 1997/02/22 09:38:36 peter Exp $ - */ - -/* - * The instruction set of the 93C66/56/46/26/06 chips are as follows: - * - * Start OP * - * Function Bit Code Address** Data Description - * ------------------------------------------------------------------- - * READ 1 10 A5 - A0 Reads data stored in memory, - * starting at specified address - * EWEN 1 00 11XXXX Write enable must preceed - * all programming modes - * ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0 - * WRITE 1 01 A5 - A0 D15 - D0 Writes register - * ERAL 1 00 10XXXX Erase all registers - * WRAL 1 00 01XXXX D15 - D0 Writes to all registers - * EWDS 1 00 00XXXX Disables all programming - * instructions - * *Note: A value of X for address is a don't care condition. - * **Note: There are 8 address bits for the 93C56/66 chips unlike - * the 93C46/26/06 chips which have 6 address bits. - * - * The 93C46 has a four wire interface: clock, chip select, data in, and - * data out. In order to perform one of the above functions, you need - * to enable the chip select for a clock period (typically a minimum of - * 1 usec, with the clock high and low a minimum of 750 and 250 nsec - * respectively). While the chip select remains high, you can clock in - * the instructions (above) starting with the start bit, followed by the - * OP code, Address, and Data (if needed). For the READ instruction, the - * requested 16-bit register contents is read from the data out line but - * is preceded by an initial zero (leading 0, followed by 16-bits, MSB - * first). The clock cycling from low to high initiates the next data - * bit to be sent from the chip. - * - */ - -#include <sys/param.h> -#include <sys/systm.h> -#if defined(__FreeBSD__) -#include <i386/scsi/93cx6.h> -#elif defined(__NetBSD__) -#include <machine/bus.h> -#include <dev/ic/smc93cx6var.h> -#endif - -/* - * Right now, we only have to read the SEEPROM. But we make it easier to - * add other 93Cx6 functions. - */ -static struct seeprom_cmd { - unsigned char len; - unsigned char bits[3]; -} seeprom_read = {3, {1, 1, 0}}; - -/* - * Wait for the SEERDY to go high; about 800 ns. - */ -#define CLOCK_PULSE(sd, rdy) \ - while ((SEEPROM_INB(sd) & rdy) == 0) { \ - ; /* Do nothing */ \ - } - -/* - * Read the serial EEPROM and returns 1 if successful and 0 if - * not successful. - */ -int -read_seeprom(sd, buf, start_addr, count) - struct seeprom_descriptor *sd; - u_int16_t *buf; -#if defined(__FreeBSD__) - u_int start_addr; - u_int count; -#elif defined(__NetBSD__) - bus_io_size_t start_addr; - bus_io_size_t count; -#endif -{ - int i = 0; - u_int k = 0; - u_int16_t v; - u_int8_t temp; - - /* - * Read the requested registers of the seeprom. The loop - * will range from 0 to count-1. - */ - for (k = start_addr; k < count + start_addr; k++) { - /* Send chip select for one clock cycle. */ - temp = sd->sd_MS ^ sd->sd_CS; - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - - /* - * Now we're ready to send the read command followed by the - * address of the 16-bit register we want to read. - */ - for (i = 0; i < seeprom_read.len; i++) { - if (seeprom_read.bits[i] != 0) - temp ^= sd->sd_DO; - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - if (seeprom_read.bits[i] != 0) - temp ^= sd->sd_DO; - } - /* Send the 6 or 8 bit address (MSB first, LSB last). */ - for (i = (sd->sd_chip - 1); i >= 0; i--) { - if ((k & (1 << i)) != 0) - temp ^= sd->sd_DO; - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - if ((k & (1 << i)) != 0) - temp ^= sd->sd_DO; - } - - /* - * Now read the 16 bit register. An initial 0 precedes the - * register contents which begins with bit 15 (MSB) and ends - * with bit 0 (LSB). The initial 0 will be shifted off the - * top of our word as we let the loop run from 0 to 16. - */ - v = 0; - for (i = 16; i >= 0; i--) { - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - v <<= 1; - if (SEEPROM_INB(sd) & sd->sd_DI) - v |= 1; - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - } - - buf[k - start_addr] = v; - - /* Reset the chip select for the next command cycle. */ - temp = sd->sd_MS; - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - } -#if 0 - printf ("Serial EEPROM:"); - for (k = 0; k < count; k = k + 1) { - if (((k % 8) == 0) && (k != 0)) - { - printf ("\n "); - } - printf (" 0x%x", buf[k]); - } - printf ("\n"); -#endif - return (1); -} diff --git a/sys/i386/scsi/93cx6.h b/sys/i386/scsi/93cx6.h deleted file mode 100644 index a253e75..0000000 --- a/sys/i386/scsi/93cx6.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Interface to the 93C46 serial EEPROM that is used to store BIOS - * settings for the aic7xxx based adaptec SCSI controllers. It can - * also be used for 93C26 and 93C06 serial EEPROMS. - * - * Copyright (c) 1994, 1995 Justin T. Gibbs. - * 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 immediately at the beginning of the file, without modification, - * 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. Absolutely no warranty of function or purpose is made by the author - * Justin T. Gibbs. - * 4. Modifications may be freely made to this file if the above conditions - * are met. - * - * $Id: 93cx6.h,v 1.7 1997/02/22 09:38:37 peter Exp $ - */ - -#include <sys/param.h> -#if !defined(__NetBSD__) -#include <sys/systm.h> -#endif - -typedef enum { - C46 = 6, - C56_66 = 8 -} seeprom_chip_t; - -struct seeprom_descriptor { -#if defined(__FreeBSD__) - u_int32_t sd_iobase; - volatile u_int8_t *sd_maddr; -#elif defined(__NetBSD__) - bus_chipset_tag_t sd_bc; - bus_io_handle_t sd_ioh; - bus_io_size_t sd_offset; -#endif - seeprom_chip_t sd_chip; - u_int16_t sd_MS; - u_int16_t sd_RDY; - u_int16_t sd_CS; - u_int16_t sd_CK; - u_int16_t sd_DO; - u_int16_t sd_DI; -}; - -/* - * This function will read count 16-bit words from the serial EEPROM and - * return their value in buf. The port address of the aic7xxx serial EEPROM - * control register is passed in as offset. The following parameters are - * also passed in: - * - * CS - Chip select - * CK - Clock - * DO - Data out - * DI - Data in - * RDY - SEEPROM ready - * MS - Memory port mode select - * - * A failed read attempt returns 0, and a successful read returns 1. - */ - -#if defined(__FreeBSD__) -#define SEEPROM_INB(sd) \ - (((sd)->sd_maddr != NULL) ? \ - *((sd)->sd_maddr) : \ - inb((sd)->sd_iobase)) -#define SEEPROM_OUTB(sd, value) \ - (((sd)->sd_maddr != NULL) ? \ - (void)(*((sd)->sd_maddr) = (value)) : \ - outb((sd)->sd_iobase, (value))) - -#elif defined(__NetBSD__) -#define SEEPROM_INB(sd) \ - bus_io_read_1(sd->sd_bc, sd->sd_ioh, sd->sd_offset) -#define SEEPROM_OUTB(sd, value) \ - bus_io_write_1(sd->sd_bc, sd->sd_ioh, sd->sd_offset, value) -#endif - -#if defined(__FreeBSD__) -int read_seeprom __P((struct seeprom_descriptor *sd, - u_int16_t *buf, u_int start_addr, u_int count)); -#elif defined(__NetBSD__) -int read_seeprom __P((struct seeprom_descriptor *sd, - u_int16_t *buf, bus_io_size_t start_addr, bus_io_size_t count)); -#endif diff --git a/sys/i386/scsi/advansys.c b/sys/i386/scsi/advansys.c deleted file mode 100644 index e48362e..0000000 --- a/sys/i386/scsi/advansys.c +++ /dev/null @@ -1,783 +0,0 @@ -/* - * Generic driver for the Advanced Systems Inc. SCSI controllers - * Product specific probe and attach routines can be found in: - * - * i386/isa/adv_isa.c ABP5140, ABP542, ABP5150, ABP842, ABP852 - * - * Copyright (c) 1996 Justin T. Gibbs. - * 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 immediately at the beginning of the file, without modification, - * 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. 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. - * - * $Id$ - */ -/* - * Ported from: - * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters - * - * Copyright (c) 1995-1996 Advanced System Products, Inc. - * All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that redistributions of source - * code retain the above copyright notice and this comment without - * modification. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/buf.h> - -#include <machine/clock.h> - -#include <scsi/scsi_all.h> -#include <scsi/scsi_message.h> -#include <scsi/scsiconf.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/pmap.h> - -#include <i386/scsi/advansys.h> - -static void adv_scsi_cmd __P((struct scsi_xfer *xs)); -static void advminphys __P((struct buf *bp)); -static timeout_t - adv_timeout; -static int adv_qdone __P((struct adv_softc *adv)); -static void adv_done __P((struct adv_softc *adv, - struct adv_q_done_info *qdonep)); -static int adv_poll __P((struct adv_softc *ahc, struct scsi_xfer *xs)); - -struct adv_softc *advsoftcs[NADV]; /* XXX Config should handle this */ - -static struct scsi_adapter adv_switch = -{ - adv_scsi_cmd, - advminphys, - NULL, - NULL, - "adv" -}; - -static void -adv_scsi_cmd(xs) - struct scsi_xfer *xs; -{ - struct adv_softc *adv; - struct adv_scsi_q scsiq; - struct adv_sg_head sghead; - - SC_DEBUG(xs->sc_link, SDEV_DB2, ("adv_scsi_cmd\n")); - - adv = (struct adv_softc *)xs->sc_link->scsibus->adpt_link.adpt_softc; - - /* - * Build up the request - */ - scsiq.q1.cntl = 0; - scsiq.q1.sg_queue_cnt = 0; - scsiq.q1.status = 0; - scsiq.q1.q_no = 0; - scsiq.q1.target_id = ADV_TID_TO_TARGET_ID(xs->sc_link->target); - scsiq.q1.target_lun = xs->sc_link->lun; - scsiq.q1.sense_addr = (u_int32_t)vtophys(&xs->sense); - scsiq.q1.sense_len = sizeof(xs->sense); - scsiq.q1.data_cnt = 0; - scsiq.q1.data_addr = 0; - scsiq.q1.user_def = 0; - scsiq.q2.xs_ptr = (u_int32_t)xs; - scsiq.q2.target_ix = ADV_TIDLUN_TO_IX(xs->sc_link->target, xs->sc_link->lun); - scsiq.q2.flag = 0; - scsiq.q2.cdb_len = xs->cmdlen; - scsiq.q2.tag_code = xs->tag_type; - scsiq.q2.vm_id = 0; - scsiq.sg_head = NULL; - scsiq.cdbptr = &xs->cmd; - - if (xs->datalen) { - /* - * Determin the number of segments needed for this - * transfer. We should only use SG if we need more - * than one. - */ - int seg; - u_int32_t datalen; - vm_offset_t vaddr; - u_int32_t paddr; - u_int32_t nextpaddr; - struct adv_sg_entry *sg; - - seg = 0; - datalen = xs->datalen; - vaddr = (vm_offset_t)xs->data; - paddr = vtophys(vaddr); - sg = &sghead.sg_list[0]; - - while ((datalen > 0) && (seg < ADV_MAX_SG_LIST)) { - /* put in the base address and length */ - sg->addr = paddr; - sg->bytes = 0; - - /* do it at least once */ - nextpaddr = paddr; - - while ((datalen > 0) && (paddr == nextpaddr)) { - u_int32_t size; - /* - * This page is contiguous (physically) - * with the the last, just extend the - * length - */ - /* how far to the end of the page */ - nextpaddr = (paddr & (~PAGE_MASK)) + PAGE_SIZE; - - /* - * Compute the maximum size - */ - size = nextpaddr - paddr; - if (size > datalen) - size = datalen; - - sg->bytes += size; - vaddr += size; - datalen -= size; - if (datalen > 0) - paddr = vtophys(vaddr); - } - /* - * next page isn't contiguous, finish the seg - */ - seg++; - sg++; - } - if (seg > 1) { - scsiq.q1.cntl |= QC_SG_HEAD; - scsiq.sg_head = &sghead; - sghead.entry_cnt = sghead.entry_to_copy = seg; - sghead.res = 0; - } - scsiq.q1.data_addr = sghead.sg_list[0].addr; - scsiq.q1.data_cnt = sghead.sg_list[0].bytes; - } - - if (adv_execute_scsi_queue(adv, &scsiq) != 0) { - xs->error = XS_QUEUE_RESOURCE_SHORTAGE; - scsi_done(xs); - } else if ((xs->flags & SCSI_POLL) != 0) { - /* - * If we can't use interrupts, poll for completion - */ - int s; - - s = splbio(); - if (adv_poll(adv, xs)) { - if (!(xs->flags & SCSI_SILENT)) - printf("cmd fail\n"); - adv_timeout(xs); - } - splx(s); - } -} - - -static void -advminphys(bp) - struct buf *bp; -{ - if (bp->b_bcount > ((ADV_MAX_SG_LIST - 1) * PAGE_SIZE)) - bp->b_bcount = ((ADV_MAX_SG_LIST - 1) * PAGE_SIZE); -} - -static void -adv_timeout(arg) - void *arg; -{ - printf("adv: Ooops. Had a timeout\n"); -} - -struct adv_softc * -adv_alloc(unit, iobase) - int unit; - u_long iobase; -{ - struct adv_softc *adv; - int i; - - if (unit >= NADV) { - printf("adv: unit number (%d) too high\n", unit); - return NULL; - } - - /* - * Allocate a storage area for us - */ - if (advsoftcs[unit]) { - printf("adv%d: memory already allocated\n", unit); - return NULL; - } - - adv = malloc(sizeof(struct adv_softc), M_DEVBUF, M_NOWAIT); - if (!adv) { - printf("adv%d: cannot malloc!\n", unit); - return NULL; - } - bzero(adv, sizeof(struct adv_softc)); - advsoftcs[unit] = adv; - adv->unit = unit; - adv->iobase = iobase; - - /* Set reasonable defaults incase we can't read the EEPROM */ - adv->max_openings = ADV_DEF_MAX_TOTAL_QNG; - adv->start_motor = TARGET_BIT_VECTOR_SET; - adv->disc_enable = TARGET_BIT_VECTOR_SET; - adv->cmd_qng_enabled = TARGET_BIT_VECTOR_SET; - adv->scsi_id = 7; - - for (i = 0; i <= ADV_MAX_TID; i++) - adv->sdtr_data[i] = ADV_DEF_SDTR_OFFSET | (ADV_DEF_SDTR_INDEX << 4); - - return(adv); -} - -void -adv_free(adv) - struct adv_softc *adv; -{ - if (adv->sense_buffers != NULL) - free(adv->sense_buffers, M_DEVBUF); - free(adv, M_DEVBUF); -} - -int -adv_init(adv) - struct adv_softc *adv; -{ - struct adv_eeprom_config eeprom_config; - int checksum, i; - u_int16_t config_lsw; - u_int16_t config_msw; - - adv_get_board_type(adv); - - /* - * Stop script execution. - */ - adv_write_lram_16(adv, ADV_HALTCODE_W, 0x00FE); - adv_stop_execution(adv); - adv_reset_chip_and_scsi_bus(adv); - /* - * The generic SCSI code does a minimum delay for us - * already. - */ - /* DELAY(3 * 1000 * 1000);*/ /* 3 Second Delay */ - if (adv_is_chip_halted(adv) == 0) { - printf("adv%d: Unable to halt adapter. Initialization" - "failed\n", adv->unit); - return (1); - } - ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR); - if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) { - printf("adv%d: Unable to set program counter. Initialization" - "failed\n", adv->unit); - return (1); - } - - config_lsw = ADV_INW(adv, ADV_CONFIG_LSW); - config_msw = ADV_INW(adv, ADV_CONFIG_MSW); - -#if 0 - /* XXX Move to PCI probe code */ - if (adv->type & ADV_PCI) { -#if CC_DISABLE_PCI_PARITY_INT - config_msw &= 0xFFC0; - ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw); -#endif - - if (asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_A) { - asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ADD_ONE_BYTE; - } - } -#endif - if ((config_msw & ADV_CFG_MSW_CLR_MASK) != 0) { - config_msw &= (~(ADV_CFG_MSW_CLR_MASK)); - /* - * XXX The Linux code flags this as an error, - * but what should we report to the user??? - * It seems that clearing the config register - * makes this error recoverable. - */ - ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw); - } - - /* Suck in the configuration from the EEProm */ - checksum = adv_get_eeprom_config(adv, &eeprom_config); - - eeprom_config.cfg_msw &= (~(ADV_CFG_MSW_CLR_MASK)); - - if (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_AUTO_CONFIG) { - /* - * XXX The Linux code sets a warning level for this - * condition, yet nothing of meaning is printed to - * the user. What does this mean??? - */ - if (adv->chip_version == 3) { - if (eeprom_config.cfg_lsw != config_lsw) { - /* XXX Yet another supposed Warning */ - eeprom_config.cfg_lsw = - ADV_INW(adv, ADV_CONFIG_LSW); - } - if (eeprom_config.cfg_msw != config_msw) { - /* XXX Yet another supposed Warning */ - eeprom_config.cfg_msw = - ADV_INW(adv, ADV_CONFIG_MSW); - } - } - } - eeprom_config.cfg_lsw |= ADV_CFG_LSW_HOST_INT_ON; - if (checksum == eeprom_config.chksum) { - if (adv_test_external_lram(adv) == 0) { - if (adv->type & ADV_PCI) { - eeprom_config.cfg_msw |= 0x0800; - config_msw |= 0x0800; - ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw); - eeprom_config.max_total_qng = ADV_MAX_PCI_INRAM_TOTAL_QNG; - eeprom_config.max_tag_qng = ADV_MAX_INRAM_TAG_QNG; - } - } - /* XXX What about wide bussed cards?? */ - for (i = 0; i <= 7; i++) - adv->sdtr_data[i] = eeprom_config.sdtr_data[i]; - - /* Range/Sanity checking */ - if (eeprom_config.max_total_qng < ADV_MIN_TOTAL_QNG) { - eeprom_config.max_total_qng = ADV_MIN_TOTAL_QNG; - } - if (eeprom_config.max_total_qng > ADV_MAX_TOTAL_QNG) { - eeprom_config.max_total_qng = ADV_MAX_TOTAL_QNG; - } - if (eeprom_config.max_tag_qng > eeprom_config.max_total_qng) { - eeprom_config.max_tag_qng = eeprom_config.max_total_qng; - } - if (eeprom_config.max_tag_qng < ADV_MIN_TAG_Q_PER_DVC) { - eeprom_config.max_tag_qng = ADV_MIN_TAG_Q_PER_DVC; - } - adv->max_openings = eeprom_config.max_total_qng; - - if ((eeprom_config.use_cmd_qng & eeprom_config.disc_enable) != - eeprom_config.use_cmd_qng) { - eeprom_config.disc_enable |= eeprom_config.use_cmd_qng; - printf("adv:%d: WARNING! One or more targets with tagged " - "queuing enabled have the disconnection priveledge " - "disabled.\n" - "adv:%d: Overriding disconnection settings to " - "allow tagged queueing devices to disconnect.\n ", - adv->unit, adv->unit); - } -#if 0 - /* - * XXX We should range check our target ID - * based on the width of our bus - */ - EEPROM_SET_SCSIID(eeprom_config, - EEPROM_SCSIID(eeprom_config) & ADV_MAX_TID); -#endif - adv->initiate_sdtr = eeprom_config.init_sdtr; - adv->disc_enable = eeprom_config.disc_enable; - adv->cmd_qng_enabled = eeprom_config.use_cmd_qng; - adv->isa_dma_speed = EEPROM_DMA_SPEED(eeprom_config); - adv->scsi_id = EEPROM_SCSIID(eeprom_config); - adv->start_motor = eeprom_config.start_motor; - adv->control = eeprom_config.cntl; - adv->no_scam = eeprom_config.no_scam; - } else { - /* - * Use the defaults that adv was initialized with. - */ - /* - * XXX Fixup EEPROM with default values??? - */ - printf("adv%d: Warning EEPROM Checksum mismatch. " - "Using default device parameters\n", adv->unit); - } - -#if 0 - /* XXX Do this in the PCI probe */ - if ((adv->btype & ADV_PCI) && - !(asc_dvc->dvc_cntl & ASC_CNTL_NO_PCI_FIX_ASYN_XFER)) { - if ((asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_A) || - (asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_B)) { - asc_dvc->pci_fix_asyn_xfer = ASC_ALL_DEVICE_BIT_SET; - } - } -#endif - if (adv_set_eeprom_config(adv, &eeprom_config) != 0) - printf("adv:%d: WARNING! Failure writing to EEPROM.\n"); - - /* Allocate space for our sense buffers */ - /* XXX this should really be done by the generic SCSI layer by ensuring - * that all scsi_xfer structs are allocated below 16M if any controller - * needs to bounce. - */ - if (adv->type & ADV_ISA) { - adv->sense_buffers = (struct scsi_sense_data *)contigmalloc(sizeof(struct scsi_sense_data) * adv->max_openings, - M_DEVBUF, M_NOWAIT, 0ul, 0xfffffful, 1ul, - 0x10000ul); - if (adv->sense_buffers == NULL) { - printf("adv%d: Unable to allocate sense buffer space.\n"); - return (1); - } - - } - - if (adv_init_lram_and_mcode(adv)) - return (1); - - return (0); -} - -void -adv_intr(arg) - void *arg; -{ - struct adv_softc *adv; - u_int16_t chipstat; - u_int16_t saved_ram_addr; - u_int8_t ctrl_reg; - u_int8_t saved_ctrl_reg; - int status; - u_int8_t host_flag; - - adv = (struct adv_softc *)arg; - - ctrl_reg = ADV_INB(adv, ADV_CHIP_CTRL); - saved_ctrl_reg = ctrl_reg & (~(ADV_CC_SCSI_RESET | ADV_CC_CHIP_RESET | - ADV_CC_SINGLE_STEP | ADV_CC_DIAG | ADV_CC_TEST)); - - - if ((chipstat = ADV_INW(adv, ADV_CHIP_STATUS)) & ADV_CSW_INT_PENDING) { - - adv_ack_interrupt(adv); - - host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B); - adv_write_lram_8(adv, ADVV_HOST_FLAG_B, - host_flag | ADV_HOST_FLAG_IN_ISR); - saved_ram_addr = ADV_INW(adv, ADV_LRAM_ADDR); - - if ((chipstat & ADV_CSW_HALTED) - && (ctrl_reg & ADV_CC_SINGLE_STEP)) { - adv_isr_chip_halted(adv); - saved_ctrl_reg &= ~ADV_CC_HALT; - } else { - if ((adv->control & ADV_CNTL_INT_MULTI_Q) != 0) { - while (((status = adv_qdone(adv)) & 0x01) != 0) - ; - } else { - do { - status = adv_qdone(adv); - } while (status == 0x11); - } - } - ADV_OUTW(adv, ADV_LRAM_ADDR, saved_ram_addr); -#ifdef DIAGNOSTIC - if (ADV_INW(adv, ADV_LRAM_ADDR) != saved_ram_addr) - panic("adv_intr: Unable to set LRAM addr"); -#endif - adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag); - } - - ADV_OUTB(adv, ADV_CHIP_CTRL, saved_ctrl_reg); -} - -int -adv_qdone(adv) - struct adv_softc *adv; -{ - u_int8_t next_qp; - u_int8_t i; - u_int8_t n_q_used; - u_int8_t sg_list_qp; - u_int8_t sg_queue_cnt; - u_int8_t done_q_tail; - u_int8_t tid_no; - target_bit_vector target_id; - u_int16_t q_addr; - u_int16_t sg_q_addr; - struct adv_q_done_info scsiq_buf; - struct adv_q_done_info *scsiq; - int false_overrun; - u_int8_t tag_code; - - n_q_used = 1; - scsiq = &scsiq_buf; - done_q_tail = adv_read_lram_16(adv, ADVV_DONE_Q_TAIL_W) & 0xFF; - q_addr = ADV_QNO_TO_QADDR(done_q_tail); - next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD); - if (next_qp != ADV_QLINK_END) { - adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, next_qp); - q_addr = ADV_QNO_TO_QADDR(next_qp); - - sg_queue_cnt = adv_copy_lram_doneq(adv, q_addr, scsiq, adv->max_dma_count); - - adv_write_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS, - scsiq->q_status & ~(QS_READY | QS_ABORTED)); - tid_no = ADV_TIX_TO_TID(scsiq->d2.target_ix); - target_id = ADV_TIX_TO_TARGET_ID(scsiq->d2.target_ix); - if ((scsiq->cntl & QC_SG_HEAD) != 0) { - sg_q_addr = q_addr; - sg_list_qp = next_qp; - for (i = 0; i < sg_queue_cnt; i++) { - sg_list_qp = adv_read_lram_8(adv, - sg_q_addr + ADV_SCSIQ_B_FWD); - sg_q_addr = ADV_QNO_TO_QADDR(sg_list_qp); -#ifdef DIAGNOSTIC - if (sg_list_qp == ASC_QLINK_END) { - panic("adv_qdone: Corrupted SG list encountered"); - } -#endif - adv_write_lram_8(adv, sg_q_addr + ADV_SCSIQ_B_STATUS, - QS_FREE); - } - - n_q_used = sg_queue_cnt + 1; - adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, sg_list_qp); - } -#if 0 - /* XXX Fix later */ - if (adv->queue_full_or_busy & target_id) { - cur_target_qng = adv_read_lram_8(adv, - ADV_QADR_BEG + scsiq->d2.target_ix); - if (cur_target_qng < adv->max_dvc_qng[tid_no]) { - scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B); - scsi_busy &= ~target_id; - adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy); - adv->queue_full_or_busy &= ~target_id; - } - } -#endif -#ifdef DIAGNOSTIC - if (adv->cur_total_qng < n_q_used) - panic("adv_qdone: Attempting to free more queues than are active"); -#endif - adv->cur_active -= n_q_used; - - if ((scsiq->d2.xs_ptr == 0) || - ((scsiq->q_status & QS_ABORTED) != 0)) - return (0x11); - else if (scsiq->q_status == QS_DONE) { - - false_overrun = FALSE; - - if (adv->bug_fix_control & ADV_BUG_FIX_ADD_ONE_BYTE) { - tag_code = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_TAG_CODE); - if (tag_code & ADV_TAG_FLAG_ADD_ONE_BYTE) { - if (scsiq->remain_bytes != 0) { - scsiq->remain_bytes--; - if (scsiq->remain_bytes == 0) - false_overrun = TRUE; - } - } - } - if ((scsiq->d3.done_stat == QD_WITH_ERROR) && - (scsiq->d3.host_stat == QHSTA_M_DATA_OVER_RUN)) { - if ((scsiq->cntl & (QC_DATA_IN | QC_DATA_OUT)) == 0) { - scsiq->d3.done_stat = QD_NO_ERROR; - scsiq->d3.host_stat = QHSTA_NO_ERROR; - } else if (false_overrun) { - scsiq->d3.done_stat = QD_NO_ERROR; - scsiq->d3.host_stat = QHSTA_NO_ERROR; - } - } - - if ((scsiq->cntl & QC_NO_CALLBACK) == 0) - adv_done(adv, scsiq); - else { - if ((adv_read_lram_8(adv, q_addr + ADV_SCSIQ_CDB_BEG) == - START_STOP)) { - adv->unit_not_ready &= ~target_id; - if (scsiq->d3.done_stat != QD_NO_ERROR) - adv->start_motor &= ~target_id; - } - } - return (1); - } else { - panic("adv_qdone: completed scsiq with unknown status"); -#if 0 - /* - * XXX Doesn't this simply indicate a software bug? - * What does setting the lram error code do for - * you. Would we even recover? - */ - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS); - - FATAL_ERR_QDONE: - if ((scsiq->cntl & QC_NO_CALLBACK) == 0) { - (*asc_isr_callback) (asc_dvc, scsiq); - } - return (0x80); -#endif - } - } - return (0); -} - - -void -adv_done(adv, qdonep) - struct adv_softc *adv; - struct adv_q_done_info *qdonep; -{ - struct scsi_xfer *xs; - - xs = (struct scsi_xfer *)qdonep->d2.xs_ptr; - - xs->status = qdonep->d3.scsi_stat; - /* - * 'qdonep' contains the command's ending status. - */ - switch (qdonep->d3.done_stat) { - case QD_NO_ERROR: - switch (qdonep->d3.host_stat) { - case QHSTA_NO_ERROR: - break; - case QHSTA_M_SEL_TIMEOUT: - xs->error = XS_SELTIMEOUT; - break; - default: - /* QHSTA error occurred */ -#if 0 - /* XXX Can I get more explicit information here? */ - xs->error = XS_DRIVER_STUFFUP; -#endif - break; - } - break; - - case QD_WITH_ERROR: - switch (qdonep->d3.host_stat) { - case QHSTA_NO_ERROR: - if ((qdonep->d3.scsi_stat == STATUS_CHECK_CONDITION) - || (qdonep->d3.scsi_stat == STATUS_COMMAND_TERMINATED)) { - /* We have valid sense information to return */ - xs->error = XS_SENSE; - if (adv->sense_buffers != NULL) - /* Structure copy */ - xs->sense = adv->sense_buffers[qdonep->q_no]; - } - break; - case QHSTA_M_SEL_TIMEOUT: - xs->error = XS_SELTIMEOUT; - break; - default: -#if 0 - /* XXX Can I get more explicit information here? */ - xs->error = XS_DRIVER_STUFFUP; -#endif - break; - } - break; - - case QD_ABORTED_BY_HOST: - /* XXX Should have an explicit ABORTED error code */ - xs->error = XS_ABORTED; - break; - - default: -#if 0 - printf("adv_done: Unknown done status 0x%x\n", - qdonep->d3.done_stat); - xs->error = XS_DRIVER_STUFFUP; -#endif - break; - } - xs->flags |= SCSI_ITSDONE; - scsi_done(xs); - return; -} - -/* - * Function to poll for command completion when - * interrupts are disabled (crash dumps) - */ -static int -adv_poll(adv, xs) - struct adv_softc *adv; - struct scsi_xfer *xs; -{ - int wait; - - wait = xs->timeout; - do { - DELAY(1000); - adv_intr((void *)adv); - } while (--wait && ((xs->flags & SCSI_ITSDONE) == 0)); - if (wait == 0) { - printf("adv%d: board is not responding\n", adv->unit); - return (EIO); - } - return (0); -} - -/* - * Attach all the sub-devices we can find - */ -int -adv_attach(adv) - struct adv_softc *adv; -{ - struct scsi_bus *scbus; - struct scsi_queue *scsiq; - - scsiq = scsi_alloc_queue(adv->max_openings); - if (scsiq == NULL) - return 0; - - /* - * Prepare the scsi_bus area for the upperlevel scsi code. - */ - scbus = scsi_alloc_bus(&adv_switch, adv, adv->unit, scsiq); - if (scbus == NULL) { - scsi_free_queue(scsiq); - return 0; - } - - /* Override defaults */ - if ((adv->type & ADV_ISA) != 0) - scbus->adpt_link.adpt_flags |= SADPT_BOUNCE; - scbus->adpt_link.adpt_target = adv->scsi_id; - scbus->adpt_link.adpt_openings = 2; /* XXX Is this correct for these cards? */ - scbus->adpt_link.adpt_tagged_openings = adv->max_openings; - - /* - * ask the adapter what subunits are present - */ - if(bootverbose) - printf("adv%d: Probing SCSI bus\n", adv->unit); - - scsi_attachdevs(scbus); - - return 1; -} diff --git a/sys/i386/scsi/advansys.h b/sys/i386/scsi/advansys.h deleted file mode 100644 index 47bca6a..0000000 --- a/sys/i386/scsi/advansys.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Generic driver for the Advanced Systems Inc. SCSI controllers - * Product specific probe and attach routines can be found in: - * - * XXX Fill this in. - * - * Copyright (c) 1996 Justin T. Gibbs. - * 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 immediately at the beginning of the file, without modification, - * 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. 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. - * - * $Id$ - */ - -#ifndef _ADVANSYS_H_ -#define _ADVANSYS_H_ - -#include "adv.h" -#include <dev/advansys/advlib.h> - -struct adv_softc * adv_alloc __P((int unit, u_long iobase)); -void adv_free __P((struct adv_softc *adv)); -int adv_init __P((struct adv_softc *adv)); -void adv_intr __P((void *arg)); -int adv_attach __P((struct adv_softc *adv)); - -extern struct adv_softc *advsoftcs[NADV]; /* XXX Config should handle this */ -#endif /* _ADVANSYS_H_ */ diff --git a/sys/i386/scsi/aic7xxx.c b/sys/i386/scsi/aic7xxx.c deleted file mode 100644 index 4ded5b5..0000000 --- a/sys/i386/scsi/aic7xxx.c +++ /dev/null @@ -1,3867 +0,0 @@ -/* - * Generic driver for the aic7xxx based adaptec SCSI controllers - * Product specific probe and attach routines can be found in: - * i386/eisa/aic7770.c 27/284X and aic7770 motherboard controllers - * pci/aic7870.c 3940, 2940, aic7880, aic7870, aic7860, - * and aic7850 controllers - * - * Copyright (c) 1994-1997 Justin Gibbs. - * 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, - * without modification, immediately at the beginning of the file. - * 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. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. - * - * $Id: aic7xxx.c,v 1.126 1997/09/27 19:38:27 gibbs Exp $ - */ -/* - * TODO: - * Implement Target Mode - * - * A few notes on features of the driver. - * - * SCB paging takes advantage of the fact that devices stay disconnected - * from the bus a relatively long time and that while they're disconnected, - * having the SCBs for these transactions down on the host adapter is of - * little use. Instead of leaving this idle SCB down on the card we copy - * it back up into kernel memory and reuse the SCB slot on the card to - * schedule another transaction. This can be a real payoff when doing random - * I/O to tagged queueing devices since there are more transactions active at - * once for the device to sort for optimal seek reduction. The algorithm goes - * like this... - * - * The sequencer maintains two lists of its hardware SCBs. The first is the - * singly linked free list which tracks all SCBs that are not currently in - * use. The second is the doubly linked disconnected list which holds the - * SCBs of transactions that are in the disconnected state sorted most - * recently disconnected first. When the kernel queues a transaction to - * the card, a hardware SCB to "house" this transaction is retrieved from - * either of these two lists. If the SCB came from the disconnected list, - * a check is made to see if any data transfer or SCB linking (more on linking - * in a bit) information has been changed since it was copied from the host - * and if so, DMAs the SCB back up before it can be used. Once a hardware - * SCB has been obtained, the SCB is DMAed from the host. Before any work - * can begin on this SCB, the sequencer must ensure that either the SCB is - * for a tagged transaction or the target is not already working on another - * non-tagged transaction. If a conflict arises in the non-tagged case, the - * sequencer finds the SCB for the active transactions and sets the SCB_LINKED - * field in that SCB to this next SCB to execute. To facilitate finding - * active non-tagged SCBs, the last four bytes of up to the first four hardware - * SCBs serve as a storage area for the currently active SCB ID for each - * target. - * - * When a device reconnects, a search is made of the hardware SCBs to find - * the SCB for this transaction. If the search fails, a hardware SCB is - * pulled from either the free or disconnected SCB list and the proper - * SCB is DMAed from the host. If the SCB_ABORTED control bit is set - * in the control byte of the SCB while it was disconnected, the sequencer - * will send an abort or abort tag message to the target during the - * reconnection and signal the kernel that the abort was successfull. - * - * When a command completes, a check for non-zero status and residuals is - * made. If either of these conditions exists, the SCB is DMAed back up to - * the host so that it can interpret this information. Additionally, in the - * case of bad status, the sequencer generates a special interrupt and pauses - * itself. This allows the host to setup a request sense command if it - * chooses for this target synchronously with the error so that sense - * information isn't lost. - * - */ - -#include <sys/param.h> -#include <sys/systm.h> -#if defined(__NetBSD__) -#include <sys/device.h> -#include <machine/bus.h> -#include <machine/intr.h> -#endif /* defined(__NetBSD__) */ - -#include <sys/malloc.h> -#include <sys/buf.h> - -#include <scsi/scsi_message.h> -#if defined(__NetBSD__) -#include <scsi/scsi_debug.h> -#endif -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> - -#if defined(__FreeBSD__) -#include <machine/clock.h> -#endif - -#include <vm/vm.h> -#include <vm/pmap.h> - -#if defined(__FreeBSD__) -#include <i386/scsi/aic7xxx.h> -#include <dev/aic7xxx/sequencer.h> -#include <aic7xxx_reg.h> -#include <aic7xxx_seq.h> -#endif /* defined(__FreeBSD__) */ - -#if defined(__NetBSD__) -#include <dev/ic/aic7xxxreg.h> -#include <dev/ic/aic7xxxvar.h> - -#define bootverbose 1 - -#if DEBUGTARGET < 0 /* Negative numbers for disabling cause warnings */ -#define DEBUGTARGET 17 -#endif -#endif /* defined(__NetBSD__) */ - -#include <sys/kernel.h> - -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#define ALL_TARGETS -1 -#define ALL_LUNS -1 -#define ALL_CHANNELS '\0' - -#if defined(__FreeBSD__) -u_long ahc_unit = 0; -#endif - -#ifdef AHC_DEBUG -static int ahc_debug = AHC_DEBUG; -#endif - -#ifdef AHC_BROKEN_CACHE -int ahc_broken_cache = 1; - -/* - * "wbinvd" cause writing back whole cache (both CPU internal & external) - * to memory, so that the instruction takes a lot of time. - * This makes machine slow. - */ -#define INVALIDATE_CACHE() __asm __volatile("wbinvd") -#endif - -/**** bit definitions for SCSIDEF ****/ -#define HSCSIID 0x07 /* our SCSI ID */ -#define HWSCSIID 0x0f /* our SCSI ID if Wide Bus */ - -static void ahcminphys __P((struct buf *bp)); -static int32_t ahc_scsi_cmd __P((struct scsi_xfer *xs)); -static void ahc_run_waiting_queue __P((struct ahc_softc *ahc)); -static struct scb * - ahc_get_scb __P((struct ahc_softc *ahc, u_int32_t flags)); -static void ahc_free_scb __P((struct ahc_softc *ahc, struct scb *scb)); -static struct scb * - ahc_alloc_scb __P((struct ahc_softc *ahc)); -static __inline void pause_sequencer __P((struct ahc_softc *ahc)); -static __inline void unpause_sequencer __P((struct ahc_softc *ahc, - int unpause_always)); -static __inline void restart_sequencer __P((struct ahc_softc *ahc)); - -#define AHC_BUSRESET_DELAY 1000 /* Reset delay in us */ - -static struct scsi_adapter ahc_switch = -{ - ahc_scsi_cmd, - ahcminphys, - NULL, - NULL, -#if defined(__FreeBSD__) - NULL, - "ahc", - { 0, 0 } -#endif -}; - -static struct scsi_device ahc_dev = -{ - NULL, /* Use default error handler */ - NULL, /* have a queue, served by this */ - NULL, /* have no async handler */ - NULL, /* Use default 'done' routine */ -#if defined(__FreeBSD__) - "ahc", - 0, - { 0, 0 } -#endif -}; - -static __inline void -pause_sequencer(ahc) - struct ahc_softc *ahc; -{ - ahc_outb(ahc, HCNTRL, ahc->pause); - - /* - * Since the sequencer can disable pausing in a critical section, we - * must loop until it actually stops. - */ - while ((ahc_inb(ahc, HCNTRL) & PAUSE) == 0) - ; -} - -static __inline void -unpause_sequencer(ahc, unpause_always) - struct ahc_softc *ahc; - int unpause_always; -{ - if (unpause_always - || (ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0) - ahc_outb(ahc, HCNTRL, ahc->unpause); -} - -/* - * Restart the sequencer program from address zero - */ -static __inline void -restart_sequencer(ahc) - struct ahc_softc *ahc; -{ - pause_sequencer(ahc); - ahc_outb(ahc, SEQCTL, SEQRESET|FASTMODE); - unpause_sequencer(ahc, /*unpause_always*/TRUE); -} - -#if defined(__FreeBSD__) -#define IS_SCSIBUS_B(ahc, sc_link) \ - (((u_int32_t)((sc_link)->fordriver) & SELBUSB) != 0) -#else /* NetBSD/OpenBSD */ -#define IS_SCSIBUS_B(ahc, sc_link) \ - ((sc_link)->scsibus == (ahc)->sc_link_b.scsibus) -#endif - -#define SCB_TARGET(scb) \ - (((scb)->hscb->tcl & TID) >> 4) -#define SCB_LUN(scb) \ - ((scb)->hscb->tcl & LID) -#define SCB_IS_SCSIBUS_B(scb) \ - (((scb)->hscb->tcl & SELBUSB) != 0) - -static u_int8_t ahc_abort_wscb __P((struct ahc_softc *ahc, struct scb *scbp, - u_int8_t scbpos, u_int8_t prev, - u_int32_t xs_error)); -static void ahc_done __P((struct ahc_softc *ahc, struct scb *scbp)); -static void ahc_handle_seqint __P((struct ahc_softc *ahc, u_int8_t intstat)); -static void ahc_handle_scsiint __P((struct ahc_softc *ahc, - u_int8_t intstat)); -static void ahc_handle_devreset __P((struct ahc_softc *ahc, - int target, char channel)); -static void ahc_loadseq __P((struct ahc_softc *ahc)); -static struct patch * - ahc_next_patch __P((struct patch *cur_patch, int options, - int instrptr)); -static void ahc_download_instr(struct ahc_softc *ahc, int options, - int instrptr, u_int8_t *dconsts); -static int ahc_match_scb __P((struct scb *scb, int target, char channel, - int lun, u_int8_t tag)); -static int ahc_poll __P((struct ahc_softc *ahc, int wait)); -#ifdef AHC_DEBUG -static void ahc_print_scb __P((struct scb *scb)); -#endif -static u_int8_t ahc_find_scb __P((struct ahc_softc *ahc, struct scb *scb)); -static int ahc_search_qinfifo __P((struct ahc_softc *ahc, int target, - char channel, int lun, u_int8_t tag, - u_int32_t flags, u_int32_t xs_error, - int requeue)); -static int ahc_reset_channel __P((struct ahc_softc *ahc, char channel, - u_int32_t xs_error, int initiate_reset)); -static int ahc_reset_device __P((struct ahc_softc *ahc, int target, - char channel, int lun, u_int8_t tag, - u_int32_t xs_error)); -static u_int8_t ahc_rem_scb_from_disc_list __P((struct ahc_softc *ahc, - u_int8_t scbptr)); -static void ahc_add_curscb_to_free_list __P((struct ahc_softc *ahc)); -static void ahc_clear_intstat __P((struct ahc_softc *ahc)); -static void ahc_reset_current_bus __P((struct ahc_softc *ahc)); -static void ahc_run_done_queue __P((struct ahc_softc *ahc)); -static void ahc_untimeout_done_queue __P((struct ahc_softc *ahc)); -static void ahc_scsirate __P((struct ahc_softc* ahc, u_int8_t *scsirate, - u_int8_t *period, u_int8_t *offset, - char channel, int target)); -#if defined(__FreeBSD__) -static timeout_t - ahc_timeout; -#elif defined(__NetBSD__) -static void ahc_timeout __P((void *)); -#endif - -static u_int8_t ahc_index_busy_target __P((struct ahc_softc *ahc, int target, - char channel, int unbusy)); - -static void ahc_busy_target __P((struct ahc_softc *ahc, int target, - char channel, u_int8_t scbid)); - -static void ahc_construct_sdtr __P((struct ahc_softc *ahc, int start_byte, - u_int8_t period, u_int8_t offset)); - -static void ahc_construct_wdtr __P((struct ahc_softc *ahc, int start_byte, - u_int8_t bus_width)); - -static void ahc_calc_residual __P((struct scb *scb)); - -#if defined(__FreeBSD__) - -char *ahc_name(ahc) - struct ahc_softc *ahc; -{ - static char name[10]; - - sprintf(name, "ahc%d", ahc->unit); - return (name); -} - -#elif defined(__NetBSD__) -struct cfdriver ahc_cd = { - NULL, "ahc", DV_DULL -}; -#endif - -#ifdef AHC_DEBUG -static void -ahc_print_scb(scb) - struct scb *scb; -{ - struct hardware_scb *hscb = scb->hscb; - - printf("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%lx\n", - scb, - hscb->control, - hscb->tcl, - hscb->cmdlen, - hscb->cmdpointer ); - printf(" datlen:%d data:0x%lx segs:0x%x segp:0x%lx\n", - hscb->datalen, - hscb->data, - hscb->SG_segment_count, - hscb->SG_list_pointer); - printf(" sg_addr:%lx sg_len:%ld\n", - hscb->ahc_dma[0].addr, - hscb->ahc_dma[0].len); -} - -#endif - -static struct { - u_int8_t errno; - char *errmesg; -} hard_error[] = { - { ILLHADDR, "Illegal Host Access" }, - { ILLSADDR, "Illegal Sequencer Address referrenced" }, - { ILLOPCODE, "Illegal Opcode in sequencer program" }, - { PARERR, "Sequencer Ram Parity Error" } -}; - - -/* - * Valid SCSIRATE values. (p. 3-17) - * Provides a mapping of tranfer periods in ns to the proper value to - * stick in the scsiscfr reg to use that transfer rate. - */ -static struct { - int sxfr; - /* Rates in Ultra mode have bit 8 of sxfr set */ -#define ULTRA_SXFR 0x100 - u_int8_t period; /* Period to send to SCSI target */ - char *rate; -} ahc_syncrates[] = { - { 0x100, 12, "20.0" }, - { 0x110, 15, "16.0" }, - { 0x120, 18, "13.4" }, - { 0x000, 25, "10.0" }, - { 0x010, 31, "8.0" }, - { 0x020, 37, "6.67" }, - { 0x030, 43, "5.7" }, - { 0x040, 50, "5.0" }, - { 0x050, 56, "4.4" }, - { 0x060, 62, "4.0" }, - { 0x070, 68, "3.6" } -}; - -static int ahc_num_syncrates = - sizeof(ahc_syncrates) / sizeof(ahc_syncrates[0]); - -/* - * Allocate a controller structure for a new device and initialize it. - */ -#if defined(__FreeBSD__) -struct ahc_softc * -ahc_alloc(unit, iobase, maddr, type, flags, scb_data) - int unit; - u_int32_t iobase; -#elif defined(__NetBSD__) -void -ahc_construct(ahc, bc, ioh, maddr, type, flags) - struct ahc_softc *ahc; - bus_chipset_tag_t bc; - bus_io_handle_t ioh; -#endif - vm_offset_t maddr; - ahc_type type; - ahc_flag flags; - struct scb_data *scb_data; -{ - /* - * find unit and check we have that many defined - */ -#if defined(__FreeBSD__) - struct ahc_softc *ahc; - size_t alloc_size; - - /* - * Allocate a storage area for us - */ - if (scb_data == NULL) - /* - * We are not sharing SCB space with another controller - * so allocate our own SCB data space. - */ - alloc_size = sizeof(struct full_ahc_softc); - else - alloc_size = sizeof(struct ahc_softc); - ahc = malloc(alloc_size, M_DEVBUF, M_NOWAIT); - if (!ahc) { - printf("ahc%d: cannot malloc!\n", unit); - return NULL; - } - bzero(ahc, alloc_size); -#endif - if (scb_data == NULL) { - struct full_ahc_softc* full_softc = (struct full_ahc_softc*)ahc; - ahc->scb_data = &full_softc->scb_data_storage; - STAILQ_INIT(&ahc->scb_data->free_scbs); - } else - ahc->scb_data = scb_data; - STAILQ_INIT(&ahc->waiting_scbs); - STAILQ_INIT(&ahc->cmplete_scbs); -#if defined(__FreeBSD__) - ahc->unit = unit; -#endif -#if defined(__FreeBSD__) - ahc->baseport = iobase; -#elif defined(__NetBSD__) - ahc->sc_bc = bc; - ahc->sc_ioh = ioh; -#endif - ahc->maddr = (volatile u_int8_t *)maddr; - ahc->type = type; - ahc->flags = flags; - ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS) | INTEN; - ahc->pause = ahc->unpause | PAUSE; - -#if defined(__FreeBSD__) - return (ahc); -#endif -} - -void -ahc_free(ahc) - struct ahc_softc *ahc; -{ -#if defined(__FreeBSD__) - free(ahc, M_DEVBUF); - return; -#endif -} - -void -ahc_reset(ahc) - struct ahc_softc *ahc; -{ - u_int8_t hcntrl; - int wait; - - /* Retain the IRQ type accross the chip reset */ - hcntrl = (ahc_inb(ahc, HCNTRL) & IRQMS) | INTEN; - - ahc_outb(ahc, HCNTRL, CHIPRST | PAUSE); - /* - * Ensure that the reset has finished - */ - wait = 1000; - while (--wait && !(ahc_inb(ahc, HCNTRL) & CHIPRSTACK)) - DELAY(1000); - if (wait == 0) { - printf("%s: WARNING - Failed chip reset! " - "Trying to initialize anyway.\n", ahc_name(ahc)); - } - ahc_outb(ahc, HCNTRL, hcntrl | PAUSE); -} - -/* - * Look up the valid period to SCSIRATE conversion in our table. - */ -static void -ahc_scsirate(ahc, scsirate, period, offset, channel, target ) - struct ahc_softc *ahc; - u_int8_t *scsirate; - u_int8_t *period; - u_int8_t *offset; - char channel; - int target; -{ - int i; - u_int32_t ultra_enb_addr; - u_int8_t sxfrctl0; - u_int8_t ultra_enb; - - i = ahc_num_syncrates; /* Default to async */ - - if (*period >= ahc_syncrates[0].period && *offset != 0) { - for (i = 0; i < ahc_num_syncrates; i++) { - - if (*period <= ahc_syncrates[i].period) { - /* - * Watch out for Ultra speeds when ultra is not - * enabled and vice-versa. - */ - if (!(ahc->type & AHC_ULTRA) - && (ahc_syncrates[i].sxfr & ULTRA_SXFR)) { - /* - * This should only happen if the - * drive is the first to negotiate - * and chooses a high rate. We'll - * just move down the table util - * we hit a non ultra speed. - */ - continue; - } - *scsirate = (ahc_syncrates[i].sxfr & 0xF0) - | (*offset & 0x0f); - *period = ahc_syncrates[i].period; - - if (bootverbose) { - printf("%s: target %d synchronous at " - "%sMHz, offset = 0x%x\n", - ahc_name(ahc), target, - ahc_syncrates[i].rate, *offset ); - } - break; - } - } - } - if (i >= ahc_num_syncrates) { - /* Use asynchronous transfers. */ - *scsirate = 0; - *period = 0; - *offset = 0; - if (bootverbose) - printf("%s: target %d using asynchronous transfers\n", - ahc_name(ahc), target ); - } - /* - * Ensure Ultra mode is set properly for - * this target. - */ - ultra_enb_addr = ULTRA_ENB; - if (channel == 'B' || target > 7) - ultra_enb_addr++; - ultra_enb = ahc_inb(ahc, ultra_enb_addr); - sxfrctl0 = ahc_inb(ahc, SXFRCTL0); - if (*scsirate != 0 && (ahc_syncrates[i].sxfr & ULTRA_SXFR)) { - ultra_enb |= 0x01 << (target & 0x07); - sxfrctl0 |= FAST20; - } else { - ultra_enb &= ~(0x01 << (target & 0x07)); - sxfrctl0 &= ~FAST20; - } - ahc_outb(ahc, ultra_enb_addr, ultra_enb); - ahc_outb(ahc, SXFRCTL0, sxfrctl0); -} - -#if defined(__NetBSD__) -int -ahcprint(aux, name) - void *aux; - char *name; -{ - if (name != NULL) - printf("%s: scsibus ", name); - return UNCONF; -} -#endif - - -/* - * Attach all the sub-devices we can find - */ -int -ahc_attach(ahc) - struct ahc_softc *ahc; -{ - struct scsibus_data *scbus; - -#ifdef AHC_BROKEN_CACHE - if (cpu_class == CPUCLASS_386) /* doesn't have "wbinvd" instruction */ - ahc_broken_cache = 0; -#endif - /* - * fill in the prototype scsi_links. - */ -#if defined(__FreeBSD__) - ahc->sc_link.adapter_unit = ahc->unit; - ahc->sc_link.adapter_targ = ahc->our_id; - ahc->sc_link.fordriver = 0; -#elif defined(__NetBSD__) - ahc->sc_link.adapter_target = ahc->our_id; -#endif - ahc->sc_link.adapter_softc = ahc; - ahc->sc_link.adapter = &ahc_switch; - ahc->sc_link.opennings = 2; - ahc->sc_link.device = &ahc_dev; - ahc->sc_link.flags = DEBUGLEVEL; - - if (ahc->type & AHC_TWIN) { - /* Configure the second scsi bus */ - ahc->sc_link_b = ahc->sc_link; -#if defined(__FreeBSD__) - ahc->sc_link_b.adapter_targ = ahc->our_id_b; - ahc->sc_link_b.adapter_bus = 1; - ahc->sc_link_b.fordriver = (void *)SELBUSB; -#elif defined(__NetBSD__) - ahc->sc_link_b.adapter_target = ahc->our_id_b; -#endif - } - - -#if defined(__FreeBSD__) - /* - * Prepare the scsibus_data area for the upperlevel - * scsi code. - */ - scbus = scsi_alloc_bus(); - if(!scbus) - return 0; - scbus->adapter_link = (ahc->flags & AHC_CHANNEL_B_PRIMARY) ? - &ahc->sc_link_b : &ahc->sc_link; - if (ahc->type & AHC_WIDE) - scbus->maxtarg = 15; - - /* - * ask the adapter what subunits are present - */ - if (bootverbose) - printf("ahc%d: Probing channel %c\n", ahc->unit, - (ahc->flags & AHC_CHANNEL_B_PRIMARY) ? 'B' : 'A'); - scsi_attachdevs(scbus); - scbus = NULL; /* Upper-level SCSI code owns this now */ - - if (ahc->type & AHC_TWIN) { - scbus = scsi_alloc_bus(); - if (!scbus) - return 0; - scbus->adapter_link = (ahc->flags & AHC_CHANNEL_B_PRIMARY) ? - &ahc->sc_link : &ahc->sc_link_b; - if (ahc->type & AHC_WIDE) - scbus->maxtarg = 15; - if (bootverbose) - printf("ahc%d: Probing Channel %c\n", ahc->unit, - (ahc->flags & AHC_CHANNEL_B_PRIMARY) ? 'A': 'B'); - scsi_attachdevs(scbus); - scbus = NULL; /* Upper-level SCSI code owns this now */ - } -#elif defined(__NetBSD__) - /* - * XXX - Update MI SCSI code - * - * if(ahc->type & AHC_WIDE) - * max target of both channel A and B = 15; - */ - - /* - * ask the adapter what subunits are present - */ - if ((ahc->flags & AHC_CHANNEL_B_PRIMARY) == 0) { - /* make IS_SCSIBUS_B() == false, while probing channel A */ - ahc->sc_link_b.scsibus = 0xff; - - if (ahc->type & AHC_TWIN) - printf("%s: Probing channel A\n", ahc_name(ahc)); - config_found((void *)ahc, &ahc->sc_link, ahcprint); - if (ahc->type & AHC_TWIN) { - printf("%s: Probing channel B\n", ahc_name(ahc)); - config_found((void *)ahc, &ahc->sc_link_b, ahcprint); - } - } else { - /* - * if implementation of IS_SCSIBUS_B() is changed to use - * ahc->sc_link.scsibus, then "ahc->sc_link.scsibus = 0xff;" - * is needed, here. - */ - - /* assert(ahc->type & AHC_TWIN); */ - printf("%s: Probing channel B\n", ahc_name(ahc)); - config_found((void *)ahc, &ahc->sc_link_b, ahcprint); - printf("%s: Probing channel A\n", ahc_name(ahc)); - config_found((void *)ahc, &ahc->sc_link, ahcprint); - } -#endif - return 1; -} - -/* - * Catch an interrupt from the adapter - */ -#if defined(__FreeBSD__) -void -#elif defined (__NetBSD__) -int -#endif -ahc_intr(arg) - void *arg; -{ - struct ahc_softc *ahc; - u_int8_t intstat; - - ahc = (struct ahc_softc *)arg; - intstat = ahc_inb(ahc, INTSTAT); - /* - * Is this interrupt for me? or for - * someone who is sharing my interrupt? - */ - if (!(intstat & INT_PEND)) -#if defined(__FreeBSD__) - return; -#elif defined(__NetBSD__) - return 0; -#endif - - if (intstat & CMDCMPLT) { - struct scb *scb; - u_int8_t scb_index; - u_int8_t qoutcnt; - int int_cleared; - - int_cleared = 0; - while ((qoutcnt = (ahc_inb(ahc, QOUTCNT) & ahc->qcntmask)) != 0) { - ahc->cmdoutcnt += qoutcnt; - for (; qoutcnt > 0; qoutcnt--) { - scb_index = ahc_inb(ahc, QOUTFIFO); - scb = ahc->scb_data->scbarray[scb_index]; - if (!scb || !(scb->flags & SCB_ACTIVE)) { - printf("%s: WARNING " - "no command for scb %d " - "(cmdcmplt)\nQOUTCNT == %d\n", - ahc_name(ahc), scb_index, - qoutcnt); - continue; - } - STAILQ_INSERT_TAIL(&ahc->cmplete_scbs, scb, - links); - } - if ((ahc->flags & AHC_PAGESCBS) != 0) { - if (ahc->cmdoutcnt >= ahc->qfullcount) { - /* - * Since paging only occurs on - * aic78X0 chips, we can use - * Auto Access Pause to clear - * the command count. - */ - ahc_outb(ahc, CMDOUTCNT, 0); - ahc->cmdoutcnt = 0; - } - } - while((scb = ahc->cmplete_scbs.stqh_first) != NULL) { - STAILQ_REMOVE_HEAD(&ahc->cmplete_scbs, links); - /* - * Save off the residual if there is one. - */ - if (scb->hscb->residual_SG_segment_count != 0) - ahc_calc_residual(scb); - if ((scb->flags & SCB_QUEUED_ABORT) != 0) { - /* Have to clean up any possible - * entries in the waiting queue and - * QINFIFO. - */ - int target; - char channel; - int lun; - u_int8_t tag; - - tag = SCB_LIST_NULL; - target = scb->xs->sc_link->target; - lun = scb->xs->sc_link->lun; - channel = (scb->hscb->tcl & SELBUSB) - ? 'B': 'A'; - if (scb->hscb->control & TAG_ENB) - tag = scb->hscb->tag; - ahc_reset_device(ahc, - target, - channel, - lun, - tag, - scb->xs->error); - ahc_run_done_queue(ahc); - } - ahc_done(ahc, scb); - } - ahc_outb(ahc, CLRINT, CLRCMDINT); - int_cleared++; - } - - if (int_cleared == 0) - ahc_outb(ahc, CLRINT, CLRCMDINT); - } - if (intstat & BRKADRINT) { - /* - * We upset the sequencer :-( - * Lookup the error message - */ - int i, error, num_errors; - - error = ahc_inb(ahc, ERROR); - num_errors = sizeof(hard_error)/sizeof(hard_error[0]); - for (i = 0; error != 1 && i < num_errors; i++) - error >>= 1; - printf("%s: brkadrint, %s at seqaddr = 0x%x\n", - ahc_name(ahc), hard_error[i].errmesg, - (ahc_inb(ahc, SEQADDR1) << 8) | - ahc_inb(ahc, SEQADDR0)); - - ahc_reset_device(ahc, ALL_TARGETS, ALL_CHANNELS, ALL_LUNS, - SCB_LIST_NULL, XS_DRIVER_STUFFUP); - ahc_run_done_queue(ahc); - } - if (intstat & SEQINT) - ahc_handle_seqint(ahc, intstat); - - if (intstat & SCSIINT) - ahc_handle_scsiint(ahc, intstat); - - if (ahc->waiting_scbs.stqh_first != NULL) - ahc_run_waiting_queue(ahc); -#if defined(__NetBSD__) - return 1; -#endif -} - -static void -ahc_handle_seqint(ahc, intstat) - struct ahc_softc *ahc; - u_int8_t intstat; -{ - struct scb *scb; - u_int16_t targ_mask; - u_int8_t target; - int scratch_offset; - char channel; - - if ((ahc_inb(ahc, SEQ_FLAGS) & RESELECTED) != 0) - target = ahc_inb(ahc, SELID); - else - target = ahc_inb(ahc, SCSIID); - target = (target >> 4) & 0x0f; - scratch_offset = target; - channel = ahc_inb(ahc, SBLKCTL) & SELBUSB ? 'B': 'A'; - if (channel == 'B') - scratch_offset += 8; - targ_mask = (0x01 << scratch_offset); - - switch (intstat & SEQINT_MASK) { - case NO_MATCH: - { - /* - * This could be for a normal abort request. - * Figure out the SCB that we were trying to find - * and only give an error if we didn't ask for this - * to happen. - */ - u_int8_t scb_index; - u_int8_t busy_scbid; - u_int8_t arg1; - - busy_scbid = ahc_index_busy_target(ahc, target, channel, - /*unbusy*/FALSE); - arg1 = ahc_inb(ahc, ARG_1); - - if (arg1 == SCB_LIST_NULL) - /* Untagged Request */ - scb_index = busy_scbid; - else - scb_index = arg1; - - if (scb_index < ahc->scb_data->numscbs) { - scb = ahc->scb_data->scbarray[scb_index]; - - if (scb->hscb->control & ABORT_SCB) { - /* - * We expected this. Let the busfree - * handler take care of this when we - * the abort is finially sent. - * Set IDENTIFY_SEEN so that the busfree - * handler knows that there is an SCB to - * cleanup. - */ - ahc_outb(ahc, SEQ_FLAGS, ahc_inb(ahc, SEQ_FLAGS) - | IDENTIFY_SEEN); - sc_print_addr(scb->xs->sc_link); - printf("reconnect SCB abort successfull\n"); - break; - } - } - - printf("%s:%c:%d: no active SCB for reconnecting " - "target - issuing BUS DEVICE RESET\n", - ahc_name(ahc), channel, target); - printf("SAVED_TCL == 0x%x ARG_1 == 0x%x SEQADDR == 0x%x\n", - ahc_inb(ahc, SAVED_TCL), arg1, - (ahc_inb(ahc, SEQADDR1) << 8) - | ahc_inb(ahc, SEQADDR0)); - - ahc_handle_devreset(ahc, target, channel); - - break; - } - case NO_MATCH_BUSY: - { - /* - * XXX Leave this as a panic for the time being since - * it indicates a bug in the timeout code for this - * to happen. - */ - u_int8_t scb_index; - - scb_index = ahc_inb(ahc, CUR_SCBID); - scb = ahc->scb_data->scbarray[scb_index]; - - panic("%s:%c:%d: Target busy link failure.\n", - ahc_name(ahc), (scb->hscb->tcl & SELBUSB) ? 'B' : 'A', - scb->xs->sc_link->target); - } - case SEND_REJECT: - { - u_int8_t rejbyte = ahc_inb(ahc, ACCUM); - printf("%s:%c:%d: Warning - unknown message received from " - "target (0x%x). SEQ_FLAGS == 0x%x. Rejecting\n", - ahc_name(ahc), channel, target, rejbyte, - ahc_inb(ahc, SEQ_FLAGS)); - break; - } - case NO_IDENT: - { - /* - * The reconnecting target either did not send an identify - * message, or did, but we didn't find and SCB to match and - * before it could respond to our ATN/abort, it hit a dataphase. - * The only safe thing to do is to blow it away with a bus - * reset. - */ - int found; - - printf("%s:%c:%d: Target did not send an IDENTIFY message. " - "LASTPHASE = 0x%x, SAVED_TCL == 0x%x\n", - ahc_name(ahc), channel, target, ahc_inb(ahc, LASTPHASE), - ahc_inb(ahc, SAVED_TCL)); - found = ahc_reset_channel(ahc, channel, XS_TIMEOUT, - /*initiate reset*/TRUE); - printf("%s: Issued Channel %c Bus Reset. " - "%d SCBs aborted\n", ahc_name(ahc), channel, found); - break; - } - case BAD_PHASE: - if (ahc_inb(ahc, LASTPHASE) == P_BUSFREE) { - printf("%s:%c:%d: Missed busfree.\n", ahc_name(ahc), - channel, target); - restart_sequencer(ahc); - } else { - printf("%s:%c:%d: unknown scsi bus phase. Attempting " - "to continue\n", ahc_name(ahc), channel, target); - } - break; - case EXTENDED_MSG: - { - u_int8_t message_length; - u_int8_t message_code; - u_int8_t scb_index; - - message_length = ahc_inb(ahc, MSGIN_EXT_LEN); - message_code = ahc_inb(ahc, MSGIN_EXT_OPCODE); - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc->scb_data->scbarray[scb_index]; - switch (message_code) { - case MSG_EXT_SDTR: - { - u_int8_t period; - u_int8_t offset; - u_int8_t saved_offset; - u_int8_t targ_scratch; - u_int8_t maxoffset; - u_int8_t rate; - - if (message_length != MSG_EXT_SDTR_LEN) { - ahc_outb(ahc, RETURN_1, SEND_REJ); - break; - } - period = ahc_inb(ahc, MSGIN_EXT_BYTES); - saved_offset = ahc_inb(ahc, MSGIN_EXT_BYTES + 1); - targ_scratch = ahc_inb(ahc, TARG_SCRATCH - + scratch_offset); - if (targ_scratch & WIDEXFER) - maxoffset = MAX_OFFSET_16BIT; - else - maxoffset = MAX_OFFSET_8BIT; - offset = MIN(saved_offset, maxoffset); - ahc_scsirate(ahc, &rate, &period, &offset, - channel, target); - /* Preserve the WideXfer flag */ - targ_scratch = rate | (targ_scratch & WIDEXFER); - - /* - * Update both the target scratch area and the - * current SCSIRATE. - */ - ahc_outb(ahc, TARG_SCRATCH + scratch_offset, - targ_scratch); - ahc_outb(ahc, SCSIRATE, targ_scratch); - - /* - * See if we initiated Sync Negotiation - * and didn't have to fall down to async - * transfers. - */ - if ((scb->flags & SCB_MSGOUT_SDTR) != 0) { - /* We started it */ - if (saved_offset == offset) { - /* - * Don't send an SDTR back to - * the target - */ - ahc_outb(ahc, RETURN_1, 0); - } else - /* Went too low - force async */ - ahc_outb(ahc, RETURN_1, SEND_REJ); - } else { - /* - * Send our own SDTR in reply - */ - printf("Sending SDTR!!\n"); - ahc_construct_sdtr(ahc, /*start_byte*/0, - period, offset); - ahc_outb(ahc, RETURN_1, SEND_MSG); - } - ahc->needsdtr &= ~targ_mask; - break; - } - case MSG_EXT_WDTR: - { - u_int8_t scratch, bus_width; - - if (message_length != MSG_EXT_WDTR_LEN) { - ahc_outb(ahc, RETURN_1, SEND_REJ); - break; - } - - bus_width = ahc_inb(ahc, MSGIN_EXT_BYTES); - scratch = ahc_inb(ahc, TARG_SCRATCH + scratch_offset); - - if ((scb->flags & SCB_MSGOUT_WDTR) != 0) { - /* - * Don't send a WDTR back to the - * target, since we asked first. - */ - ahc_outb(ahc, RETURN_1, 0); - switch (bus_width){ - case BUS_8_BIT: - scratch &= 0x7f; - break; - case BUS_16_BIT: - if (bootverbose) - printf("%s: target %d using " - "16Bit transfers\n", - ahc_name(ahc), target); - scratch |= WIDEXFER; - break; - case BUS_32_BIT: - /* - * How can we do 32bit transfers - * on a 16bit bus? - */ - ahc_outb(ahc, RETURN_1, SEND_REJ); - printf("%s: target %d requested 32Bit " - "transfers. Rejecting...\n", - ahc_name(ahc), target); - break; - default: - break; - } - } else { - /* - * Send our own WDTR in reply - */ - switch (bus_width) { - case BUS_8_BIT: - scratch &= 0x7f; - break; - case BUS_32_BIT: - case BUS_16_BIT: - if (ahc->type & AHC_WIDE) { - /* Negotiate 16_BITS */ - bus_width = BUS_16_BIT; - if (bootverbose) - printf("%s: target %d " - "using 16Bit " - "transfers\n", - ahc_name(ahc), - target); - scratch |= WIDEXFER; - } else - bus_width = BUS_8_BIT; - break; - default: - break; - } - ahc_construct_wdtr(ahc, /*start_byte*/0, - bus_width); - ahc_outb(ahc, RETURN_1, SEND_MSG); - } - ahc->needwdtr &= ~targ_mask; - ahc_outb(ahc, TARG_SCRATCH + scratch_offset, scratch); - ahc_outb(ahc, SCSIRATE, scratch); - break; - } - default: - /* Unknown extended message. Reject it. */ - ahc_outb(ahc, RETURN_1, SEND_REJ); - } - break; - } - case REJECT_MSG: - { - /* - * What we care about here is if we had an - * outstanding SDTR or WDTR message for this - * target. If we did, this is a signal that - * the target is refusing negotiation. - */ - - u_int8_t targ_scratch; - u_int8_t scb_index; - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc->scb_data->scbarray[scb_index]; - - targ_scratch = ahc_inb(ahc, TARG_SCRATCH - + scratch_offset); - - if ((scb->flags & SCB_MSGOUT_WDTR) != 0) { - /* note 8bit xfers and clear flag */ - targ_scratch &= 0x7f; - ahc->needwdtr &= ~targ_mask; - printf("%s:%c:%d: refuses WIDE negotiation. Using " - "8bit transfers\n", ahc_name(ahc), - channel, target); - } else if ((scb->flags & SCB_MSGOUT_SDTR) != 0) { - /* note asynch xfers and clear flag */ - targ_scratch &= 0xf0; - ahc->needsdtr &= ~targ_mask; - printf("%s:%c:%d: refuses synchronous negotiation. " - "Using asynchronous transfers\n", - ahc_name(ahc), - channel, target); - } else { - /* - * Otherwise, we ignore it. - */ -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWMISC) - printf("%s:%c:%d: Message reject -- ignored\n", - ahc_name(ahc), channel, target); -#endif - break; - } - ahc_outb(ahc, TARG_SCRATCH + scratch_offset, targ_scratch); - ahc_outb(ahc, SCSIRATE, targ_scratch); - break; - } - case BAD_STATUS: - { - u_int8_t scb_index; - struct scsi_xfer *xs; - struct hardware_scb *hscb; - - /* - * The sequencer will notify us when a command - * has an error that would be of interest to - * the kernel. This allows us to leave the sequencer - * running in the common case of command completes - * without error. The sequencer will already have - * dma'd the SCB back up to us, so we can reference - * the in kernel copy directly. - */ - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc->scb_data->scbarray[scb_index]; - hscb = scb->hscb; - - /* - * Set the default return value to 0 (don't - * send sense). The sense code will change - * this if needed and this reduces code - * duplication. - */ - ahc_outb(ahc, RETURN_1, 0); - if (!(scb && (scb->flags & SCB_ACTIVE))) { - printf("%s:%c:%d: ahc_intr - referenced scb " - "not valid during seqint 0x%x scb(%d)\n", - ahc_name(ahc), - channel, target, intstat, - scb_index); - goto clear; - } - - xs = scb->xs; - - xs->status = hscb->status; - switch (hscb->status){ - case SCSI_OK: - printf("%s: Interrupted for staus of" - " 0???\n", ahc_name(ahc)); - break; - case SCSI_CHECK: -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWSENSE) { - sc_print_addr(xs->sc_link); - printf("SCB %d: requests Check Status\n", - scb->hscb->tag); - } -#endif - - if ((xs->error == XS_NOERROR) - && !(scb->flags & SCB_SENSE)) { - struct ahc_dma_seg *sg = scb->ahc_dma; - struct scsi_sense *sc = &(scb->sense_cmd); - - /* - * Save off the residual if there is one. - */ - if (hscb->residual_SG_segment_count != 0) - ahc_calc_residual(scb); - -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWSENSE) { - sc_print_addr(xs->sc_link); - printf("Sending Sense\n"); - } -#endif -#if defined(__FreeBSD__) - sc->op_code = REQUEST_SENSE; -#elif defined(__NetBSD__) - sc->opcode = REQUEST_SENSE; -#endif - sc->byte2 = xs->sc_link->lun << 5; - sc->length = sizeof(struct scsi_sense_data); - sc->control = 0; - - sg->addr = vtophys(&xs->sense); - sg->len = sizeof(struct scsi_sense_data); - - /* XXX should allow disconnection, but - * can't as it might allow overlapped - * tagged commands. - */ - /* hscb->control &= DISCENB; */ - hscb->control = 0; - hscb->status = 0; - hscb->SG_segment_count = 1; - hscb->SG_list_pointer = vtophys(sg); - hscb->data = sg->addr; - /* Maintain SCB_LINKED_NEXT */ - hscb->datalen &= 0xFF000000; - hscb->datalen |= sg->len; - hscb->cmdpointer = vtophys(sc); - hscb->cmdlen = sizeof(*sc); - scb->sg_count = hscb->SG_segment_count; - scb->flags |= SCB_SENSE; - /* - * Ensure the target is busy since this - * will be an untagged request. - */ - ahc_busy_target(ahc, target, channel, - hscb->tag); - ahc_outb(ahc, RETURN_1, SEND_SENSE); - - /* - * Ensure we have enough time to actually - * retrieve the sense. - */ - untimeout(ahc_timeout, (caddr_t)scb, - scb->xs->timeout_ch); - scb->xs->timeout_ch = timeout(ahc_timeout, - (caddr_t)scb, hz); - break; - } - /* - * Clear the SCB_SENSE Flag and have - * the sequencer do a normal command - * complete with either a "DRIVER_STUFFUP" - * error or whatever other error condition - * we already had. - */ - scb->flags &= ~SCB_SENSE; - if (xs->error == XS_NOERROR) - xs->error = XS_DRIVER_STUFFUP; - break; - case SCSI_QUEUE_FULL: - if (scb->hscb->control & TAG_ENB) { - /* - * The upper level SCSI code in 3.0 - * handles this properly... - */ - struct scsi_link *sc_link; - - sc_link = xs->sc_link; - if (sc_link->active > 2 - && sc_link->opennings != 0) { - /* truncate the opennings */ - sc_link->opennings = 0; - sc_print_addr(sc_link); - printf("Tagged openings reduced to " - "%d\n", sc_link->active); - } - /* - * XXX requeue this unconditionally. - */ - scb->xs->retries++; - scb->xs->error = XS_BUSY; - break; - } - /* Else treat as if it is a BUSY condition */ - scb->hscb->status = SCSI_BUSY; - /* Fall Through... */ - case SCSI_BUSY: - xs->error = XS_BUSY; - sc_print_addr(xs->sc_link); - printf("Target Busy\n"); - break; - case SCSI_RSVD: - xs->error = XS_BUSY; /*XXX*/ - sc_print_addr(xs->sc_link); - printf("Target Reserved\n"); - break; - default: - sc_print_addr(xs->sc_link); - printf("unexpected targ_status: %x\n", hscb->status); - xs->error = XS_DRIVER_STUFFUP; - break; - } - break; - } - case AWAITING_MSG: - { - int scb_index; - u_int8_t message_offset; - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc->scb_data->scbarray[scb_index]; - - /* - * This SCB had MK_MESSAGE set in its control byte, - * informing the sequencer that we wanted to send a - * special message to this target. - */ - message_offset = ahc_inb(ahc, MSG_LEN); - if (scb->flags & SCB_DEVICE_RESET) { - ahc_outb(ahc, MSG_OUT, MSG_BUS_DEV_RESET); - ahc_outb(ahc, MSG_LEN, 1); - sc_print_addr(scb->xs->sc_link); - printf("Bus Device Reset Message Sent\n"); - } else if (scb->flags & SCB_ABORT) { - if ((scb->hscb->control & TAG_ENB) != 0) - ahc_outb(ahc, MSG_OUT + message_offset, - MSG_ABORT_TAG); - else - ahc_outb(ahc, MSG_OUT + message_offset, - MSG_ABORT); - ahc_outb(ahc, MSG_LEN, message_offset + 1); - sc_print_addr(scb->xs->sc_link); - printf("Abort Message Sent\n"); - } else if (scb->flags & SCB_MSGOUT_WDTR) { - ahc_construct_wdtr(ahc, message_offset, BUS_16_BIT); - } else if (scb->flags & SCB_MSGOUT_SDTR) { - int sxfr; - int i; - u_int16_t ultraenable; - u_int8_t target_scratch; - - /* Pull the user defined setting */ - target_scratch = ahc_inb(ahc, TARG_SCRATCH - + scratch_offset); - - sxfr = target_scratch & SXFR; - ultraenable = ahc_inb(ahc, ULTRA_ENB) - | (ahc_inb(ahc, ULTRA_ENB + 1) << 8); - - if (ultraenable & targ_mask) - /* Want an ultra speed in the table */ - sxfr |= 0x100; - - for (i = 0; i < ahc_num_syncrates; i++) - if (sxfr == ahc_syncrates[i].sxfr) - break; - - ahc_construct_sdtr(ahc, message_offset, - ahc_syncrates[i].period, - (target_scratch & WIDEXFER) ? - MAX_OFFSET_16BIT : MAX_OFFSET_8BIT); - } else - panic("ahc_intr: AWAITING_MSG for an SCB that " - "does not have a waiting message"); - break; - } - case DATA_OVERRUN: - { - /* - * When the sequencer detects an overrun, it - * sets STCNT to 0x00ffffff and allows the - * target to complete its transfer in - * BITBUCKET mode. - */ - u_int8_t scbindex = ahc_inb(ahc, SCB_TAG); - u_int8_t lastphase = ahc_inb(ahc, LASTPHASE); - u_int32_t overrun; - int i; - scb = ahc->scb_data->scbarray[scbindex]; - overrun = ahc_inb(ahc, STCNT) - | (ahc_inb(ahc, STCNT + 1) << 8) - | (ahc_inb(ahc, STCNT + 2) << 16); - overrun = 0x00ffffff - overrun; - sc_print_addr(scb->xs->sc_link); - printf("data overrun of %d bytes detected in %s phase." - " Tag == 0x%x. Forcing a retry.\n", overrun, - lastphase == P_DATAIN ? "Data-In" : "Data-Out", - scb->hscb->tag); - sc_print_addr(scb->xs->sc_link); - printf("%s seen Data Phase. Length = %d. NumSGs = %d.\n", - ahc_inb(ahc, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't", - scb->xs->datalen, scb->sg_count); - for (i = 0; i < scb->sg_count; i++) { - printf("sg[%d] - Addr 0x%x : Length %d\n", - i, - scb->ahc_dma[i].addr, - scb->ahc_dma[i].len); - } - /* - * Set this and it will take affect when the - * target does a command complete. - */ - scb->xs->error = XS_DRIVER_STUFFUP; - break; - } -#if NOT_YET - /* XXX Fill these in later */ - case MESG_BUFFER_BUSY: - break; - case MSGIN_PHASEMIS: - break; -#endif -#if 0 - case SCB_TRACE_POINT: - { - /* - * Print out the bus phase - */ - char *phase; - u_int8_t scbindex = ahc_inb(ahc, SCB_TAG); - u_int8_t lastphase = ahc_inb(ahc, LASTPHASE); - - scb = ahc->scb_data->scbarray[scbindex]; - sc_print_addr(scb->xs->sc_link); - - switch (lastphase) { - case P_DATAOUT: - phase = "Data-Out"; - break; - case P_DATAIN: - phase = "Data-In"; - break; - case P_COMMAND: - phase = "Command"; - break; - case P_MESGOUT: - phase = "Message-Out"; - break; - case P_STATUS: - phase = "Status"; - break; - case P_MESGIN: - phase = "Message-In"; - break; - default: - phase = "busfree"; - break; - } - printf("- %s\n", phase); - break; - } -#endif - case ABORT_CMDCMPLT: - /* This interrupt serves to pause the sequencer - * until we can clean up the QOUTFIFO allowing us - * to hanle any abort SCBs that may have completed - * yet still have an SCB in the QINFIFO or - * waiting for selection queue. By the time we get - * here, we should have already cleaned up the - * queues, so all we need to do is unpause the sequencer. - */ - break; - default: - printf("ahc_intr: seqint, " - "intstat == 0x%x, scsisigi = 0x%x\n", - intstat, ahc_inb(ahc, SCSISIGI)); - break; - } - -clear: - /* - * Clear the upper byte that holds SEQINT status - * codes and clear the SEQINT bit. - */ - ahc_outb(ahc, CLRINT, CLRSEQINT); - - /* - * The sequencer is paused immediately on - * a SEQINT, so we should restart it when - * we're done. - */ - unpause_sequencer(ahc, /*unpause_always*/TRUE); -} - -static void -ahc_handle_scsiint(ahc, intstat) - struct ahc_softc *ahc; - u_int8_t intstat; -{ - u_int8_t scb_index; - u_int8_t status; - struct scb *scb; - - scb_index = ahc_inb(ahc, SCB_TAG); - status = ahc_inb(ahc, SSTAT1); - - if (scb_index < ahc->scb_data->numscbs) { - scb = ahc->scb_data->scbarray[scb_index]; - if ((scb->flags & SCB_ACTIVE) == 0) - scb = NULL; - } else - scb = NULL; - - if ((status & SCSIRSTI) != 0) { - char channel; - channel = (ahc_inb(ahc, SBLKCTL) & SELBUSB) ? 'B' : 'A'; - printf("%s: Someone reset channel %c\n", - ahc_name(ahc), channel); - ahc_reset_channel(ahc, - channel, - XS_BUSY, - /* Initiate Reset */FALSE); - scb = NULL; - } else if ((status & BUSFREE) != 0 && (status & SELTO) == 0) { - /* - * First look at what phase we were last in. - * If its message out, chances are pretty good - * that the busfree was in response to one of - * our abort requests. - */ - u_int8_t lastphase = ahc_inb(ahc, LASTPHASE); - u_int8_t target = (ahc_inb(ahc, SAVED_TCL) >> 4) & 0x0f; - char channel = ahc_inb(ahc, SBLKCTL) & SELBUSB ? 'B': 'A'; - int printerror = 1; - - ahc_outb(ahc, SCSISEQ, 0); - if (lastphase == P_MESGOUT) { - u_int8_t sindex; - u_int8_t message; - - sindex = ahc_inb(ahc, SINDEX); - message = ahc_inb(ahc, sindex - 1); - - if (message == MSG_ABORT) { - - sc_print_addr(scb->xs->sc_link); - printf("SCB %d - Abort Completed.\n", - scb->hscb->tag); - ahc_reset_device(ahc, target, channel, - SCB_LUN(scb), - SCB_LIST_NULL, - XS_TIMEOUT); - ahc_run_done_queue(ahc); - scb = NULL; - printerror = 0; - } else if (message == MSG_ABORT_TAG) { - - sc_print_addr(scb->xs->sc_link); - printf("SCB %d - Abort Tag Completed.\n", - scb->hscb->tag); - ahc_reset_device(ahc, - target, - channel, - SCB_LUN(scb), - scb->hscb->tag, - XS_TIMEOUT); - ahc_run_done_queue(ahc); - scb = NULL; - printerror = 0; - } else if (message == MSG_BUS_DEV_RESET) { - ahc_handle_devreset(ahc, target, - channel); - scb = NULL; - printerror = 0; - } - } - if (printerror != 0) { - if (scb != NULL) { - u_int8_t tag; - - if ((scb->hscb->control & TAG_ENB) != 0) - tag = scb->hscb->tag; - else - tag = SCB_LIST_NULL; - ahc_reset_device(ahc, target, channel, - SCB_LUN(scb), tag, XS_TIMEOUT); - } else { - /* - * XXX can we handle this better? - * Reset the bus? Send a Bus Device Reset? - */ - ahc_reset_device(ahc, target, channel, - ALL_LUNS, SCB_LIST_NULL, - XS_TIMEOUT); - printf("%s: ", ahc_name(ahc)); - } - printf("Unexpected busfree. LASTPHASE == 0x%x\n" - "SEQADDR == 0x%x\n", - lastphase, (ahc_inb(ahc, SEQADDR1) << 8) - | ahc_inb(ahc, SEQADDR0)); - } - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); - ahc_outb(ahc, CLRSINT1, CLRBUSFREE); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - restart_sequencer(ahc); - } else if ((status & SELTO) != 0) { - struct scsi_xfer *xs; - u_int8_t scbptr; - u_int8_t nextscb; - - scbptr = ahc_inb(ahc, WAITING_SCBH); - ahc_outb(ahc, SCBPTR, scbptr); - scb_index = ahc_inb(ahc, SCB_TAG); - - if (scb_index < ahc->scb_data->numscbs) { - scb = ahc->scb_data->scbarray[scb_index]; - if ((scb->flags & SCB_ACTIVE) == 0) - scb = NULL; - } else - scb = NULL; - - if (scb == NULL) { - printf("%s: ahc_intr - referenced scb not " - "valid during SELTO scb(%d)\n", - ahc_name(ahc), scb_index); - printf("SEQADDR = 0x%x SCSISEQ = 0x%x " - "SSTAT0 = 0x%x SSTAT1 = 0x%x\n", - ahc_inb(ahc, SEQADDR0) - | (ahc_inb(ahc, SEQADDR1) << 8), - ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SSTAT0), - ahc_inb(ahc,SSTAT1)); - } else { - /* - * XXX If we queued an abort tag, go clean up the - * disconnected list. - */ - xs = scb->xs; - xs->error = XS_SELTIMEOUT; - /* - * Clear any pending messages for the timed out - * target, and mark the target as free - */ - ahc_outb(ahc, MSG_LEN, 0); - ahc_index_busy_target(ahc, SCB_TARGET(scb), - SCB_IS_SCSIBUS_B(scb) ? 'B' : 'A', - /*unbusy*/TRUE); - - ahc_outb(ahc, SCB_CONTROL, 0); - /* Shift the waiting Q forward. */ - nextscb = ahc_inb(ahc, SCB_NEXT); - ahc_outb(ahc, WAITING_SCBH, nextscb); - - ahc_add_curscb_to_free_list(ahc); - } - /* Stop the selection */ - ahc_outb(ahc, SCSISEQ, 0); - - ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE); - - ahc_outb(ahc, CLRINT, CLRSCSIINT); - - restart_sequencer(ahc); - } else if (scb == NULL) { - printf("%s: ahc_intr - referenced scb not " - "valid during scsiint 0x%x scb(%d)\n" - "SIMODE0 = 0x%x, SIMODE1 = 0x%x, SSTAT0 = 0x%x\n" - "SEQADDR = 0x%x\n", ahc_name(ahc), - status, scb_index, ahc_inb(ahc, SIMODE0), - ahc_inb(ahc, SIMODE1), ahc_inb(ahc, SSTAT0), - (ahc_inb(ahc, SEQADDR1) << 8) - | ahc_inb(ahc, SEQADDR0)); - ahc_outb(ahc, CLRSINT1, status); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - unpause_sequencer(ahc, /*unpause_always*/TRUE); - scb = NULL; - } else if ((status & SCSIPERR) != 0) { - /* - * Determine the bus phase and - * queue an appropriate message - */ - char *phase; - u_int8_t mesg_out = MSG_NOOP; - u_int8_t lastphase = ahc_inb(ahc, LASTPHASE); - struct scsi_xfer *xs; - - xs = scb->xs; - sc_print_addr(xs->sc_link); - - switch (lastphase) { - case P_DATAOUT: - phase = "Data-Out"; - break; - case P_DATAIN: - phase = "Data-In"; - mesg_out = MSG_INITIATOR_DET_ERR; - break; - case P_COMMAND: - phase = "Command"; - break; - case P_MESGOUT: - phase = "Message-Out"; - break; - case P_STATUS: - phase = "Status"; - mesg_out = MSG_INITIATOR_DET_ERR; - break; - case P_MESGIN: - phase = "Message-In"; - mesg_out = MSG_PARITY_ERROR; - break; - default: - phase = "unknown"; - break; - } - printf("parity error during %s phase.\n", phase); - - /* - * We've set the hardware to assert ATN if we - * get a parity error on "in" phases, so all we - * need to do is stuff the message buffer with - * the appropriate message. "In" phases have set - * mesg_out to something other than MSG_NOP. - */ - if (mesg_out != MSG_NOOP) { - ahc_outb(ahc, MSG_OUT, mesg_out); - ahc_outb(ahc, MSG_LEN, 1); - scb = NULL; - } else - /* - * Should we allow the target to make - * this decision for us? If we get a - * sense request from the drive, we will - * not fetch it since xs->error != XS_NOERROR. - * perhaps we need two error fields in the - * xs structure? - */ - xs->error = XS_DRIVER_STUFFUP; - ahc_outb(ahc, CLRSINT1, CLRSCSIPERR); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - unpause_sequencer(ahc, /*unpause_always*/TRUE); - } else { - sc_print_addr(scb->xs->sc_link); - printf("Unknown SCSIINT. Status = 0x%x\n", status); - ahc_outb(ahc, CLRSINT1, status); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - unpause_sequencer(ahc, /*unpause_always*/TRUE); - scb = NULL; - } - if (scb != NULL) { - /* We want to process the command */ - ahc_done(ahc, scb); - } -} - -static void -ahc_handle_devreset(ahc, target, channel) - struct ahc_softc *ahc; - int target; - char channel; -{ - u_int16_t targ_mask; - u_int8_t targ_scratch; - int scratch_offset = target; - int found; - - if (channel == 'B') - scratch_offset += 8; - targ_mask = (0x01 << scratch_offset); - /* - * Go back to async/narrow transfers and - * renegotiate. - */ - ahc->needsdtr |= ahc->needsdtr_orig & targ_mask; - ahc->needwdtr |= ahc->needwdtr_orig & targ_mask; - ahc->sdtrpending &= ~targ_mask; - ahc->wdtrpending &= ~targ_mask; - targ_scratch = ahc_inb(ahc, TARG_SCRATCH + scratch_offset); - targ_scratch &= SXFR; - ahc_outb(ahc, TARG_SCRATCH + scratch_offset, targ_scratch); - found = ahc_reset_device(ahc, target, channel, ALL_LUNS, - SCB_LIST_NULL, XS_NOERROR); - printf("%s: Bus Device Reset delivered. %d SCBs aborted\n", - ahc_name(ahc), found); - ahc_run_done_queue(ahc); -} - -/* - * We have a scb which has been processed by the - * adaptor, now we look to see how the operation - * went. - */ -static void -ahc_done(ahc, scb) - struct ahc_softc *ahc; - struct scb *scb; -{ - struct scsi_xfer *xs = scb->xs; - - SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahc_done\n")); - /* - * If the recovery SCB completes, we have to be - * out of our timeout. - */ - if (scb->flags & SCB_RECOVERY_SCB) { - ahc->in_timeout = FALSE; - sc_print_addr(scb->xs->sc_link); - printf("no longer in timeout\n"); - } - /* - * Put the results of the operation - * into the xfer and call whoever started it - */ - /* Don't override the error value. */ - if (xs->error == XS_NOERROR - && (scb->flags & SCB_SENSE) != 0) - xs->error = XS_SENSE; - -#if defined(__FreeBSD__) - if ((xs->flags & SCSI_ERR_OK) && !(xs->error == XS_SENSE)) { - /* All went correctly OR errors expected */ - xs->error = XS_NOERROR; - } -#elif defined(__NetBSD__) - /* - * Since NetBSD doesn't have error ignoring operation mode - * (SCSI_ERR_OK in FreeBSD), we don't have to care this case. - */ -#endif - xs->flags |= ITSDONE; -#ifdef AHC_TAGENABLE - /* - * This functionality will be provided by the generic SCSI layer - * in FreeBSD 3.0. - */ - if (xs->cmd->opcode == INQUIRY && xs->error == XS_NOERROR) { - struct scsi_inquiry_data *inq_data; - u_int16_t mask = 0x01 << (xs->sc_link->target | - (scb->hscb->tcl & 0x08)); - /* - * Sneak a look at the results of the SCSI Inquiry - * command and see if we can do Tagged queing. This - * should really be done by the higher level drivers. - */ - inq_data = (struct scsi_inquiry_data *)xs->data; - if ((inq_data->flags & SID_CmdQue) - && !(ahc->tagenable & mask)) { - printf("%s: target %d Tagged Queuing Device\n", - ahc_name(ahc), xs->sc_link->target); - ahc->tagenable |= mask; - if (ahc->scb_data->maxhscbs >= 16 - || (ahc->flags & AHC_PAGESCBS)) { - /* Default to 8 tags */ - xs->sc_link->opennings += 6; - } else { - /* - * Default to 4 tags on whimpy - * cards that don't have much SCB - * space and can't page. This prevents - * a single device from hogging all - * slots. We should really have a better - * way of providing fairness. - */ - xs->sc_link->opennings += 2; - } - } - } -#endif /* AHC_TAGENABLE */ - if ((scb->flags & (SCB_MSGOUT_WDTR|SCB_MSGOUT_SDTR)) != 0) { - /* - * Turn off the pending flags for any DTR messages - * regardless of whether they completed successfully - * or not. This ensures that we don't have lingering - * state after we abort an SCB. - */ - u_int16_t mask; - - mask = (0x01 << (xs->sc_link->target - | (IS_SCSIBUS_B(ahc, xs->sc_link) ? SELBUSB : 0))); - if (scb->flags & SCB_MSGOUT_WDTR) - ahc->wdtrpending &= ~mask; - if (scb->flags & SCB_MSGOUT_SDTR) - ahc->sdtrpending &= ~mask; - } - untimeout(ahc_timeout, (caddr_t)scb, scb->xs->timeout_ch); - ahc_free_scb(ahc, scb); - /* - * If we're polling, we rely on the ITS_DONE flag in the xs structure - * to know that the command has completed. Unfortunately, scsi_done - * can cause the same xs to get requeued putting us in an infinite - * loop. So, we defer the scsi_done call until the poll routine exits - * its loop. I hate the way this works. - */ - if ((xs->flags & SCSI_NOMASK) == 0) - scsi_done(xs); -} - -/* - * Start the board, ready for normal operation - */ -int -ahc_init(ahc) - struct ahc_softc *ahc; -{ - u_int8_t scsi_conf, sblkctl, sxfrctl1, i; - u_int16_t ultraenable = 0; - int max_targ = 15; - /* - * Assume we have a board at this stage and it has been reset. - */ - - /* Handle the SCBPAGING option */ -#ifndef AHC_SCBPAGING_ENABLE - ahc->flags &= ~AHC_PAGESCBS; -#endif - - /* Determine channel configuration and who we are on the scsi bus. */ - switch ((sblkctl = ahc_inb(ahc, SBLKCTL) & 0x0a)) { - case 0: - ahc->our_id = (ahc_inb(ahc, SCSICONF) & HSCSIID); - ahc->flags &= ~AHC_CHANNEL_B_PRIMARY; - if ((ahc->type & AHC_39X) != 0) { - char channel = 'A'; - - if ((ahc->flags & (AHC_CHNLB|AHC_CHNLC)) != 0) - channel = ahc->flags & AHC_CHNLB ? 'B' : 'C'; - printf("Channel %c, SCSI Id=%d, ", channel, - ahc->our_id); - } else - printf("Single Channel, SCSI Id=%d, ", ahc->our_id); - ahc_outb(ahc, SEQ_FLAGS, ahc->flags & AHC_PAGESCBS); - break; - case 2: - ahc->our_id = (ahc_inb(ahc, SCSICONF + 1) & HWSCSIID); - ahc->flags &= ~AHC_CHANNEL_B_PRIMARY; - if ((ahc->type & AHC_39X) != 0) { - char channel = 'A'; - - if ((ahc->flags & (AHC_CHNLB|AHC_CHNLC)) != 0) - channel = ahc->flags & AHC_CHNLB ? 'B' : 'C'; - printf("Wide Channel %c, SCSI Id=%d, ", channel, - ahc->our_id); - } else - printf("Wide Channel, SCSI Id=%d, ", ahc->our_id); - ahc->type |= AHC_WIDE; - ahc_outb(ahc, SEQ_FLAGS, WIDE_BUS | (ahc->flags & AHC_PAGESCBS)); - break; - case 8: - ahc->our_id = (ahc_inb(ahc, SCSICONF) & HSCSIID); - ahc->our_id_b = (ahc_inb(ahc, SCSICONF + 1) & HSCSIID); - printf("Twin Channel, A SCSI Id=%d, B SCSI Id=%d, ", - ahc->our_id, ahc->our_id_b); - ahc->type |= AHC_TWIN; - ahc_outb(ahc, SEQ_FLAGS, TWIN_BUS | (ahc->flags & AHC_PAGESCBS)); - break; - default: - printf(" Unsupported adapter type. Ignoring\n"); - return(-1); - } - - /* Determine the number of SCBs and initialize them */ - - if (ahc->scb_data->maxhscbs == 0) { - /* SCB 0 heads the free list */ - ahc_outb(ahc, FREE_SCBH, 0); - for (i = 0; i < AHC_SCB_MAX; i++) { - ahc_outb(ahc, SCBPTR, i); - ahc_outb(ahc, SCB_CONTROL, i); - if(ahc_inb(ahc, SCB_CONTROL) != i) - break; - ahc_outb(ahc, SCBPTR, 0); - if(ahc_inb(ahc, SCB_CONTROL) != 0) - break; - ahc_outb(ahc, SCBPTR, i); - - /* Clear the control byte. */ - ahc_outb(ahc, SCB_CONTROL, 0); - - /* Set the next pointer */ - ahc_outb(ahc, SCB_NEXT, i+1); - - /* Make the tag number invalid */ - ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL); - - /* No Busy non-tagged targets yet */ - ahc_outb(ahc, SCB_BUSYTARGETS, SCB_LIST_NULL); - ahc_outb(ahc, SCB_BUSYTARGETS + 1, SCB_LIST_NULL); - ahc_outb(ahc, SCB_BUSYTARGETS + 2, SCB_LIST_NULL); - ahc_outb(ahc, SCB_BUSYTARGETS + 3, SCB_LIST_NULL); - } - - /* Make that the last SCB terminates the free list */ - ahc_outb(ahc, SCBPTR, i-1); - ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL); - - /* Ensure we clear the 0 SCB's control byte. */ - ahc_outb(ahc, SCBPTR, 0); - ahc_outb(ahc, SCB_CONTROL, 0); - - ahc->scb_data->maxhscbs = i; - } - - if ((ahc->scb_data->maxhscbs < AHC_SCB_MAX) - && (ahc->flags & AHC_PAGESCBS)) { - u_int8_t max_scbid = 255; - - /* Determine the number of valid bits in the FIFOs */ - ahc_outb(ahc, QINFIFO, max_scbid); - max_scbid = ahc_inb(ahc, QINFIFO); - ahc->scb_data->maxscbs = MIN(AHC_SCB_MAX, max_scbid + 1); - printf("%d/%d SCBs\n", ahc->scb_data->maxhscbs, - ahc->scb_data->maxscbs); - } else { - ahc->scb_data->maxscbs = ahc->scb_data->maxhscbs; - ahc->flags &= ~AHC_PAGESCBS; - printf("%d SCBs\n", ahc->scb_data->maxhscbs); - } - -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWMISC) { - printf("%s: hardware scb %d bytes; kernel scb %d bytes; " - "ahc_dma %d bytes\n", - ahc_name(ahc), - sizeof(struct hardware_scb), - sizeof(struct scb), - sizeof(struct ahc_dma_seg)); - } -#endif /* AHC_DEBUG */ - - /* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels*/ - if (ahc->type & AHC_TWIN) { - /* - * The device is gated to channel B after a chip reset, - * so set those values first - */ - ahc_outb(ahc, SCSIID, ahc->our_id_b); - scsi_conf = ahc_inb(ahc, SCSICONF + 1); - sxfrctl1 = ahc_inb(ahc, SXFRCTL1); - ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) - |(sxfrctl1 & STPWEN) - |ENSTIMER|ACTNEGEN); - ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); - if (ahc->type & AHC_ULTRA) - ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN|FAST20); - else - ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); - - if (scsi_conf & RESET_SCSI) { - /* Reset the bus */ - if (bootverbose) - printf("%s: Resetting Channel B\n", - ahc_name(ahc)); - ahc_reset_current_bus(ahc); - } - - /* Select Channel A */ - ahc_outb(ahc, SBLKCTL, 0); - } - ahc_outb(ahc, SCSIID, ahc->our_id); - scsi_conf = ahc_inb(ahc, SCSICONF); - sxfrctl1 = ahc_inb(ahc, SXFRCTL1); - ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) - |(sxfrctl1 & STPWEN) - |ENSTIMER|ACTNEGEN); - ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); - if (ahc->type & AHC_ULTRA) - ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN|FAST20); - else - ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); - - if (scsi_conf & RESET_SCSI) { - /* Reset the bus */ - if (bootverbose) - printf("%s: Resetting Channel A\n", ahc_name(ahc)); - - ahc_reset_current_bus(ahc); - } - - /* - * Look at the information that board initialization or - * the board bios has left us. In the lower four bits of each - * target's scratch space any value other than 0 indicates - * that we should initiate synchronous transfers. If it's zero, - * the user or the BIOS has decided to disable synchronous - * negotiation to that target so we don't activate the needsdtr - * flag. - */ - ahc->needsdtr_orig = 0; - ahc->needwdtr_orig = 0; - - /* Grab the disconnection disable table and invert it for our needs */ - if (ahc->flags & AHC_USEDEFAULTS) { - printf("%s: Host Adapter Bios disabled. Using default SCSI " - "device parameters\n", ahc_name(ahc)); - ahc->discenable = 0xff; - } else - ahc->discenable = ~((ahc_inb(ahc, DISC_DSB + 1) << 8) - | ahc_inb(ahc, DISC_DSB)); - - if (!(ahc->type & (AHC_WIDE|AHC_TWIN))) - max_targ = 7; - - for (i = 0; i <= max_targ; i++) { - u_int8_t target_settings; - if (ahc->flags & AHC_USEDEFAULTS) { - target_settings = 0; /* 10MHz/20MHz */ - ahc->needsdtr_orig |= (0x01 << i); - ahc->needwdtr_orig |= (0x01 << i); - if (ahc->type & AHC_ULTRA) - ultraenable |= (0x01 << i); - } else { - /* Take the settings leftover in scratch RAM. */ - target_settings = ahc_inb(ahc, TARG_SCRATCH + i); - - if (target_settings & 0x0f) { - ahc->needsdtr_orig |= (0x01 << i); - /*Default to a asynchronous transfers(0 offset)*/ - target_settings &= 0xf0; - } - if (target_settings & 0x80) { - ahc->needwdtr_orig |= (0x01 << i); - /* - * We'll set the Wide flag when we - * are successful with Wide negotiation. - * Turn it off for now so we aren't - * confused. - */ - target_settings &= 0x7f; - } - if (ahc->type & AHC_ULTRA) { - /* - * Enable Ultra for any target that - * has a valid ultra syncrate setting. - */ - u_int8_t rate = target_settings & 0x70; - if (rate == 0x00 || rate == 0x10 || - rate == 0x20 || rate == 0x40) { - if (rate == 0x40) { - /* Treat 10MHz specially */ - target_settings &= ~0x70; - } else - ultraenable |= (0x01 << i); - } - } - } - ahc_outb(ahc, TARG_SCRATCH+i,target_settings); - } - /* - * If we are not a WIDE device, forget WDTR. This - * makes the driver work on some cards that don't - * leave these fields cleared when the BIOS is not - * installed. - */ - if ((ahc->type & AHC_WIDE) == 0) - ahc->needwdtr_orig = 0; - ahc->needsdtr = ahc->needsdtr_orig; - ahc->needwdtr = ahc->needwdtr_orig; - ahc->sdtrpending = 0; - ahc->wdtrpending = 0; - ahc->tagenable = 0; - ahc->orderedtag = 0; - - ahc_outb(ahc, ULTRA_ENB, ultraenable & 0xff); - ahc_outb(ahc, ULTRA_ENB + 1, (ultraenable >> 8) & 0xff); - -#ifdef AHC_DEBUG - /* How did we do? */ - if (ahc_debug & AHC_SHOWMISC) - printf("NEEDSDTR == 0x%x\nNEEDWDTR == 0x%x\n" - "DISCENABLE == 0x%x\n", ahc->needsdtr, - ahc->needwdtr, ahc->discenable); -#endif - /* - * Allocate enough "hardware scbs" to handle - * the maximum number of concurrent transactions - * we can have active. We have to use contigmalloc - * if this array crosses a page boundary since the - * sequencer depends on this array being physically - * contiguous. - */ - if (ahc->scb_data->hscbs == NULL) { - size_t array_size; - u_int32_t hscb_physaddr; - - array_size = ahc->scb_data->maxscbs*sizeof(struct hardware_scb); - if (array_size > PAGE_SIZE) { - ahc->scb_data->hscbs = (struct hardware_scb *) - contigmalloc(array_size, M_DEVBUF, - M_NOWAIT, 0ul, 0xffffffff, - PAGE_SIZE, 0x10000); - } else { - ahc->scb_data->hscbs = (struct hardware_scb *) - malloc(array_size, M_DEVBUF, M_NOWAIT); - } - - if (ahc->scb_data->hscbs == NULL) { - printf("%s: unable to allocate hardware SCB array. " - "Failing attach\n", ahc_name(ahc)); - return (-1); - } - /* At least the control byte of each hscb needs to be zeroed */ - bzero(ahc->scb_data->hscbs, array_size); - - /* Tell the sequencer where it can find the hscb array. */ - hscb_physaddr = vtophys(ahc->scb_data->hscbs); - ahc_outb(ahc, HSCB_ADDR, hscb_physaddr & 0xFF); - ahc_outb(ahc, HSCB_ADDR + 1, (hscb_physaddr >> 8)& 0xFF); - ahc_outb(ahc, HSCB_ADDR + 2, (hscb_physaddr >> 16)& 0xFF); - ahc_outb(ahc, HSCB_ADDR + 3, (hscb_physaddr >> 24)& 0xFF); - } - - /* - * Q-Full-Count. Some cards have more Q space - * then SCBs. - */ - if (ahc->type & AHC_AIC7770) { - ahc->qfullcount = 4; - ahc->qcntmask = 0x07; - } else if (ahc->type & AHC_AIC7850) { - ahc->qfullcount = 8; - ahc->qcntmask = 0x0f; - } else if (ahc->scb_data->maxhscbs == 255) { - /* 7870/7880 with external SRAM */ - ahc->qfullcount = 255; - ahc->qcntmask = 0xff; - } else { - /* 7870/7880 */ - ahc->qfullcount = 16; - ahc->qcntmask = 0x1f; - } - - ahc_outb(ahc, CMDOUTCNT, 0); - - /* We don't have any waiting selections */ - ahc_outb(ahc, WAITING_SCBH, SCB_LIST_NULL); - - /* Our disconnection list is empty too */ - ahc_outb(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL); - - /* Message out buffer starts empty */ - ahc_outb(ahc, MSG_LEN, 0x00); - - /* - * Load the Sequencer program and Enable the adapter - * in "fast" mode. - */ - if (bootverbose) - printf("%s: Downloading Sequencer Program...", - ahc_name(ahc)); - - ahc_loadseq(ahc); - - if (bootverbose) - printf("Done\n"); - - unpause_sequencer(ahc, /*unpause_always*/TRUE); - - /* - * Note that we are going and return (to probe) - */ - ahc->flags |= AHC_INIT; - return (0); -} - -static void -ahcminphys(bp) - struct buf *bp; -{ -/* - * Even though the card can transfer up to 16megs per command - * we are limited by the number of segments in the dma segment - * list that we can hold. The worst case is that all pages are - * discontinuous physically, hense the "page per segment" limit - * enforced here. - */ - if (bp->b_bcount > ((AHC_NSEG - 1) * PAGE_SIZE)) { - bp->b_bcount = ((AHC_NSEG - 1) * PAGE_SIZE); - } -#if defined(__NetBSD__) - minphys(bp); -#endif -} - -/* - * start a scsi operation given the command and - * the data address, target, and lun all of which - * are stored in the scsi_xfer struct - */ -static int32_t -ahc_scsi_cmd(xs) - struct scsi_xfer *xs; -{ - struct scb *scb; - struct hardware_scb *hscb; - struct ahc_softc *ahc; - u_int16_t mask; - int flags; - int s; - - ahc = (struct ahc_softc *)xs->sc_link->adapter_softc; - mask = (0x01 << (xs->sc_link->target - | (IS_SCSIBUS_B(ahc, xs->sc_link) ? SELBUSB : 0))); - SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahc_scsi_cmd\n")); - flags = xs->flags; - - /* - * get an scb to use. If the transfer - * is from a buf (possibly from interrupt time) - * then we can't allow it to sleep - */ - if ((scb = ahc_get_scb(ahc, flags)) == NULL) { - xs->error = XS_DRIVER_STUFFUP; - return (TRY_AGAIN_LATER); - } - hscb = scb->hscb; - SC_DEBUG(xs->sc_link, SDEV_DB3, ("start scb(%p)\n", scb)); - scb->xs = xs; - - /* - * Put all the arguments for the xfer in the scb - */ - if (ahc->discenable & mask) { - hscb->control |= DISCENB; - if (ahc->tagenable & mask) - hscb->control |= MSG_SIMPLE_Q_TAG; - if (ahc->orderedtag & mask) { - /* XXX this should be handled by the upper SCSI layer */ - printf("Ordered Tag sent\n"); - hscb->control |= MSG_ORDERED_Q_TAG; - ahc->orderedtag &= ~mask; - } - } - - if (flags & SCSI_RESET) { - scb->flags |= SCB_DEVICE_RESET; - hscb->control |= MK_MESSAGE; - } else if ((ahc->needwdtr & mask) && !(ahc->wdtrpending & mask)) { - ahc->wdtrpending |= mask; - hscb->control |= MK_MESSAGE; - scb->flags |= SCB_MSGOUT_WDTR; - } else if((ahc->needsdtr & mask) && !(ahc->sdtrpending & mask)) { - ahc->sdtrpending |= mask; - hscb->control |= MK_MESSAGE; - scb->flags |= SCB_MSGOUT_SDTR; - } - -#if 0 - /* Set the trace flag if this is the target we want to trace */ - if (ahc->unit == 2 && xs->sc_link->target == 3) - hscb->control |= TRACE_SCB; -#endif - - hscb->tcl = ((xs->sc_link->target << 4) & 0xF0) - | (IS_SCSIBUS_B(ahc,xs->sc_link)? SELBUSB : 0) - | (xs->sc_link->lun & 0x07); - hscb->cmdlen = xs->cmdlen; - hscb->cmdpointer = vtophys(xs->cmd); - xs->resid = 0; - xs->status = 0; - - /* Only use S/G if non-zero length */ - if (xs->datalen) { - int seg; - u_int32_t datalen; - vm_offset_t vaddr; - u_int32_t paddr; - u_int32_t nextpaddr; - struct ahc_dma_seg *sg; - - seg = 0; - datalen = xs->datalen; - vaddr = (vm_offset_t)xs->data; - paddr = vtophys(vaddr); - sg = scb->ahc_dma; - hscb->SG_list_pointer = vtophys(sg); - - while ((datalen > 0) && (seg < AHC_NSEG)) { - /* put in the base address and length */ - sg->addr = paddr; - sg->len = 0; - - /* do it at least once */ - nextpaddr = paddr; - - while ((datalen > 0) && (paddr == nextpaddr)) { - u_int32_t size; - /* - * This page is contiguous (physically) - * with the the last, just extend the - * length - */ - /* how far to the end of the page */ - nextpaddr = (paddr & (~PAGE_MASK)) + PAGE_SIZE; - - /* - * Compute the maximum size - */ - size = nextpaddr - paddr; - if (size > datalen) - size = datalen; - - sg->len += size; - vaddr += size; - datalen -= size; - if (datalen > 0) - paddr = vtophys(vaddr); - } - /* - * next page isn't contiguous, finish the seg - */ - seg++; - sg++; - } - hscb->SG_segment_count = seg; - scb->sg_count = hscb->SG_segment_count; - - /* Copy the first SG into the data pointer area */ - hscb->data = scb->ahc_dma->addr; - hscb->datalen = scb->ahc_dma->len | (SCB_LIST_NULL << 24); - if (datalen) { - /* there's still data, must have run out of segs! */ - printf("%s: ahc_scsi_cmd: more than %d DMA segs\n", - ahc_name(ahc), AHC_NSEG); - xs->error = XS_DRIVER_STUFFUP; - ahc_free_scb(ahc, scb); - return (COMPLETE); - } -#ifdef AHC_BROKEN_CACHE - if (ahc_broken_cache) - INVALIDATE_CACHE(); -#endif - } else { - /* - * No data xfer, use non S/G values - */ - hscb->SG_segment_count = 0; - scb->sg_count = hscb->SG_segment_count; - hscb->SG_list_pointer = 0; - hscb->data = 0; - hscb->datalen = (SCB_LIST_NULL << 24); - } - -#ifdef AHC_DEBUG - if((ahc_debug & AHC_SHOWSCBS) && (xs->sc_link->target == DEBUGTARGET)) - ahc_print_scb(scb); -#endif - s = splbio(); - - STAILQ_INSERT_TAIL(&ahc->waiting_scbs, scb, links); - - scb->flags |= SCB_ACTIVE|SCB_WAITINGQ; - - ahc_run_waiting_queue(ahc); - - if ((flags & SCSI_NOMASK) == 0) { - scb->xs->timeout_ch = timeout(ahc_timeout, (caddr_t)scb, - (xs->timeout * hz) / 1000); - splx(s); - return (SUCCESSFULLY_QUEUED); - } - /* - * If we can't use interrupts, poll for completion - */ - SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_poll\n")); - do { - if (ahc_poll(ahc, xs->timeout)) { - if (!(xs->flags & SCSI_SILENT)) - printf("cmd fail\n"); - ahc_timeout(scb); - break; - } - } while ((xs->flags & ITSDONE) == 0); /* a non command complete intr */ - scsi_done(xs); - splx(s); - return (COMPLETE); -} - -/* - * Look for space in the QINFIFO and queue as many SCBs in the waiting - * queue as possible. Assumes that it is called at splbio(). - */ -static void -ahc_run_waiting_queue(ahc) - struct ahc_softc *ahc; -{ - struct scb *scb; - - pause_sequencer(ahc); - - if (ahc->curqincnt >= ahc->qfullcount) { - ahc->curqincnt = ahc_inb(ahc, QINCNT) & ahc->qcntmask; - } - - while ((scb = ahc->waiting_scbs.stqh_first) != NULL - && (ahc->curqincnt < ahc->qfullcount)) { - - STAILQ_REMOVE_HEAD(&ahc->waiting_scbs, links); - scb->flags &= ~SCB_WAITINGQ; - - ahc_outb(ahc, QINFIFO, scb->hscb->tag); - - if ((ahc->flags & AHC_PAGESCBS) != 0) - /* - * We only care about this statistic when paging - * since it is impossible to overflow the qinfifo - * in the non-paging case. - */ - ahc->curqincnt++; - } - unpause_sequencer(ahc, /*Unpause always*/FALSE); -} - -/* - * An scb (and hence an scb entry on the board) is put onto the - * free list. - */ -static void -ahc_free_scb(ahc, scb) - struct ahc_softc *ahc; - struct scb *scb; -{ - struct hardware_scb *hscb; - int opri; - - hscb = scb->hscb; - - opri = splbio(); - - /* Clean up for the next user */ - scb->flags = SCB_FREE; - hscb->control = 0; - hscb->status = 0; - - STAILQ_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links); - if (scb->links.stqe_next == NULL) { - /* - * If there were no SCBs available, wake anybody waiting - * for one to come free. - */ - wakeup((caddr_t)&ahc->scb_data->free_scbs); - } -#ifdef AHC_DEBUG - ahc->activescbs--; -#endif - splx(opri); -} - -/* - * Get a free scb, either one already assigned to a hardware slot - * on the adapter or one that will require an SCB to be paged out before - * use. If there are none, see if we can allocate a new SCB. Otherwise - * either return an error or sleep. - */ -static struct scb * -ahc_get_scb(ahc, flags) - struct ahc_softc *ahc; - u_int32_t flags; -{ - struct scb *scbp; - int opri; - - opri = splbio(); - /* - * If we can and have to, sleep waiting for one to come free - * but only if we can't allocate a new one. - */ - while (1) { - if ((scbp = ahc->scb_data->free_scbs.stqh_first)) { - STAILQ_REMOVE_HEAD(&ahc->scb_data->free_scbs, links); - } else if(ahc->scb_data->numscbs < ahc->scb_data->maxscbs) { - scbp = ahc_alloc_scb(ahc); - if (scbp == NULL) - printf("%s: Can't malloc SCB\n", ahc_name(ahc)); - } else if ((flags & SCSI_NOSLEEP) == 0) { - tsleep((caddr_t)&ahc->scb_data->free_scbs, PRIBIO, - "ahcscb", 0); - continue; - } - break; - } - -#ifdef AHC_DEBUG - if (scbp) { - ahc->activescbs++; - if((ahc_debug & AHC_SHOWSCBCNT) - && (ahc->activescbs == ahc->scb_data->maxhscbs)) - printf("%s: Max SCBs active\n", ahc_name(ahc)); - } -#endif - - splx(opri); - - return (scbp); -} - - -static struct scb * -ahc_alloc_scb(ahc) - struct ahc_softc *ahc; -{ - static struct ahc_dma_seg *next_sg_array = NULL; - static int sg_arrays_free = 0; - struct scb *newscb; - - newscb = (struct scb *) malloc(sizeof(struct scb), M_DEVBUF, M_NOWAIT); - if (newscb != NULL) { - bzero(newscb, sizeof(struct scb)); - if (next_sg_array == NULL) { - size_t alloc_size = sizeof(struct ahc_dma_seg) - * AHC_NSEG; - sg_arrays_free = PAGE_SIZE / alloc_size; - alloc_size *= sg_arrays_free; - if (alloc_size == 0) - panic("%s: SG list doesn't fit in a page", - ahc_name(ahc)); - next_sg_array = (struct ahc_dma_seg *) - malloc(alloc_size, M_DEVBUF, M_NOWAIT); - } - if (next_sg_array != NULL) { - struct hardware_scb *hscb; - - newscb->ahc_dma = next_sg_array; - sg_arrays_free--; - if (sg_arrays_free == 0) - next_sg_array = NULL; - else - next_sg_array = &next_sg_array[AHC_NSEG]; - hscb = &ahc->scb_data->hscbs[ahc->scb_data->numscbs]; - newscb->hscb = hscb; - hscb->control = 0; - hscb->status = 0; - hscb->tag = ahc->scb_data->numscbs; - hscb->residual_data_count[2] = 0; - hscb->residual_data_count[1] = 0; - hscb->residual_data_count[0] = 0; - hscb->residual_SG_segment_count = 0; - ahc->scb_data->numscbs++; - /* - * Place in the scbarray - * Never is removed. - */ - ahc->scb_data->scbarray[hscb->tag] = newscb; - } else { - free(newscb, M_DEVBUF); - newscb = NULL; - } - } - return newscb; -} - -static void -ahc_loadseq(struct ahc_softc *ahc) -{ - int options; - struct patch *cur_patch; - int i; - int downloaded; - u_int8_t download_consts[4]; - - options = 1; /* Code for all options */ - downloaded = 0; - if ((ahc->type & AHC_ULTRA) != 0) - options |= ULTRA; - if ((ahc->type & AHC_TWIN) != 0) - options |= TWIN_CHANNEL; - if (ahc->scb_data->maxscbs > ahc->scb_data->maxhscbs) - options |= SCB_PAGING; - - /* Setup downloadable constant table */ - download_consts[SCBCOUNT] = ahc->scb_data->maxhscbs; - download_consts[COMP_SCBCOUNT] = -ahc->scb_data->maxscbs & 0xFF; - download_consts[FIFODEPTH] = ahc->qfullcount; - download_consts[QCNTMASK] = ahc->qcntmask; - - cur_patch = patches; - ahc_outb(ahc, SEQCTL, PERRORDIS|LOADRAM); - ahc_outb(ahc, SEQADDR0, 0); - ahc_outb(ahc, SEQADDR1, 0); - - for(i = 0; i < sizeof(seqprog)/4; i++) { - cur_patch = ahc_next_patch(cur_patch, options, i); - - if (cur_patch && cur_patch->begin <= i && cur_patch->end > i) - /* Skip this instruction for this configuration */ - continue; - ahc_download_instr(ahc, options, i, download_consts); - downloaded++; - } - - ahc_outb(ahc, SEQCTL, FASTMODE); - ahc_outb(ahc, SEQADDR0, 0); - ahc_outb(ahc, SEQADDR1, 0); - if (bootverbose) - printf("%s: %d instructions downloaded\n", ahc_name(ahc), - downloaded); -} - -static struct patch * -ahc_next_patch(cur_patch, options, instrptr) - struct patch *cur_patch; - int options; - int instrptr; -{ - while(cur_patch != NULL) { - if (((cur_patch->options & options) != 0 - && cur_patch->negative == FALSE) - || ((cur_patch->options & options) == 0 - && cur_patch->negative == TRUE) - || (instrptr >= cur_patch->end)) { - /* - * Either we want to keep this section of code, - * or we have consumed this patch. Skip to the - * next patch. - */ - cur_patch++; - if (cur_patch->options == 0) - /* Out of patches */ - cur_patch = NULL; - } else - /* Found an okay patch */ - break; - } - return (cur_patch); -} - -static void -ahc_download_instr(struct ahc_softc *ahc, int options, - int instrptr, u_int8_t *dconsts) -{ - u_int8_t opcode; - struct ins_format3 instr; - - /* Structure copy */ - instr = *(struct ins_format3 *)&seqprog[instrptr * 4]; - - /* Pull the opcode */ - opcode = (instr.opcode_addr & ~DOWNLOAD_CONST_IMMEDIATE) >> 1; - switch (opcode) { - case AIC_OP_JMP: - case AIC_OP_JC: - case AIC_OP_JNC: - case AIC_OP_CALL: - case AIC_OP_JNE: - case AIC_OP_JNZ: - case AIC_OP_JE: - case AIC_OP_JZ: - { - int address_offset; - u_int address; - struct patch *patch; - int i; - - address_offset = 0; - address = instr.address; - address |= (instr.opcode_addr & ADDR_HIGH_BIT) << 8; - for (i = 0; i < sizeof(patches)/sizeof(patches[0]); i++) { - patch = &patches[i]; - if (((patch->options & options) == 0 - && patch->negative == FALSE) - || ((patch->options & options) != 0 - && patch->negative == TRUE)) { - if (address >= patch->end) - address_offset += - patch->end - patch->begin; - } - } - address -= address_offset; - instr.address = address & 0xFF; - instr.opcode_addr &= ~ADDR_HIGH_BIT; - instr.opcode_addr |= (address >> 8) & ADDR_HIGH_BIT; - /* FALLTHROUGH */ - } - case AIC_OP_OR: - case AIC_OP_AND: - case AIC_OP_XOR: - case AIC_OP_ADD: - case AIC_OP_ADC: - if ((instr.opcode_addr & DOWNLOAD_CONST_IMMEDIATE) != 0) { - instr.immediate = dconsts[instr.immediate]; - } - instr.opcode_addr &= ~DOWNLOAD_CONST_IMMEDIATE; - /* FALLTHROUGH */ - case AIC_OP_ROL: - ahc_outsb(ahc, SEQRAM, &instr.immediate, 4); - break; - default: - panic("Unknown opcode encountered in seq program"); - break; - } -} - -/* - * Function to poll for command completion when - * interrupts are disabled (crash dumps) - */ -static int -ahc_poll(ahc, wait) - struct ahc_softc *ahc; - int wait; /* in msec */ -{ - while (--wait) { - DELAY(1000); - if (ahc_inb(ahc, INTSTAT) & INT_PEND) - break; - } if (wait == 0) { - printf("%s: board is not responding\n", ahc_name(ahc)); - return (EIO); - } - ahc_intr((void *)ahc); - return (0); -} - -static void -ahc_timeout(arg) - void *arg; -{ - struct scb *scb = (struct scb *)arg; - struct ahc_softc *ahc; - int s, found; - u_int8_t bus_state; - char channel; - - ahc = (struct ahc_softc *)scb->xs->sc_link->adapter_softc; - - s = splbio(); - - /* - * Ensure that the card doesn't do anything - * behind our back. Also make sure that we - * didn't "just" miss an interrupt that would - * affect this timeout. - */ - do { - ahc_intr(ahc); - pause_sequencer(ahc); - } while (ahc_inb(ahc, INTSTAT) & INT_PEND); - - if (!(scb->flags & SCB_ACTIVE)) { - /* Previous timeout took care of me already */ - printf("Timedout SCB handled by another timeout\n"); - unpause_sequencer(ahc, /*unpause_always*/TRUE); - splx(s); - return; - } - - if (ahc->in_timeout) { - /* - * Some other SCB has started a recovery operation - * and is still working on cleaning things up. - */ - if ((scb->flags & SCB_RECOVERY_SCB) == 0) { - /* - * This is not the SCB that started this timeout - * processing. Give this scb another lifetime so - * that it can continue once we deal with the - * timeout. - */ - scb->flags |= SCB_TIMEDOUT; - sc_print_addr(scb->xs->sc_link); - printf("SCB 0x%x timedout while recovery in progress\n", - scb->hscb->tag); - scb->xs->timeout_ch = - timeout(ahc_timeout, (caddr_t)scb, - (scb->xs->timeout * hz) / 1000); - unpause_sequencer(ahc, /*unpause_always*/TRUE); - splx(s); - return; - } - } - ahc->in_timeout = TRUE; - - sc_print_addr(scb->xs->sc_link); - printf("SCB 0x%x - timed out ", scb->hscb->tag); - /* - * Take a snapshot of the bus state and print out - * some information so we can track down driver bugs. - */ - bus_state = ahc_inb(ahc, LASTPHASE); - - switch(bus_state) - { - case P_DATAOUT: - printf("in dataout phase"); - break; - case P_DATAIN: - printf("in datain phase"); - break; - case P_COMMAND: - printf("in command phase"); - break; - case P_MESGOUT: - printf("in message out phase"); - break; - case P_STATUS: - printf("in status phase"); - break; - case P_MESGIN: - printf("in message in phase"); - break; - case P_BUSFREE: - printf("while idle, LASTPHASE == 0x%x", - bus_state); - break; - default: - /* - * We aren't in a valid phase, so assume we're - * idle. - */ - printf("invalid phase, LASTPHASE == 0x%x", - bus_state); - break; - } - - printf(", SCSISIGI == 0x%x\n", ahc_inb(ahc, SCSISIGI)); - - printf("SEQADDR = 0x%x SCSISEQ = 0x%x SSTAT0 = 0x%x SSTAT1 = 0x%x\n", - ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8), - ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SSTAT0), - ahc_inb(ahc,SSTAT1)); - /* Decide our course of action */ - - channel = (scb->hscb->tcl & SELBUSB) ? 'B': 'A'; - if (scb->flags & SCB_ABORT) { - /* - * Been down this road before. - * Do a full bus reset. - */ -bus_reset: - scb->flags |= SCB_RECOVERY_SCB; - found = ahc_reset_channel(ahc, channel, XS_TIMEOUT, - /*Initiate Reset*/TRUE); - printf("%s: Issued Channel %c Bus Reset. " - "%d SCBs aborted\n", ahc_name(ahc), channel, found); - } else if ((scb->hscb->control & TAG_ENB) != 0 - && (scb->flags & SCB_SENTORDEREDTAG) == 0) { - /* - * We could be starving this command - * try sending an ordered tag command - * to the target we come from. - */ - u_int16_t mask; - - mask = (0x01 << (scb->xs->sc_link->target - | (IS_SCSIBUS_B(ahc, scb->xs->sc_link) ? - SELBUSB : 0))); - scb->flags |= SCB_SENTORDEREDTAG|SCB_RECOVERY_SCB; - ahc->orderedtag |= mask; - scb->xs->timeout_ch = timeout(ahc_timeout, (caddr_t)scb, - (5 * hz)); - unpause_sequencer(ahc, /*unpause_always*/TRUE); - printf("Ordered Tag queued\n"); - } else { - /* - * Send an Abort Message: - * The target that is holding up the bus may not - * be the same as the one that triggered this timeout - * (different commands have different timeout lengths). - * Our strategy here is to queue an abort message - * to the timed out target if it is disconnected. - * Otherwise, if we have an active target we stuff the - * message buffer with an abort message and assert ATN - * in the hopes that the target will let go of the bus - * and go to the mesgout phase. If this fails, we'll - * get another timeout 2 seconds later which will attempt - * a bus reset. - */ - u_int8_t saved_scbptr; - u_int8_t active_scb_index; - struct scb *active_scb; - - saved_scbptr = ahc_inb(ahc, SCBPTR); - active_scb_index = ahc_inb(ahc, SCB_TAG); - active_scb = ahc->scb_data->scbarray[active_scb_index]; - - if (bus_state != P_BUSFREE) { - if (active_scb_index >= ahc->scb_data->numscbs) { - /* Go "immediatly" to the bus reset */ - /* - * XXX queue an abort for the timedout SCB - * instead. - */ - sc_print_addr(scb->xs->sc_link); - printf("SCB %d: Yucky Immediate reset. " - "Flags = 0x%x\n", scb->hscb->tag, - scb->flags); - goto bus_reset; - } - /* Send the abort to the active SCB */ - ahc_outb(ahc, MSG_LEN, 1); - ahc_outb(ahc, MSG_OUT, - (active_scb->hscb->control & TAG_ENB) == 0 ? - MSG_ABORT : MSG_ABORT_TAG); - ahc_outb(ahc, SCSISIGO, bus_state|ATNO); - sc_print_addr(active_scb->xs->sc_link); - printf("abort message in message buffer\n"); - active_scb->flags |= SCB_ABORT|SCB_RECOVERY_SCB; - if (active_scb != scb) { - untimeout(ahc_timeout, - (caddr_t)active_scb, - active_scb->xs->timeout_ch); - /* Give scb a new lease on life */ - scb->xs->timeout_ch = - timeout(ahc_timeout, (caddr_t)scb, - (scb->xs->timeout * hz) / 1000); - } - active_scb->xs->timeout_ch = - timeout(ahc_timeout, active_scb, 2 * hz); - unpause_sequencer(ahc, /*unpause_always*/TRUE); - } else { - int disconnected; - u_int8_t hscb_index; - u_int8_t linked_next; - - disconnected = FALSE; - hscb_index = ahc_find_scb(ahc, scb); - if (hscb_index == SCB_LIST_NULL) { - disconnected = TRUE; - linked_next = (scb->hscb->datalen >> 24) - & 0xFF; - } else { - ahc_outb(ahc, SCBPTR, hscb_index); - if (ahc_inb(ahc, SCB_CONTROL) & DISCONNECTED) - disconnected = TRUE; - linked_next = ahc_inb(ahc, SCB_LINKED_NEXT); - } - - if (disconnected) { - /* - * Simply set the ABORT_SCB control bit - * and preserve the linked next pointer - */ - scb->hscb->control |= ABORT_SCB|MK_MESSAGE; - scb->hscb->datalen &= ~0xFF000000; - scb->hscb->datalen |= linked_next << 24; - if ((ahc->flags & AHC_PAGESCBS) == 0) - scb->hscb->control &= ~DISCONNECTED; - scb->flags |= SCB_QUEUED_ABORT - | SCB_ABORT|SCB_RECOVERY_SCB; - if (hscb_index != SCB_LIST_NULL) { - u_int8_t scb_control; - - scb_control = ahc_inb(ahc, SCB_CONTROL); - ahc_outb(ahc, SCB_CONTROL, - scb_control | MK_MESSAGE - | ABORT_SCB); - } - /* - * Actually re-queue this SCB in case we can - * select the device before it reconnects. If - * the transaction we want to abort is not - * tagged, unbusy it first so that we don't - * get held back from sending the command. - */ - if ((scb->hscb->control & TAG_ENB) == 0) { - int target; - int lun; - - target = scb->xs->sc_link->target; - lun = scb->xs->sc_link->lun; - ahc_search_qinfifo(ahc, target, - channel, - lun, - SCB_LIST_NULL, - 0, 0, - /*requeue*/TRUE); - } - sc_print_addr(scb->xs->sc_link); - printf("Queueing an Abort SCB\n"); - STAILQ_INSERT_HEAD(&ahc->waiting_scbs, scb, - links); - scb->flags |= SCB_WAITINGQ; - scb->xs->timeout_ch = - timeout(ahc_timeout, (caddr_t)scb, - (2000 * hz) / 1000); - ahc_outb(ahc, SCBPTR, saved_scbptr); - /* - * ahc_run_waiting_queue may unpause us - * so do this last. - */ - ahc_run_waiting_queue(ahc); - /* - * If we are using AAP, ahc_run_waiting_queue - * will not unpause us, so ensure we are - * unpaused. - */ - unpause_sequencer(ahc, /*unpause_always*/FALSE); - } else { - /* Go "immediatly" to the bus reset */ - sc_print_addr(scb->xs->sc_link); - printf("SCB %d: Immediate reset. " - "Flags = 0x%x\n", scb->hscb->tag, - scb->flags); - goto bus_reset; - } - } - } - splx(s); -} - -/* - * Look through the SCB array of the card and attempt to find the - * hardware SCB that corresponds to the passed in SCB. Return - * SCB_LIST_NULL if unsuccessful. This routine assumes that the - * card is already paused. - */ -static u_int8_t -ahc_find_scb(ahc, scb) - struct ahc_softc *ahc; - struct scb *scb; -{ - u_int8_t saved_scbptr; - u_int8_t curindex; - - saved_scbptr = ahc_inb(ahc, SCBPTR); - for (curindex = 0; curindex < ahc->scb_data->maxhscbs; curindex++) { - ahc_outb(ahc, SCBPTR, curindex); - if (ahc_inb(ahc, SCB_TAG) == scb->hscb->tag) - break; - } - ahc_outb(ahc, SCBPTR, saved_scbptr); - if (curindex >= ahc->scb_data->maxhscbs) - curindex = SCB_LIST_NULL; - - return curindex; -} - -static int -ahc_search_qinfifo(ahc, target, channel, lun, tag, flags, xs_error, requeue) - struct ahc_softc *ahc; - int target; - char channel; - int lun; - u_int8_t tag; - u_int32_t flags; - u_int32_t xs_error; - int requeue; -{ - u_int8_t saved_queue[AHC_SCB_MAX]; - int queued = ahc_inb(ahc, QINCNT) & ahc->qcntmask; - int i; - int found; - struct scb *scbp; - STAILQ_HEAD(, scb) removed_scbs; - - found = 0; - STAILQ_INIT(&removed_scbs); - for (i = 0; i < (queued - found); i++) { - saved_queue[i] = ahc_inb(ahc, QINFIFO); - scbp = ahc->scb_data->scbarray[saved_queue[i]]; - if (ahc_match_scb(scbp, target, channel, lun, tag)) { - /* - * We found an scb that needs to be removed. - */ - if (requeue) { - STAILQ_INSERT_HEAD(&removed_scbs, scbp, links); - } else { - scbp->flags |= flags; - scbp->flags &= ~SCB_ACTIVE; - scbp->xs->error = xs_error; - } - i--; - found++; - } - } - /* Now put the saved scbs back. */ - for (queued = 0; queued < i; queued++) - ahc_outb(ahc, QINFIFO, saved_queue[queued]); - - if (requeue) { - while ((scbp = removed_scbs.stqh_first) != NULL) { - STAILQ_REMOVE_HEAD(&removed_scbs, links); - STAILQ_INSERT_HEAD(&ahc->waiting_scbs, scbp, links); - scbp->flags |= SCB_WAITINGQ; - } - } - - return found; -} - - -/* - * The device at the given target/channel has been reset. Abort - * all active and queued scbs for that target/channel. - */ -static int -ahc_reset_device(ahc, target, channel, lun, tag, xs_error) - struct ahc_softc *ahc; - int target; - char channel; - int lun; - u_int8_t tag; - u_int32_t xs_error; -{ - struct scb *scbp; - u_int8_t active_scb; - int i; - int found; - - /* restore this when we're done */ - active_scb = ahc_inb(ahc, SCBPTR); - - /* - * Deal with the busy target and linked next issues. - */ - { - int min_target, max_target; - u_int8_t busy_scbid; - - /* Make all targets 'relative' to bus A */ - if (target == ALL_TARGETS) { - switch (channel) { - case 'A': - min_target = 0; - max_target = ahc->type & AHC_WIDE ? 15 : 7; - break; - case 'B': - min_target = 8; - max_target = 15; - break; - case ALL_CHANNELS: - min_target = 0; - max_target = ahc->type & (AHC_WIDE|AHC_TWIN) - ? 15 : 7; - break; - default: - /* Shutup warning */ - min_target = 0; - max_target = 0; - panic("ahc_reset_device: Bogus Channel"); - /* NOTREACHED */ - } - } else { - min_target = max_target - = target + (channel == 'B' ? 8 : 0); - } - - for (i = min_target; i <= max_target; i++) { - busy_scbid = ahc_index_busy_target(ahc, i, 'A', - /*unbusy*/FALSE); - if (busy_scbid < ahc->scb_data->numscbs) { - struct scb *busy_scb; - struct scb *next_scb; - u_int8_t next_scbid; - - busy_scb = ahc->scb_data->scbarray[busy_scbid]; - - next_scbid = busy_scb->hscb->datalen >> 24; - - if (next_scbid == SCB_LIST_NULL) { - busy_scbid = ahc_find_scb(ahc, - busy_scb); - - if (busy_scbid != SCB_LIST_NULL) { - ahc_outb(ahc, SCBPTR, - busy_scbid); - next_scbid = ahc_inb(ahc, - SCB_LINKED_NEXT); - } - } - - if (ahc_match_scb(busy_scb, target, channel, - lun, tag)) { - ahc_index_busy_target(ahc, i, 'A', - /*unbusy*/TRUE); - } - - if (next_scbid != SCB_LIST_NULL) { - next_scb = ahc->scb_data->scbarray[next_scbid]; - if (ahc_match_scb(next_scb, target, - channel, lun, tag)) - continue; - /* Requeue for later processing */ - STAILQ_INSERT_HEAD(&ahc->waiting_scbs, - next_scb, links); - next_scb->flags |= SCB_WAITINGQ; - } - } - } - } - /* - * Remove any entries from the Queue-In FIFO. - */ - found = ahc_search_qinfifo(ahc, target, channel, lun, tag, - SCB_ABORTED|SCB_QUEUED_FOR_DONE, xs_error, - /*requeue*/FALSE); - - /* - * Search waiting for selection list. - */ - { - u_int8_t next, prev; - - next = ahc_inb(ahc, WAITING_SCBH); /* Start at head of list. */ - prev = SCB_LIST_NULL; - - while (next != SCB_LIST_NULL) { - u_int8_t scb_index; - - ahc_outb(ahc, SCBPTR, next); - scb_index = ahc_inb(ahc, SCB_TAG); - if (scb_index >= ahc->scb_data->numscbs) { - panic("Waiting List inconsistency. " - "SCB index == %d, yet numscbs == %d.", - scb_index, ahc->scb_data->numscbs); - } - scbp = ahc->scb_data->scbarray[scb_index]; - if (ahc_match_scb(scbp, target, channel, lun, tag)) { - u_int8_t linked_next; - - next = ahc_abort_wscb(ahc, scbp, next, prev, - xs_error); - linked_next = ahc_inb(ahc, SCB_LINKED_NEXT); - if (linked_next != SCB_LIST_NULL) { - struct scb *next_scb; - - /* - * Re-queue the waiting SCB via the - * waiting list. - */ - next_scb = - ahc->scb_data->scbarray[linked_next]; - if (!ahc_match_scb(next_scb, target, - channel, lun, tag)) { - STAILQ_INSERT_HEAD(&ahc->waiting_scbs, - next_scb, - links); - next_scb->flags |= SCB_WAITINGQ; - } - } - found++; - } else { - prev = next; - next = ahc_inb(ahc, SCB_NEXT); - } - } - } - /* - * Go through the disconnected list and remove any entries we - * have queued for completion, 0'ing their control byte too. - */ - { - u_int8_t next, prev; - - next = ahc_inb(ahc, DISCONNECTED_SCBH); - prev = SCB_LIST_NULL; - - while (next != SCB_LIST_NULL) { - u_int8_t scb_index; - - ahc_outb(ahc, SCBPTR, next); - scb_index = ahc_inb(ahc, SCB_TAG); - if (scb_index >= ahc->scb_data->numscbs) { - panic("Disconnected List inconsistency. " - "SCB index == %d, yet numscbs == %d.", - scb_index, ahc->scb_data->numscbs); - } - scbp = ahc->scb_data->scbarray[scb_index]; - if (ahc_match_scb(scbp, target, channel, lun, tag)) { - next = ahc_rem_scb_from_disc_list(ahc, next); - } else { - prev = next; - next = ahc_inb(ahc, SCB_NEXT); - } - } - } - /* - * Go through the hardware SCB array looking for commands that - * were active but not on any list. - */ - for(i = 0; i < ahc->scb_data->maxhscbs; i++) { - u_int8_t scbid; - - ahc_outb(ahc, SCBPTR, i); - scbid = ahc_inb(ahc, SCB_TAG); - if (scbid < ahc->scb_data->numscbs) { - scbp = ahc->scb_data->scbarray[scbid]; - if (ahc_match_scb(scbp, target, channel, lun, tag)) { - ahc_add_curscb_to_free_list(ahc); - } - } - } - /* - * Go through the entire SCB array now and look for - * commands for this target that are still active. These - * are other tagged commands that were disconnected when - * the reset occured or untagged commands that were linked - * to the command that preceeded it. - */ - for (i = 0; i < ahc->scb_data->numscbs; i++) { - scbp = ahc->scb_data->scbarray[i]; - if ((scbp->flags & SCB_ACTIVE) != 0 - && ahc_match_scb(scbp, target, channel, lun, tag)) { - scbp->flags |= SCB_ABORTED|SCB_QUEUED_FOR_DONE; - scbp->flags &= ~SCB_ACTIVE; - scbp->xs->error = xs_error; - found++; - - if ((scbp->flags & SCB_WAITINGQ) != 0) { - STAILQ_REMOVE(&ahc->waiting_scbs, scbp, scb, - links); - scbp->flags &= ~SCB_WAITINGQ; - } - } - } - ahc_outb(ahc, SCBPTR, active_scb); - return found; -} - -static u_int8_t -ahc_rem_scb_from_disc_list(ahc, scbptr) - struct ahc_softc *ahc; - u_int8_t scbptr; -{ - u_int8_t next; - u_int8_t prev; - - ahc_outb(ahc, SCBPTR, scbptr); - next = ahc_inb(ahc, SCB_NEXT); - prev = ahc_inb(ahc, SCB_PREV); - - ahc_outb(ahc, SCB_CONTROL, 0); - - ahc_add_curscb_to_free_list(ahc); - - if (prev != SCB_LIST_NULL) { - ahc_outb(ahc, SCBPTR, prev); - ahc_outb(ahc, SCB_NEXT, next); - } else - ahc_outb(ahc, DISCONNECTED_SCBH, next); - - if (next != SCB_LIST_NULL) { - ahc_outb(ahc, SCBPTR, next); - ahc_outb(ahc, SCB_PREV, prev); - } - return next; -} - -static void -ahc_add_curscb_to_free_list(ahc) - struct ahc_softc *ahc; -{ - /* Invalidate the tag so that ahc_find_scb doesn't think it's active */ - ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL); - - ahc_outb(ahc, SCB_NEXT, ahc_inb(ahc, FREE_SCBH)); - ahc_outb(ahc, FREE_SCBH, ahc_inb(ahc, SCBPTR)); -} - -/* - * Manipulate the waiting for selection list and return the - * scb that follows the one that we remove. - */ -static u_char -ahc_abort_wscb (ahc, scbp, scbpos, prev, xs_error) - struct ahc_softc *ahc; - struct scb *scbp; - u_int8_t scbpos; - u_int8_t prev; - u_int32_t xs_error; -{ - u_int8_t curscb, next; - /* - * Select the SCB we want to abort and - * pull the next pointer out of it. - */ - curscb = ahc_inb(ahc, SCBPTR); - ahc_outb(ahc, SCBPTR, scbpos); - next = ahc_inb(ahc, SCB_NEXT); - - /* Clear the necessary fields */ - ahc_outb(ahc, SCB_CONTROL, 0); - - ahc_add_curscb_to_free_list(ahc); - - /* update the waiting list */ - if (prev == SCB_LIST_NULL) - /* First in the list */ - ahc_outb(ahc, WAITING_SCBH, next); - else { - /* - * Select the scb that pointed to us - * and update its next pointer. - */ - ahc_outb(ahc, SCBPTR, prev); - ahc_outb(ahc, SCB_NEXT, next); - } - - /* - * Point us back at the original scb position - * and inform the SCSI system that the command - * has been aborted. - */ - ahc_outb(ahc, SCBPTR, curscb); - scbp->flags |= SCB_ABORTED|SCB_QUEUED_FOR_DONE; - scbp->flags &= ~SCB_ACTIVE; - scbp->xs->error = xs_error; - return next; -} - -static u_int8_t -ahc_index_busy_target(ahc, target, channel, unbusy) - struct ahc_softc *ahc; - int target; - char channel; - int unbusy; -{ - u_int8_t active_scb; - u_int8_t info_scb; - u_int8_t busy_scbid; - u_int32_t scb_offset; - - info_scb = target / 4; - if (channel == 'B') - info_scb += 2; - active_scb = ahc_inb(ahc, SCBPTR); - ahc_outb(ahc, SCBPTR, info_scb); - scb_offset = SCB_BUSYTARGETS + (target & 0x03); - busy_scbid = ahc_inb(ahc, scb_offset); - if (unbusy) - ahc_outb(ahc, scb_offset, SCB_LIST_NULL); - ahc_outb(ahc, SCBPTR, active_scb); - return busy_scbid; -} - -static void -ahc_busy_target(ahc, target, channel, scbid) - struct ahc_softc *ahc; - int target; - char channel; - u_int8_t scbid; -{ - u_int8_t active_scb; - u_int8_t info_scb; - u_int32_t scb_offset; - - info_scb = target / 4; - if (channel == 'B') - info_scb += 2; - active_scb = ahc_inb(ahc, SCBPTR); - ahc_outb(ahc, SCBPTR, info_scb); - scb_offset = SCB_BUSYTARGETS + (target & 0x03); - ahc_outb(ahc, scb_offset, scbid); - ahc_outb(ahc, SCBPTR, active_scb); - return; -} - -static void -ahc_clear_intstat(ahc) - struct ahc_softc *ahc; -{ - /* Clear any interrupt conditions this may have caused */ - ahc_outb(ahc, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO); - ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI - |CLRBUSFREE|CLRSCSIPERR|CLRPHASECHG| - CLRREQINIT); - ahc_outb(ahc, CLRINT, CLRSCSIINT); -} - -static void -ahc_reset_current_bus(ahc) - struct ahc_softc *ahc; -{ - u_int8_t scsiseq; - - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENSCSIRST); - scsiseq = ahc_inb(ahc, SCSISEQ); - ahc_outb(ahc, SCSISEQ, scsiseq | SCSIRSTO); - - DELAY(AHC_BUSRESET_DELAY); - /* Turn off the bus reset */ - ahc_outb(ahc, SCSISEQ, scsiseq & ~SCSIRSTO); - - ahc_clear_intstat(ahc); - - /* Re-enable reset interrupts */ - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) | ENSCSIRST); -} - -static int -ahc_reset_channel(ahc, channel, xs_error, initiate_reset) - struct ahc_softc *ahc; - char channel; - u_int32_t xs_error; - int initiate_reset; -{ - u_int32_t offset, offset_max; - int found; - u_int8_t sblkctl; - char cur_channel; - - pause_sequencer(ahc); - /* - * Clean up all the state information for the - * pending transactions on this bus. - */ - found = ahc_reset_device(ahc, ALL_TARGETS, channel, ALL_LUNS, - SCB_LIST_NULL, xs_error); - if (channel == 'B') { - ahc->needsdtr |= (ahc->needsdtr_orig & 0xff00); - ahc->sdtrpending &= 0x00ff; - ahc->orderedtag &= 0x00ff; - offset = TARG_SCRATCH + 8; - offset_max = TARG_SCRATCH + 16; - } else if (ahc->type & AHC_WIDE){ - ahc->needsdtr = ahc->needsdtr_orig; - ahc->needwdtr = ahc->needwdtr_orig; - ahc->orderedtag = 0; - ahc->sdtrpending = 0; - ahc->wdtrpending = 0; - offset = TARG_SCRATCH; - offset_max = TARG_SCRATCH + 16; - } else { - ahc->needsdtr |= (ahc->needsdtr_orig & 0x00ff); - ahc->sdtrpending &= 0xff00; - ahc->orderedtag &= 0xff00; - offset = TARG_SCRATCH; - offset_max = TARG_SCRATCH + 8; - } - - for (; offset < offset_max; offset++) { - /* - * Revert to async/narrow transfers - * until we renegotiate. - */ - u_int8_t targ_scratch; - - targ_scratch = ahc_inb(ahc, offset); - targ_scratch &= SXFR; - ahc_outb(ahc, offset, targ_scratch); - } - - /* - * Reset the bus if we are initiating this reset and - * restart/unpause the sequencer - */ - sblkctl = ahc_inb(ahc, SBLKCTL); - cur_channel = (sblkctl & SELBUSB) ? 'B' : 'A'; - if (cur_channel != channel) { - /* Case 1: Command for another bus is active - * Stealthily reset the other bus without - * upsetting the current bus. - */ - ahc_outb(ahc, SBLKCTL, sblkctl ^ SELBUSB); - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); - if (initiate_reset) - ahc_reset_current_bus(ahc); - ahc_outb(ahc, SCSISEQ, 0); - ahc_clear_intstat(ahc); - ahc_outb(ahc, SBLKCTL, sblkctl); - unpause_sequencer(ahc, /*unpause_always*/FALSE); - } else { - /* Case 2: A command from this bus is active or we're idle */ - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); - if (initiate_reset) - ahc_reset_current_bus(ahc); - ahc_outb(ahc, SCSISEQ, 0); - ahc_clear_intstat(ahc); - restart_sequencer(ahc); - } - /* - * Untimeout our scbs now in case we have to delay our done - * processing. - */ - ahc_untimeout_done_queue(ahc); - ahc_run_done_queue(ahc); - return found; -} - -static void -ahc_run_done_queue(ahc) - struct ahc_softc *ahc; -{ - int i; - struct scb *scbp; - - for (i = 0; i < ahc->scb_data->numscbs; i++) { - scbp = ahc->scb_data->scbarray[i]; - if (scbp->flags & SCB_QUEUED_FOR_DONE) - ahc_done(ahc, scbp); - } -} - -static void -ahc_untimeout_done_queue(ahc) - struct ahc_softc *ahc; -{ - int i; - struct scb *scbp; - - for (i = 0; i < ahc->scb_data->numscbs; i++) { - scbp = ahc->scb_data->scbarray[i]; - if (scbp->flags & SCB_QUEUED_FOR_DONE) - untimeout(ahc_timeout, (caddr_t)scbp, - scbp->xs->timeout_ch); - } -} - -static int -ahc_match_scb (scb, target, channel, lun, tag) - struct scb *scb; - int target; - char channel; - int lun; - u_int8_t tag; -{ - int targ = (scb->hscb->tcl >> 4) & 0x0f; - char chan = (scb->hscb->tcl & SELBUSB) ? 'B' : 'A'; - int slun = scb->hscb->tcl & 0x07; - int match; - - match = ((chan == channel) || (channel == ALL_CHANNELS)); - if (match != 0) - match = ((targ == target) || (target == ALL_TARGETS)); - if (match != 0) - match = ((lun == slun) || (lun == ALL_LUNS)); - if (match != 0) - match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL)); - - return match; -} - -static void -ahc_construct_sdtr(ahc, start_byte, period, offset) - struct ahc_softc *ahc; - int start_byte; - u_int8_t period; - u_int8_t offset; -{ - ahc_outb(ahc, MSG_OUT + start_byte, MSG_EXTENDED); - ahc_outb(ahc, MSG_OUT + 1 + start_byte, MSG_EXT_SDTR_LEN); - ahc_outb(ahc, MSG_OUT + 2 + start_byte, MSG_EXT_SDTR); - ahc_outb(ahc, MSG_OUT + 3 + start_byte, period); - ahc_outb(ahc, MSG_OUT + 4 + start_byte, offset); - ahc_outb(ahc, MSG_LEN, start_byte + 5); -} - -static void -ahc_construct_wdtr(ahc, start_byte, bus_width) - struct ahc_softc *ahc; - int start_byte; - u_int8_t bus_width; -{ - ahc_outb(ahc, MSG_OUT + start_byte, MSG_EXTENDED); - ahc_outb(ahc, MSG_OUT + 1 + start_byte, MSG_EXT_WDTR_LEN); - ahc_outb(ahc, MSG_OUT + 2 + start_byte, MSG_EXT_WDTR); - ahc_outb(ahc, MSG_OUT + 3 + start_byte, bus_width); - ahc_outb(ahc, MSG_LEN, start_byte + 4); -} - -static void -ahc_calc_residual(scb) - struct scb *scb; -{ - struct scsi_xfer *xs; - struct hardware_scb *hscb; - int resid_sgs; - - xs = scb->xs; - hscb = scb->hscb; - - /* - * If the disconnected flag is still set, this is bogus - * residual information left over from a sequencer - * pagin/pageout, so ignore this case. - */ - if ((scb->hscb->control & DISCONNECTED) == 0 - && (scb->flags & SCB_SENSE) == 0) { - /* - * Remainder of the SG where the transfer - * stopped. - */ - xs->resid = (hscb->residual_data_count[2] <<16) | - (hscb->residual_data_count[1] <<8) | - (hscb->residual_data_count[0]); - - /* - * Add up the contents of all residual - * SG segments that are after the SG where - * the transfer stopped. - */ - resid_sgs = scb->hscb->residual_SG_segment_count - 1; - while (resid_sgs > 0) { - int sg; - - sg = scb->sg_count - resid_sgs; - xs->resid += scb->ahc_dma[sg].len; - resid_sgs--; - } -#if defined(__FreeBSD__) - xs->flags |= SCSI_RESID_VALID; -#elif defined(__NetBSD__) - /* XXX - Update to do this right */ -#endif - } - - /* - * Clean out the residual information in this SCB for its - * next consumer. - */ - hscb->residual_data_count[2] = 0; - hscb->residual_data_count[1] = 0; - hscb->residual_data_count[0] = 0; - hscb->residual_SG_segment_count = 0; - -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWMISC) { - sc_print_addr(xs->sc_link); - printf("Handled Residual of %ld bytes\n" ,xs->resid); - } -#endif -} diff --git a/sys/i386/scsi/aic7xxx.h b/sys/i386/scsi/aic7xxx.h deleted file mode 100644 index 1794cec..0000000 --- a/sys/i386/scsi/aic7xxx.h +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Interface to the generic driver for the aic7xxx based adaptec - * SCSI controllers. This is used to implement product specific - * probe and attach routines. - * - * Copyright (c) 1994-1997 Justin Gibbs. - * 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, - * without modification, immediately at the beginning of the file. - * 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. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. - * - * $Id: aic7xxx.h,v 1.42 1997/08/13 17:02:47 gibbs Exp $ - */ - -#ifndef _AIC7XXX_H_ -#define _AIC7XXX_H_ - -#if defined(__FreeBSD__) -#include "ahc.h" /* for NAHC from config */ -#include "opt_aic7xxx.h" /* for config options */ -#endif - -#if defined(__NetBSD__) -/* - * convert FreeBSD's <sys/queue.h> symbols to NetBSD's - */ -#define STAILQ_ENTRY SIMPLEQ_ENTRY -#define STAILQ_HEAD SIMPLEQ_HEAD -#define STAILQ_INIT SIMPLEQ_INIT -#define STAILQ_INSERT_HEAD SIMPLEQ_INSERT_HEAD -#define STAILQ_INSERT_TAIL SIMPLEQ_INSERT_TAIL -#define STAILQ_REMOVE_HEAD(head, field) \ - SIMPLEQ_REMOVE_HEAD(head, (head)->sqh_first, field) -#define stqh_first sqh_first -#define stqe_next sqe_next -#endif - -#define AHC_NSEG 32 /* The number of dma segments supported. - * AHC_NSEG can be maxed out at 256 entries, - * but the kernel will never need to transfer - * such a large (1MB) request. To reduce the - * driver's memory consumption, we reduce the - * max to 32. 16 would work if all transfers - * are paged alined since the kernel will only - * generate at most a 64k transfer, but to - * handle non-page aligned transfers, you need - * 17, so we round to the next power of two - * to make allocating SG space easy and - * efficient. - */ - -#define AHC_SCB_MAX 255 /* - * Up to 255 SCBs on some types of aic7xxx - * based boards. The aic7870 have 16 internal - * SCBs, but external SRAM bumps this to 255. - * The aic7770 family have only 4, and the - * aic7850 has only 3. - */ - - -typedef u_int32_t physaddr; -#if defined(__FreeBSD__) -extern u_long ahc_unit; -#endif - -struct ahc_dma_seg { - physaddr addr; - u_int32_t len; -}; - -typedef enum { - AHC_NONE = 0x0000, - AHC_ULTRA = 0x0001, /* Supports 20MHz Transfers */ - AHC_WIDE = 0x0002, /* Wide Channel */ - AHC_TWIN = 0x0008, /* Twin Channel */ - AHC_AIC7770 = 0x0010, - AHC_AIC7850 = 0x0020, - AHC_AIC7860 = 0x0021, /* ULTRA version of the aic7850 */ - AHC_AIC7870 = 0x0040, - AHC_AIC7880 = 0x0041, - AHC_AIC78X0 = 0x0060, /* PCI Based Controller */ - AHC_274 = 0x0110, /* EISA Based Controller */ - AHC_284 = 0x0210, /* VL/ISA Based Controller */ - AHC_294AU = 0x0421, /* aic7860 based '2940' */ - AHC_294 = 0x0440, /* PCI Based Controller */ - AHC_294U = 0x0441, /* ULTRA PCI Based Controller */ - AHC_394 = 0x0840, /* Twin Channel PCI Controller */ - AHC_394U = 0x0841, /* ULTRA, Twin Channel PCI Controller */ - AHC_398 = 0x1040, /* Multi Channel PCI RAID Controller */ - AHC_398U = 0x1041, /* ULTRA, Multi Channel PCI - * RAID Controller - */ - AHC_39X = 0x1800 /* Multi Channel PCI Adapter */ -}ahc_type; - -typedef enum { - AHC_FNONE = 0x00, - AHC_INIT = 0x01, - AHC_RUNNING = 0x02, - AHC_PAGESCBS = 0x04, /* Enable SCB paging */ - AHC_CHANNEL_B_PRIMARY = 0x08, /* - * On twin channel adapters, probe - * channel B first since it is the - * primary bus. - */ - AHC_USEDEFAULTS = 0x10, /* - * For cards without an seeprom - * or a BIOS to initialize the chip's - * SRAM, we use the default target - * settings. - */ - AHC_CHNLB = 0x20, /* - * Second controller on 3940/398X - * Also encodes the offset in the - * SEEPROM for CHNLB info (32) - */ - AHC_CHNLC = 0x40 /* - * Third controller on 3985 - * Also encodes the offset in the - * SEEPROM for CHNLC info (64) - */ -} ahc_flag; - -typedef enum { - SCB_FREE = 0x0000, - SCB_ACTIVE = 0x0001, - SCB_ABORTED = 0x0002, - SCB_DEVICE_RESET = 0x0004, - SCB_SENSE = 0x0008, - SCB_TIMEDOUT = 0x0010, - SCB_QUEUED_FOR_DONE = 0x0020, - SCB_RECOVERY_SCB = 0x0040, - SCB_WAITINGQ = 0x0080, - SCB_ASSIGNEDQ = 0x0100, - SCB_SENTORDEREDTAG = 0x0200, - SCB_MSGOUT_SDTR = 0x0400, - SCB_MSGOUT_WDTR = 0x0800, - SCB_ABORT = 0x1000, - SCB_QUEUED_ABORT = 0x2000 -} scb_flag; - -/* - * The driver keeps up to MAX_SCB scb structures per card in memory. The SCB - * consists of a "hardware SCB" mirroring the fields availible on the card - * and additional information the kernel stores for each transaction. - */ -struct hardware_scb { -/*0*/ u_int8_t control; -/*1*/ u_int8_t tcl; /* 4/1/3 bits */ -/*2*/ u_int8_t status; -/*3*/ u_int8_t SG_segment_count; -/*4*/ physaddr SG_list_pointer; -/*8*/ u_int8_t residual_SG_segment_count; -/*9*/ u_int8_t residual_data_count[3]; -/*12*/ physaddr data; -/*16*/ u_int32_t datalen; /* Really only three bits, but its - * faster to treat it as a long on - * a quad boundary. - */ -/*20*/ physaddr cmdpointer; -/*24*/ u_int8_t cmdlen; -/*25*/ u_int8_t tag; /* Index into our kernel SCB array. - * Also used as the tag for tagged I/O - */ -#define SCB_PIO_TRANSFER_SIZE 26 /* amount we need to upload/download - * via PIO to initialize a transaction. - */ -/*26*/ u_int8_t next; /* Used for threading SCBs in the - * "Waiting for Selection" and - * "Disconnected SCB" lists down - * in the sequencer. - */ -/*27*/ u_int8_t prev; - -/*28*/ u_int32_t pad; /* - * Unused by the kernel, but we require - * the padding so that the array of - * hardware SCBs is alligned on 32 byte - * boundaries so the sequencer can - * index them easily. - */ -}; - -struct scb { - struct hardware_scb *hscb; - STAILQ_ENTRY(scb) links; /* for chaining */ - struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ - scb_flag flags; - struct ahc_dma_seg *ahc_dma;/* Pointer to SG segments */ - struct scsi_sense sense_cmd; - u_int8_t sg_count;/* How full ahc_dma_seg is */ - u_int8_t position;/* Position in card's scbarray */ -}; - -struct scb_data { - struct hardware_scb *hscbs; /* Array of hardware SCBs */ - struct scb *scbarray[AHC_SCB_MAX]; /* Array of kernel SCBs */ - STAILQ_HEAD(, scb) free_scbs; /* - * Pool of SCBs ready to be assigned - * commands to execute. - */ - u_int8_t numscbs; - u_int8_t maxhscbs; /* Number of SCBs on the card */ - u_int8_t maxscbs; /* - * Max SCBs we allocate total including - * any that will force us to page SCBs - */ -}; - -struct ahc_busreset_args { - struct ahc_softc *ahc; - char bus; -}; - -struct ahc_softc { -#if defined(__FreeBSD__) - int unit; -#elif defined(__NetBSD__) - struct device sc_dev; - void *sc_ih; - bus_chipset_tag_t sc_bc; - bus_io_handle_t sc_ioh; -#endif - ahc_type type; - ahc_flag flags; -#if defined(__FreeBSD__) - u_int32_t baseport; -#endif - volatile u_int8_t *maddr; - struct scb_data *scb_data; - struct scsi_link sc_link; - struct scsi_link sc_link_b; /* Second bus for Twin channel cards */ - STAILQ_HEAD(, scb) waiting_scbs;/* - * SCBs waiting ready to go but - * waiting for space in the QINFIFO. - */ - STAILQ_HEAD(, scb) cmplete_scbs;/* - * SCBs out of the QOUTFIFO, waiting - * to be ahc_done'd. - */ - u_int8_t activescbs; - u_int8_t cmdoutcnt; - u_int16_t needsdtr_orig; /* Targets we initiate sync neg with */ - u_int16_t needwdtr_orig; /* Targets we initiate wide neg with */ - u_int16_t needsdtr; /* Current list of negotiated targets */ - u_int16_t needwdtr; /* Current list of negotiated targets */ - u_int16_t sdtrpending; /* Pending SDTR to these targets */ - u_int16_t wdtrpending; /* Pending WDTR to these targets */ - u_int16_t tagenable; /* Targets that can handle tags */ - u_int16_t orderedtag; /* Targets to use ordered tag on */ - u_int16_t discenable; /* Targets allowed to disconnect */ - u_int8_t our_id; /* our scsi id */ - u_int8_t our_id_b; /* B channel scsi id */ - u_int8_t qcntmask; /* - * Mask of valid registers in the - * Q*CNT registers. - */ - u_int8_t qfullcount; /* - * The maximum number of entries - * storable in the Q*FIFOs. - */ - u_int8_t curqincnt; /* - * The current value we "think" the - * QINCNT has. The reason it is - * "think" is that this is a cached - * value that is only updated when - * curqincount == qfullcount to reduce - * the amount of accesses made to the - * card. - */ - u_int8_t unpause; - u_int8_t pause; - u_int8_t in_timeout; -}; - -struct full_ahc_softc { - struct ahc_softc softc; - struct scb_data scb_data_storage; -}; - -/* #define AHC_DEBUG */ -#ifdef AHC_DEBUG -/* Different debugging levels used when AHC_DEBUG is defined */ -#define AHC_SHOWMISC 0x0001 -#define AHC_SHOWCMDS 0x0002 -#define AHC_SHOWSCBS 0x0004 -#define AHC_SHOWABORTS 0x0008 -#define AHC_SHOWSENSE 0x0010 -#define AHC_SHOWSCBCNT 0x0020 - -extern int ahc_debug; /* Initialized in i386/scsi/aic7xxx.c */ -#endif - -#if defined(__FreeBSD__) -char *ahc_name __P((struct ahc_softc *ahc)); - -struct ahc_softc *ahc_alloc __P((int unit, u_int32_t io_base, - vm_offset_t maddr, ahc_type type, - ahc_flag flags, struct scb_data *scb_data)); -#elif defined(__NetBSD__) - -#define ahc_name(ahc) (ahc)->sc_dev.dv_xname - -void ahc_construct __P((struct ahc_softc *ahc, bus_chipset_tag_t bc, bus_io_handle_t ioh, ahc_type type, ahc_flag flags)); -#endif -void ahc_reset __P((struct ahc_softc *ahc)); -void ahc_free __P((struct ahc_softc *)); -int ahc_init __P((struct ahc_softc *)); -int ahc_attach __P((struct ahc_softc *)); -#if defined(__FreeBSD__) -void ahc_intr __P((void *arg)); -#elif defined(__NetBSD__) -int ahc_intr __P((void *arg)); -#endif - -#if defined(__FreeBSD__) -static __inline u_int8_t ahc_inb __P((struct ahc_softc *ahc, u_int32_t port)); -static __inline void ahc_outb __P((struct ahc_softc *ahc, u_int32_t port, - u_int8_t val)); -static __inline void ahc_outsb __P((struct ahc_softc *ahc, u_int32_t port, - u_int8_t *valp, size_t size)); - -static __inline u_int8_t -ahc_inb(ahc, port) - struct ahc_softc *ahc; - u_int32_t port; -{ - if (ahc->maddr != NULL) - return ahc->maddr[port]; - else - return inb(ahc->baseport + port); -} - -static __inline void -ahc_outb(ahc, port, val) - struct ahc_softc *ahc; - u_int32_t port; - u_int8_t val; -{ - if (ahc->maddr != NULL) - ahc->maddr[port] = val; - else - outb(ahc->baseport + port, val); -} - -static __inline void -ahc_outsb(ahc, port, valp, size) - struct ahc_softc *ahc; - u_int32_t port; - u_int8_t *valp; - size_t size; -{ - if (ahc->maddr != NULL) { - __asm __volatile(" - cld; - 1: lodsb; - movb %%al,(%0); - loop 1b" : - : - "r" ((ahc)->maddr + (port)), - "S" ((valp)), "c" ((size)) : - "%esi", "%ecx", "%eax"); - } else - outsb(ahc->baseport + port, valp, size); -} -#elif defined(__NetBSD__) -#define ahc_inb(ahc, port) \ - bus_io_read_1((ahc)->sc_bc, (ahc)->sc_ioh, port) -#define ahc_outb(ahc, port, val) \ - bus_io_write_1((ahc)->sc_bc, (ahc)->sc_ioh, port, val) -#define ahc_outsb(ahc, port, valp, size) \ - bus_io_write_multi_1((ahc)->sc_bc, (ahc)->sc_ioh, port, valp, size) -#endif - -#endif /* _AIC7XXX_H_ */ diff --git a/sys/i386/scsi/bt.c b/sys/i386/scsi/bt.c deleted file mode 100644 index d3d0ec0..0000000 --- a/sys/i386/scsi/bt.c +++ /dev/null @@ -1,1583 +0,0 @@ -/* - * 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. - * - * $Id: bt.c,v 1.16 1998/02/20 13:37:37 bde Exp $ - */ - -/* - * Bulogic/Bustek 32 bit Addressing Mode SCSI driver. - * - * NOTE: 1. Some bt5xx card can NOT handle 32 bit addressing mode. - * 2. OLD bt445s Revision A,B,C,D(nowired) + any firmware version - * has broken busmaster for handling 32 bit addressing on H/W bus - * side. - * - * 3. Extended probing still needs confirmation from our user base, due - * to several H/W and firmware dependencies. If you have a problem - * with extended probing, please contact 'amurai@spec.co.jp' - * - * amurai@spec.co.jp 94/6/16 - */ - -#include <sys/param.h> -#include <sys/systm.h> - -#include <sys/malloc.h> -#include <sys/buf.h> -#include <sys/kernel.h> -#include <sys/sysctl.h> - -#include <machine/clock.h> -#include <machine/stdarg.h> - -#include <vm/vm.h> -#include <vm/pmap.h> - -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> - -#include <i386/scsi/btreg.h> - -struct bt_data *btdata[NBT]; - -/* - * I/O Port Interface - */ - -#define BT_BASE bt->bt_base -#define BT_CTRL_STAT_PORT (BT_BASE + 0x0) /* control & status */ -/* ReadOps WriteOps */ -#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 */ -#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 */ -#define BT_STAT_MASK \ - (BT_STST | BT_DIAGF | BT_INIT | BT_IDLE | BT_CDF | BT_DF | BT_INVDCMD) - -#define BT_CMD_DATA_PORT (BT_BASE + 0x1) /* cmds and datas */ -/* ReadOps WriteOps */ -#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 intr */ -#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 FirmWare version #3 */ -#define BT_INQUIRE_REV_FOURTH 0x85 /* Get FirmWare version #4 */ -#define BT_INQUIRE_EXTENDED 0x8D /* Adapter Setup Inquiry */ -/* The following commands appeared at FirmWare 3.31 */ -#define BT_ROUND_ROBIN 0x8f /* Enable/Disable round robin */ -#define BT_STRICT_ROUND_ROBIN 0x00 /* Parameter for strict mode */ -#define BT_AGRES_ROUND_ROBIN 0x01 /* Parameter for back compat */ - -#define BT_INTR_PORT (BT_BASE + 0x2) /* Intr. stat */ -/* ReadOps WriteOps */ -#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 */ - -struct bt_cmd_buf { - u_char byte[16]; -}; - - -#define CCB_HASH_SHIFT 9 /* only hash on multiples of 512 */ -#define CCB_HASH(x) ((((long int)(x))>>CCB_HASH_SHIFT) % CCB_HASH_SIZE) - -#define bt_nextmbx( wmb, mbx, mbio ) \ - if ( (wmb) == &((mbx)->mbio[BT_MBX_SIZE - 1 ]) ) \ - (wmb) = &((mbx)->mbio[0]); \ - else \ - (wmb)++; - -struct bt_boardID { - u_char board_type; - u_char custom_feture; - char firm_revision; - u_char firm_version; -}; - -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]; /* for backwards compatibility */ - 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; -#define BUSDMA 0x00 -#define CHAN0 0x01 -#define CHAN5 0x20 -#define CHAN6 0x40 -#define CHAN7 0x80 - u_char intr; -#define INT9 0x01 -#define INT10 0x02 -#define INT11 0x04 -#define INT12 0x08 -#define INT14 0x20 -#define INT15 0x40 - u_char scsi_dev:3; /* XXX What about Wide Controllers? */ - u_char :5; -}; - - - -/* - * Determine 32bit address/Data firmware functionality from the bus type - * Note: bt742a/747[s|d]/757/946/445s will return 'E' - * bt542b/545s/545d will return 'A' - * 94/05/18 amurai@spec.co.jp - */ -struct bt_ext_info { - u_char bus_type; /* Host adapter bus type */ -#define BT_BUS_TYPE_24bit 'A' /* PC/AT 24 bit address bus type */ -#define BT_BUS_TYPE_32bit 'E' /* EISA/VLB/PCI 32 bit address type */ -#define BT_BUS_TYPE_MCA 'M' /* Micro chanel? */ - u_char bios_addr; /* Bios Address-Not used */ - u_short max_seg; /* Max segment List */ - u_char num_mbx; /* Number of mailbox */ - int32_t mbx_base; /* mailbox base address */ - struct { - u_char resv1:1; /* ??? */ - u_char force:1; /* ON: force sync */ - u_char maxsync:1; /* ON: 10MB/s , OFF: 5MB/s */ - u_char resv2:2; /* ??? */ - u_char sync:1; /* ON: Sync, OFF: async ONLY!! */ - u_char resv3:2; /* ??? */ - } s; - u_char firmid[3]; /* Firmware ver. & rev. w/o last char */ -}; - -#define BT_GET_BOARD_INFO 0x8b /* Get H/W ID and Revision */ -struct bt_board_info { - u_char id[4]; /* i.e bt742a -> '7','4','2','A' */ - u_char ver[2]; /* i.e Board Revision 'H' -> 'H', 0x00 */ -}; - -#define BT_GET_SYNC_VALUE 0x8c /* Get Synchronous Value */ -struct bt_sync_value { - u_char value[8]; /* Synchrnous value (value * 10 nsec) */ -}; - - -#define KVTOPHYS(x) vtophys(x) -#define PAGESIZ 4096 -#define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); } - -/***********debug values *************/ -#define BT_SHOWCCBS 0x01 -#define BT_SHOWINTS 0x02 -#define BT_SHOWCMDS 0x04 -#define BT_SHOWMISC 0x08 -static int bt_debug = 0; -SYSCTL_INT(_debug, OID_AUTO, bt_debug, CTLFLAG_RW, &bt_debug, 0, ""); - -static u_int32_t bt_adapter_info __P((int unit)); -static struct bt_ccb * - bt_ccb_phys_kv __P((struct bt_data *bt, physaddr ccb_phys)); -static int bt_cmd __P((struct bt_data *bt, int icnt, int ocnt, int wait, - u_char *retval, u_char opcode, ...)); -static void bt_done __P((struct bt_data *bt, struct bt_ccb *ccb)); -static void bt_free_ccb __P((struct bt_data *bt, struct bt_ccb *ccb, - int flags)); -static struct bt_ccb * - bt_get_ccb __P((struct bt_data *bt, int flags)); -static void bt_inquire_setup_information __P((struct bt_data *bt, - struct bt_ext_info *info)); -static void btminphys __P((struct buf *bp)); -static int bt_poll __P((struct bt_data *bt, struct scsi_xfer *xs, - struct bt_ccb *ccb)); -#ifdef UTEST -static void bt_print_active_ccbs __P((int unit)); -static void bt_print_ccb __P((struct bt_ccb *ccb)); -#endif -static int32_t bt_scsi_cmd __P((struct scsi_xfer *xs)); -static BT_MBO * bt_send_mbo __P((struct bt_data *bt, int flags, int cmd, - struct bt_ccb *ccb)); -static timeout_t - bt_timeout; - -u_long bt_unit = 0; -static int btprobing = 1; - -/* - * XXX - * Do our own re-probe protection until a configuration - * manager can do it for us. This ensures that we don't - * reprobe a card already found by the EISA or PCI probes. - */ -struct bt_found -{ - u_long port; - char probed; -}; - -static struct bt_found found[] = -{ - { 0x330, 0 }, - { 0x334, 0 }, - { 0x230, 0 }, - { 0x234, 0 }, - { 0x130, 0 }, - { 0x134, 0 } -}; - -static struct scsi_adapter bt_switch = -{ - bt_scsi_cmd, - btminphys, - 0, - 0, - bt_adapter_info, - "bt", - { 0, 0 } -}; - -/* the below structure is so we have a default dev struct for out link struct */ -static 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 */ - "bt", - 0, - { 0, 0 } -}; - -#define BT_RESET_TIMEOUT 1000 - -/* - * bt_cmd(bt, icnt, ocnt, wait, retval, opcode, ...) - * - * 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 ... - * ...: parameters to the command specified by opcode - * - * 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. - */ -static int -#ifdef __STDC__ -bt_cmd(struct bt_data *bt, int icnt, int ocnt, int wait, u_char *retval, - u_char opcode, ...) -#else -bt_cmd(bt, icnt, ocnt, wait, retval, opcode, va_alist) - struct bt_data *bt; - int icnt, ocnt, wait; - u_char *retval; - u_char opcode; - va_dcl -#endif -{ - va_list ap; - u_char data; - u_char oc; - int i; - int sts; - - /* - * 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(BT_CTRL_STAT_PORT); - if (sts & BT_IDLE) { - break; - } - DELAY(10); - } - if (i == 0) { - if(!btprobing) - printf("bt%d: bt_cmd, host not idle(0x%x)\n", - bt->unit, sts); - return (ENXIO); - } - } - /* - * Now that it is idle, if we expect output, preflush the - * queue feeding to us. - */ - if (ocnt) { - while ((inb(BT_CTRL_STAT_PORT)) & BT_DF) - inb(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 = (u_char)va_arg(ap, int)) { - sts = inb(BT_CTRL_STAT_PORT); - for (i = wait; i; i--) { - sts = inb(BT_CTRL_STAT_PORT); - if (!(sts & BT_CDF)) - break; - DELAY(10); - } - if (i == 0) { - if(!btprobing) - printf("bt%d: bt_cmd, cmd/data port full\n", - bt->unit); - outb(BT_CTRL_STAT_PORT, BT_SRST); - return (ENXIO); - } - outb(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(BT_CTRL_STAT_PORT); - for (i = wait; i; i--) { - sts = inb(BT_CTRL_STAT_PORT); - if (sts & BT_DF) - break; - DELAY(10); - } - if (i == 0) { - if(!btprobing) - printf("bt%d: bt_cmd, cmd/data port empty %d\n", - bt->unit, ocnt); - return (ENXIO); - } - oc = inb(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(BT_INTR_PORT); - if (sts & BT_HACC) { - break; - } - DELAY(10); - } - if (i == 0) { - if(!btprobing) - printf("bt%d: bt_cmd, host not finished(0x%x)\n", - bt->unit, sts); - return (ENXIO); - } - outb(BT_CTRL_STAT_PORT, BT_IRST); - return (0); -} - -struct bt_data * -bt_alloc(unit, iobase) - int unit; - u_long iobase; -{ - struct bt_data *bt; - int i; - - if (unit >= NBT) { - printf("bt: unit number (%d) too high\n", unit); - return NULL; - } - - /* - * Allocate a storage area for us - */ - if (btdata[unit]) { - printf("bt%d: memory already allocated\n", unit); - return NULL; - } - - /* - * Ensure that we haven't already been probed - */ - for (i=0; i < sizeof(found)/sizeof(struct bt_found); i++) { - if (found[i].port == iobase) { - if (found[i].probed) - return NULL; - else { - found[i].probed = 1; - break; - } - } - } - - bt = malloc(sizeof(struct bt_data), M_DEVBUF, M_NOWAIT); - if (!bt) { - printf("bt%d: cannot malloc!\n", unit); - return NULL; - } - bzero(bt, sizeof(struct bt_data)); - btdata[unit] = bt; - bt->unit = unit; - bt->bt_base = iobase; - - return(bt); -} - -void -bt_free(bt) - struct bt_data *bt; -{ - btdata[bt->unit] = NULL; - free(bt, M_DEVBUF); - return; -} - - -int -bt_attach(bt) - struct bt_data *bt; -{ - struct scsibus_data *scbus; - - btprobing = 0; - /* - * fill in the prototype scsi_link. - */ - bt->sc_link.adapter_unit = bt->unit; - bt->sc_link.adapter_targ = bt->bt_scsi_dev; - bt->sc_link.adapter_softc = bt; - bt->sc_link.adapter = &bt_switch; - bt->sc_link.device = &bt_dev; - bt->sc_link.flags = bt->bt_bounce ? SDEV_BOUNCE : 0; - - /* - * Prepare the scsibus_data area for the upperlevel - * scsi code. - */ - scbus = scsi_alloc_bus(); - /* XXX scbus->magtarg should be adjusted for Wide cards */ - if(!scbus) - return 0; - scbus->adapter_link = &bt->sc_link; - - /* - * ask the adapter what subunits are present - */ - scsi_attachdevs(scbus); - return 1; -} - -/* - * Return some information to the caller about the adapter and its - * capabilities. - */ -static u_int32_t -bt_adapter_info(unit) - int unit; -{ - return (2); /* 2 outstanding requests at a time per device */ -} - -/* - * Catch an interrupt from the adaptor - */ -void -bt_intr(arg) - void *arg; -{ - BT_MBI *wmbi; - struct bt_mbx *wmbx; - struct bt_ccb *ccb; - unsigned char stat; - int i, wait; - int found = 0; - struct bt_data *bt; - - bt = (struct bt_data *)arg; - -#ifdef UTEST - printf("bt_intr "); -#endif - /* - * First acknowlege the interrupt, Then if it's - * not telling about a completed operation - * just return. - */ - stat = inb(BT_INTR_PORT); - if((stat & BT_STAT_MASK) == 0) { - /* Shared interrupt */ - return; - } - - /* Mail Box out empty ? */ - if (stat & BT_MBOA) { - printf("bt%d: Available Free mbo post\n", bt->unit); - /* Disable MBO available interrupt */ - outb(BT_CMD_DATA_PORT, BT_MBO_INTR_EN); - wait = 100000; /* 1 sec enough? */ - for (i = wait; i; i--) { - if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF)) - break; - DELAY(10); - } - if (i == 0) { - printf("bt%d: bt_intr, cmd/data port full\n", bt->unit); - outb(BT_CTRL_STAT_PORT, BT_SRST); - return; - } - outb(BT_CMD_DATA_PORT, 0x00); /* Disable */ - wakeup((caddr_t)&bt->bt_mbx); - outb(BT_CTRL_STAT_PORT, BT_IRST); - return; - } - if (!(stat & BT_MBIF)) { - outb(BT_CTRL_STAT_PORT, BT_IRST); - return; - } - /* - * If it IS then process the competed operation - */ - wmbx = &bt->bt_mbx; - wmbi = wmbx->tmbi; - AGAIN: - while (wmbi->stat != BT_MBI_FREE) { - ccb = bt_ccb_phys_kv(bt, (wmbi->ccb_addr)); - if (!ccb) { - wmbi->stat = BT_MBI_FREE; - printf("bt: BAD CCB ADDR!\n"); - continue; - } - found++; - if ((stat = wmbi->stat) != BT_MBI_OK) { - switch (stat) { - case BT_MBI_ABORT: -#ifdef UTEST - if (bt_debug & BT_SHOWMISC) - printf("abort "); -#endif - ccb->host_stat = BT_ABORTED; - break; - - case BT_MBI_UNKNOWN: - ccb = (struct bt_ccb *) 0; -#ifdef UTEST - if (bt_debug & BT_SHOWMISC) - printf("unknown ccb for abort"); -#endif - break; - - case BT_MBI_ERROR: - break; - - default: - panic("Impossible mbxi status"); - - } -#ifdef UTEST - if ((bt_debug & BT_SHOWCMDS) && ccb) { - u_char *cp; - 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\n" - ,wmbi->stat, wmbi); - printf("addr = 0x%x\n", ccb); - } -#endif - } - wmbi->stat = BT_MBI_FREE; - if (ccb) { - untimeout(bt_timeout, (caddr_t)ccb, - ccb->xfer->timeout_ch); - bt_done(bt, ccb); - } - /* Set the IN mail Box pointer for next */ 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) { -#ifdef DEBUG - printf( - "bt%d: mbi at %p should be found, stat=%02x..resync\n", - bt->unit, wmbi, stat); -#endif - } else { - found = 0; - goto AGAIN; - } - } - wmbx->tmbi = wmbi; - outb(BT_CTRL_STAT_PORT, BT_IRST); -} - -/* - * A ccb is put onto the free list. - */ -static void -bt_free_ccb(bt, ccb, flags) - struct bt_data *bt; - struct bt_ccb *ccb; - int flags; -{ - unsigned int opri; - - opri = splbio(); - - ccb->next = bt->bt_ccb_free; - bt->bt_ccb_free = ccb; - ccb->flags = CCB_FREE; - /* - * If there were none, wake anybody waiting for one to come free, - * starting with queued entries. - */ - if (!ccb->next) { - wakeup((caddr_t)&bt->bt_ccb_free); - } - - splx(opri); -} - -/* - * 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. - */ -static struct bt_ccb * -bt_get_ccb(bt, flags) - struct bt_data *bt; - int flags; -{ - unsigned opri; - struct bt_ccb *ccbp; - int hashnum; - - opri = splbio(); - /* - * If we can and have to, sleep waiting for one to come free - * but only if we can't allocate a new one. - */ - while (!(ccbp = bt->bt_ccb_free)) { - if (bt->numccbs < BT_CCB_MAX) { - if (ccbp = (struct bt_ccb *) malloc(sizeof(struct bt_ccb), - M_TEMP, - M_NOWAIT)) { - bzero(ccbp, sizeof(struct bt_ccb)); - bt->numccbs++; - ccbp->flags = CCB_ACTIVE; - /* - * put in the phystokv hash table - * Never gets taken out. - */ - ccbp->hashkey = KVTOPHYS(ccbp); - hashnum = CCB_HASH(ccbp->hashkey); - ccbp->nexthash = bt->ccbhash[hashnum]; - bt->ccbhash[hashnum] = ccbp; - } else { - printf("bt%d: Can't malloc CCB\n", bt->unit); - } - goto gottit; - } else { - if (!(flags & SCSI_NOSLEEP)) { - tsleep((caddr_t)&bt->bt_ccb_free, PRIBIO, - "btccb", 0); - continue; - } - break; - } - } - if (ccbp) { - /* Get CCB from from free list */ - bt->bt_ccb_free = ccbp->next; - ccbp->flags = CCB_ACTIVE; - } - gottit: - splx(opri); - - return (ccbp); -} - -/* - * given a physical address, find the ccb that - * it corresponds to: - */ -static struct bt_ccb * -bt_ccb_phys_kv(bt, ccb_phys) - struct bt_data *bt; - physaddr ccb_phys; -{ - int hashnum = CCB_HASH(ccb_phys); - struct bt_ccb *ccbp = bt->ccbhash[hashnum]; - - while (ccbp) { - if (ccbp->hashkey == ccb_phys) - break; - ccbp = ccbp->nexthash; - } - return ccbp; -} - -/* - * Get a MBO and then Send it - */ -static BT_MBO * -bt_send_mbo(bt, flags, cmd, ccb) - struct bt_data *bt; - int flags; - int cmd; - struct bt_ccb *ccb; -{ - unsigned opri; - BT_MBO *wmbo; /* Mail Box Out pointer */ - struct bt_mbx *wmbx; /* Mail Box pointer specified unit */ - int i, wait; - - wmbx = &bt->bt_mbx; - - opri = splbio(); - - /* Get the Target OUT mail Box pointer and move to Next */ - wmbo = wmbx->tmbo; - wmbx->tmbo = (wmbo == &(wmbx->mbo[BT_MBX_SIZE - 1]) ? - &(wmbx->mbo[0]) : wmbo + 1); - - /* - * 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) { - wait = 100000; /* 1 sec enough? */ - /* Enable MBO available interrupt */ - outb(BT_CMD_DATA_PORT, BT_MBO_INTR_EN); - for (i = wait; i; i--) { - if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF)) - break; - DELAY(10); - } - if (i == 0) { - printf("bt%d: bt_send_mbo, cmd/data port full\n", bt->unit); - outb(BT_CTRL_STAT_PORT, BT_SRST); - return ((BT_MBO *) 0); - } - outb(BT_CMD_DATA_PORT, 0x01); /* Enable */ - tsleep((caddr_t)wmbx, PRIBIO, "btsend", 0); - /* XXX */ /*can't do this! */ - /* May be servicing an int */ - } - /* Link CCB to the Mail Box */ - wmbo->ccb_addr = KVTOPHYS(ccb); - ccb->mbx = wmbo; - wmbo->cmd = cmd; - - /* Send it! */ - outb(BT_CMD_DATA_PORT, BT_START_SCSI); - - splx(opri); - - 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 - */ -static void -bt_done(bt, ccb) - struct bt_data *bt; - struct bt_ccb *ccb; -{ - struct scsi_sense_data *s1, *s2; - struct scsi_xfer *xs = ccb->xfer; - - 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 ((ccb->host_stat != BT_OK || ccb->target_stat != SCSI_OK) - && (!(xs->flags & SCSI_ERR_OK))) { - - s1 = &(ccb->scsi_sense); - s2 = &(xs->sense); - - if (ccb->host_stat) { - switch (ccb->host_stat) { - case BT_ABORTED: /* No response */ - SC_DEBUG(xs->sc_link, SDEV_DB3, - ("timeout reported back\n")); - xs->error = XS_TIMEOUT; - break; - case BT_SEL_TIMEOUT: - SC_DEBUG(xs->sc_link, SDEV_DB3, - ("selection timeout reported back\n")); - xs->error = XS_SELTIMEOUT; - break; - default: /* Other scsi protocol messes */ - xs->error = XS_DRIVER_STUFFUP; - SC_DEBUG(xs->sc_link, SDEV_DB3, - ("unexpected host_stat: %x\n", - ccb->host_stat)); - } - } else { - switch (ccb->target_stat) { - case 0x02: - *s2 = *s1; - xs->error = XS_SENSE; - break; - case 0x08: - xs->error = XS_BUSY; - break; - default: - SC_DEBUG(xs->sc_link, SDEV_DB3, - ("unexpected target_stat: %x\n", - ccb->target_stat)); - xs->error = XS_DRIVER_STUFFUP; - } - } - } else { /* All went correctly OR errors expected */ - xs->resid = 0; - } - xs->flags |= ITSDONE; - bt_free_ccb(bt, ccb, xs->flags); - scsi_done(xs); -} - -/* - * Start the board, ready for normal operation - */ -int -bt_init(bt) - struct bt_data* bt; -{ - unsigned char ad[4]; - volatile int i, sts; - struct bt_config conf; - struct bt_ext_info info; - struct bt_board_info binfo; - - /* - * reset board, If it doesn't respond, assume - * that it's not there.. good for the probe - */ - - outb(BT_CTRL_STAT_PORT, BT_HRST | BT_SRST); - - DELAY(10000); - - for (i = BT_RESET_TIMEOUT; i; i--) { - sts = inb(BT_CTRL_STAT_PORT); - if (sts == (BT_IDLE | BT_INIT)) - break; - DELAY(1000); - } - if (i == 0) { -#ifdef UTEST - printf("bt_init: No answer from board\n"); -#endif - return (ENXIO); - } - - DELAY(10000); - - /* - * Displaying Board ID and Hardware Revision - * 94/05/18 amurai@spec.co.jp - */ - i = bt_cmd(bt, 1, sizeof(binfo),0, - (u_char *)&binfo,BT_GET_BOARD_INFO,sizeof(binfo)); - if(i) - return i; - printf("bt%d: Bt%c%c%c%c/%c%d-", bt->unit, - binfo.id[0], - binfo.id[1], - binfo.id[2], - binfo.id[3], - binfo.ver[0], - (unsigned) binfo.ver[1] - ); - - /* - * Make sure board has a capability of 32bit addressing. - * and Firmware also need a capability of 32bit addressing pointer - * in Extended mailbox and ccb structure. - * 94/05/18 amurai@spec.co.jp - */ - bt_cmd(bt, 1, sizeof(info),0, (u_char *)&info, BT_INQUIRE_EXTENDED, - sizeof(info)); - switch (info.bus_type) { - case BT_BUS_TYPE_24bit: /* PC/AT 24 bit address bus */ - printf("ISA(24bit) bus\n"); - break; - case BT_BUS_TYPE_32bit: /* EISA/VLB/PCI 32 bit bus */ - printf("(32bit) bus\n"); - break; - case BT_BUS_TYPE_MCA: /* forget it right now */ - printf("MCA bus architecture..."); - printf("giving up\n"); - return (ENXIO); - break; - default: - printf("Unknown state..."); - printf("giving up\n"); - return (ENXIO); - break; - } - - if ( binfo.id[0] == '4' && binfo.id[1] == '4' && binfo.id[2] == '5' && - binfo.id[3] == 'S' ) { - printf("bt%d: Your card cannot DMA above 16MB boundary. Bounce buffering enabled.\n", bt->unit); - bt->bt_bounce++; - } else if ( binfo.id[0] == '5' ) { - printf("bt%d: This driver is designed for using 32 bit addressing\n" - "bt%d: mode firmware and EISA/PCI/VLB bus architectures\n" - "bt%d: Bounce-buffering will be used (and is necessary)\n" - "bt%d: if you have more than 16MBytes memory.\n", - bt->unit, - bt->unit, - bt->unit, - bt->unit); - bt->bt_bounce++; - } else if ( info.bus_type == BT_BUS_TYPE_24bit ) { - printf("bt%d: Your board should report a 32bit bus architecture type..\n" - "bt%d: The firmware on your board may have a problem with over\n" - "bt%d: 16MBytes memory handling with this driver.\n", - bt->unit, - bt->unit, - bt->unit); - bt->bt_bounce++; - } - - /* - * Assume we have a board at this stage - * setup dma channel from jumpers and save int - * level - */ - printf("bt%d: reading board settings, ", bt->unit); - - bt_cmd(bt, 0, sizeof(conf), 0, (u_char *)&conf, BT_CONF_GET); - switch (conf.chan) { - case BUSDMA: - bt->bt_dma = -1; - break; - case CHAN0: - outb(0x0b, 0x0c); - outb(0x0a, 0x00); - bt->bt_dma = 0; - break; - case CHAN5: - outb(0xd6, 0xc1); - outb(0xd4, 0x01); - bt->bt_dma = 5; - break; - case CHAN6: - outb(0xd6, 0xc2); - outb(0xd4, 0x02); - bt->bt_dma = 6; - break; - case CHAN7: - outb(0xd6, 0xc3); - outb(0xd4, 0x03); - bt->bt_dma = 7; - break; - default: - printf("illegal dma setting %x\n", conf.chan); - return (EIO); - } - if (bt->bt_dma == -1) - printf("busmastering, "); - else - printf("dma=%d, ", bt->bt_dma); - - switch (conf.intr) { - case INT9: - bt->bt_int = 9; - break; - case INT10: - bt->bt_int = 10; - break; - case INT11: - bt->bt_int = 11; - break; - case INT12: - bt->bt_int = 12; - break; - case INT14: - bt->bt_int = 14; - break; - case INT15: - bt->bt_int = 15; - break; - default: - printf("illegal int setting\n"); - return (EIO); - } - printf("int=%d\n", bt->bt_int); - - /* who are we on the scsi bus */ - bt->bt_scsi_dev = conf.scsi_dev; - /* - * Initialize mail box - */ - *((physaddr *) ad) = KVTOPHYS(&bt->bt_mbx); - bt_cmd(bt, 5, 0, 0, 0, BT_MBX_INIT_EXTENDED - ,BT_MBX_SIZE - ,ad[0] - ,ad[1] - ,ad[2] - ,ad[3]); - - /* - * Set Pointer chain null for just in case - * Link the ccb's into a free-list W/O mbox - * Initialize mail box status to free - */ - if (bt->bt_ccb_free != (struct bt_ccb *) 0) { - printf("bt%d: bt_ccb_free is NOT initialized but init here\n", - bt->unit); - bt->bt_ccb_free = (struct bt_ccb *) 0; - } - for (i = 0; i < BT_MBX_SIZE; i++) { - bt->bt_mbx.mbo[i].cmd = BT_MBO_FREE; - bt->bt_mbx.mbi[i].stat = BT_MBI_FREE; - } - /* - * Set up initial mail box for round-robin operation. - */ - bt->bt_mbx.tmbo = &bt->bt_mbx.mbo[0]; - bt->bt_mbx.tmbi = &bt->bt_mbx.mbi[0]; - bt_inquire_setup_information(bt, &info); - - - /* - * Note that we are going and return (to probe) - */ - return 0; -} - -static void -bt_inquire_setup_information(bt, info) - struct bt_data* bt; - struct bt_ext_info *info; -{ - struct bt_setup setup; - struct bt_sync_value sync; - char dummy[8]; - char sub_ver[3]; - struct bt_boardID bID; - int i; - - /* Inquire Installed Devices */ - bzero( &dummy[0], sizeof(dummy) ); - bt_cmd(bt, 0, sizeof(dummy), 100, &dummy[0], BT_DEV_GET); - - /* - * If board has a capbility of Syncrhonouse mode, - * Get a SCSI Synchronous value - */ - - if (info->s.force) { /* Assume fast sync capability */ - info->s.sync = 1; /* It's appear at 4.25? version */ - info->s.maxsync = 1; - } - if ( info->s.sync ) { - bt_cmd(bt, 1, sizeof(sync), 100, - (u_char *)&sync,BT_GET_SYNC_VALUE,sizeof(sync)); - } - - /* - * Inquire Board ID to board for firmware version - */ - bt_cmd(bt, 0, sizeof(bID), 0, (u_char *)&bID, BT_INQUIRE); - bt_cmd(bt, 0, 1, 0, &sub_ver[0], BT_INQUIRE_REV_THIRD ); - i = ((int)(bID.firm_revision-'0')) * 10 + (int)(bID.firm_version-'0'); - if ( i >= 33 ) { - bt_cmd(bt, 0, 1, 0, &sub_ver[1], BT_INQUIRE_REV_FOURTH ); - } else { - /* - * Below rev 3.3 firmware has a problem for issuing - * the BT_INQUIRE_REV_FOURTH command. - */ - sub_ver[1]='\0'; - } - sub_ver[2]='\0'; - if (sub_ver[1]==' ') - sub_ver[1]='\0'; - printf("bt%d: version %c.%c%s, ", - bt->unit, bID.firm_revision, bID.firm_version, sub_ver ); - - /* - * Obtain setup information from board. - */ - bt_cmd(bt, 1, sizeof(setup), 0, (u_char *)&setup, BT_SETUP_GET, - sizeof(setup)); - - if (setup.sync_neg && info->s.sync ) { - if ( info->s.maxsync ) { - printf("fast sync, "); /* Max 10MB/s */ - } else { - printf("sync, "); /* Max 5MB/s */ - } - } else { - if ( info->s.sync ) { - printf("async, "); /* Never try by board */ - } else { - printf("async only, "); /* Doesn't has a capability on board */ - } - } - if (setup.parity) { - printf("parity, "); - } else { - printf("no parity, "); - } - printf("%d mbxs, %d ccbs\n", setup.num_mbx, BT_CCB_MAX); - - /* - * Displayi SCSI negotiation value by each target. - * amurai@spec.co.jp - */ - for (i = 0; i < 8; i++) { - if (!setup.sync[i].valid ) - continue; - if ( (!setup.sync[i].offset && !setup.sync[i].period) - || !info->s.sync ) { - printf("bt%d: targ %d async\n", bt->unit, i); - } else { - printf("bt%d: targ %d sync rate=%2d.%02dMB/s(%dns), offset=%02d\n", - bt->unit, i, - 100 / sync.value[i], - (100 % sync.value[i]) * 100 / sync.value[i], - sync.value[i] * 10, - setup.sync[i].offset ); - } - } - - /* - * Enable round-robin scheme - appeared at firmware rev. 3.31 - * Below rev 3.XX firmware has a problem for issuing - * BT_ROUND_ROBIN command amurai@spec.co.jp - */ - if ( bID.firm_revision >= '3' ) { - printf("bt%d: Using Strict Round robin scheme\n", bt->unit); - bt_cmd(bt, 1, 0, 0, 0, BT_ROUND_ROBIN, BT_STRICT_ROUND_ROBIN); - } else { - printf("bt%d: Not using Strict Round robin scheme\n", bt->unit); - } - -} - -#ifndef min -#define min(x,y) (x < y ? x : y) -#endif /* min */ - -static void -btminphys(bp) - struct buf *bp; -{ - if (bp->b_bcount > ((BT_NSEG - 1) * PAGESIZ)) { - bp->b_bcount = ((BT_NSEG - 1) * PAGESIZ); - } -} - -/* - * start a scsi operation given the command and the data address. Also needs - * the unit, target and lu. - */ -static int32_t -bt_scsi_cmd(xs) - struct scsi_xfer *xs; -{ - 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 bt_data *bt; - - bt = (struct bt_data *)xs->sc_link->adapter_softc; - - SC_DEBUG(xs->sc_link, SDEV_DB2, ("bt_scsi_cmd\n")); - /* - * get a ccb (mbox-out) 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) { - printf("bt%d: Already done?\n", bt->unit); - xs->flags &= ~ITSDONE; - } - if (!(flags & INUSE)) { - printf("bt%d: Not in use?\n", bt->unit); - xs->flags |= INUSE; - } - if (!(ccb = bt_get_ccb(bt, flags))) { - xs->error = XS_DRIVER_STUFFUP; - return (TRY_AGAIN_LATER); - } - SC_DEBUG(xs->sc_link, SDEV_DB3, - ("start ccb(%p)\n", ccb)); - /* - * Put all the arguments for the xfer in the ccb - */ - ccb->xfer = xs; - 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->target = xs->sc_link->target; - ccb->data_out = 0; - ccb->data_in = 0; - ccb->lun = xs->sc_link->lun; - ccb->scsi_cmd_length = xs->cmdlen; - ccb->sense_ptr = KVTOPHYS(&(ccb->scsi_sense)); - ccb->req_sense_length = sizeof(ccb->scsi_sense); - - if ((xs->datalen) && (!(flags & SCSI_RESET))) { /* can use S/G only if not zero length */ - ccb->data_addr = KVTOPHYS(ccb->scat_gath); - sg = ccb->scat_gath; - seg = 0; -#ifdef TFS - if (flags & SCSI_DATA_UIO) { - struct iovec *iovp; - - 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; - xs->datalen += sg->seg_len = iovp->iov_len; - SC_DEBUGN(xs->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(xs->sc_link, SDEV_DB4, - ("%ld @%p:- ", 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(xs->sc_link, SDEV_DB4, - ("0x%lx", 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 & (~(PAGESIZ - 1))) - + PAGESIZ; - 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 & (~(PAGESIZ - 1))) - + PAGESIZ; - if (datalen) - thisphys = KVTOPHYS(thiskv); - } - /* - * next page isn't contiguous, finish the seg - */ - SC_DEBUGN(xs->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(xs->sc_link, SDEV_DB4, ("\n")); - if (datalen) { - /* - * there's still data, must have run out of segs! - */ - printf("bt%d: bt_scsi_cmd, more than %d DMA segs\n", - bt->unit, BT_NSEG); - xs->error = XS_DRIVER_STUFFUP; - bt_free_ccb(bt, ccb, flags); - return (HAD_ERROR); - } - } 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)) { - bcopy(xs->cmd, ccb->scsi_cmd, ccb->scsi_cmd_length); - } - if (bt_send_mbo(bt, flags, BT_MBO_START, ccb) == (BT_MBO *) 0) { - xs->error = XS_DRIVER_STUFFUP; - bt_free_ccb(bt, ccb, flags); - return (TRY_AGAIN_LATER); - } - /* - * Usually return SUCCESSFULLY QUEUED - */ - SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_sent\n")); - if (!(flags & SCSI_NOMASK)) { - xs->timeout_ch = timeout(bt_timeout, (caddr_t)ccb, - (xs->timeout * hz) / 1000); - return (SUCCESSFULLY_QUEUED); - } - /* - * If we can't use interrupts, poll on completion - */ - return (bt_poll(bt, xs, ccb)); -} - -/* - * Poll a particular unit, looking for a particular xs - */ -static int -bt_poll(bt, xs, ccb) - struct bt_data* bt; - struct scsi_xfer *xs; - struct bt_ccb *ccb; -{ - int count = xs->timeout; - u_char stat; - - /* timeouts are in msec, so we loop in 1000 usec cycles */ - while (count) { - /* - * If we had interrupts enabled, would we - * have got an interrupt? - */ - stat = inb(BT_INTR_PORT); - if (stat & BT_ANY_INTR) { - bt_intr((void *)bt); - } - if (xs->flags & ITSDONE) { - break; - } - DELAY(1000); /* only happens in boot so ok */ - count--; - } - if (count == 0) { - /* - * We timed out, so call the timeout handler manually, - * accounting for the fact that the clock is not running yet - * by taking out the clock queue entry it makes. - */ - bt_timeout(ccb); - - /* - * because we are polling, take out the timeout entry - * bt_timeout made - */ - untimeout(bt_timeout, (caddr_t)ccb, ccb->xfer->timeout_ch); - count = 2000; - while (count) { - /* - * Once again, wait for the int bit - */ - stat = inb(BT_INTR_PORT); - if (stat & BT_ANY_INTR) { - bt_intr((void *)bt); - } - if (xs->flags & ITSDONE) { - break; - } - DELAY(1000); /* only happens in boot so ok */ - count--; - } - if (count == 0) { - /* - * We timed out again... This is bad. Notice that - * this time there is no clock queue entry to remove. - */ - bt_timeout(ccb); - } - } - if (xs->error) - return (HAD_ERROR); - return (COMPLETE); -} - -static void -bt_timeout(void *arg1) -{ - struct bt_ccb * ccb = (struct bt_ccb *)arg1; - int unit; - struct bt_data *bt; - int s = splbio(); - - /* - * A timeout routine in kernel DONOT unlink - * Entry chains when time outed....So infinity Loop.. - * 94/04/20 amurai@spec.co.jp - */ - untimeout(bt_timeout, (caddr_t)ccb, ccb->xfer->timeout_ch); - - unit = ccb->xfer->sc_link->adapter_unit; - bt = btdata[unit]; - -#ifdef UTEST - bt_print_active_ccbs(bt); -#endif - - /* - * If the ccb's mbx is not free, then the board has gone Far East? - */ - if (bt_ccb_phys_kv(bt, ccb->mbx->ccb_addr) == ccb && - ccb->mbx->cmd != BT_MBO_FREE) { - printf("bt%d: not taking commands!\n", unit); - Debugger("bt742a"); - } - /* - * 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("bt%d: Abort Operation has timed out\n", unit); - ccb->xfer->retries = 0; /* I MEAN IT ! */ - ccb->host_stat = BT_ABORTED; - bt_done(bt, ccb); - } else { - /* abort the operation that has timed out */ - printf("bt%d: Try to abort\n", unit); - bt_send_mbo(bt, ~SCSI_NOMASK, BT_MBO_ABORT, ccb); - /* 2 secs for the abort */ - ccb->flags = CCB_ABORTED; - ccb->xfer->timeout_ch = timeout(bt_timeout, (caddr_t)ccb, - 2 * hz); - } - splx(s); -} - -#ifdef UTEST -static 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); -} - -static void -bt_print_active_ccbs(bt) - struct bt_data *bt; -{ - struct bt_ccb *ccb; - int i = 0; - - while (i < CCB_HASH_SIZE) { - ccb = bt->ccbhash[i]; - while (ccb) { - if (ccb->flags != CCB_FREE) - bt_print_ccb(ccb); - ccb = ccb->nexthash; - } - i++; - } -} -#endif /*UTEST */ diff --git a/sys/i386/scsi/btreg.h b/sys/i386/scsi/btreg.h deleted file mode 100644 index 8475fa5..0000000 --- a/sys/i386/scsi/btreg.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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 - * organizations 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. - * - * $Id: btreg.h,v 1.6 1997/02/22 09:38:43 peter Exp $ - */ - -#ifndef _BTREG_H_ -#define _BTREG_H_ - -#include "bt.h" - -/* - * Mail box defs etc. - * these could be bigger but we need the bt_data 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 32CCBs at any one time */ - /* in bt742a H/W ( Not MAX ? ) */ -#define CCB_HASH_SIZE 32 /* when we have a physical addr. for */ - /* a ccb and need to find the ccb in */ - /* space, look it up in the hash table */ -#define BT_NSEG 33 /* - * Number of SG segments per command - * Max of 2048??? - */ - -typedef unsigned long int physaddr; - -struct bt_scat_gath { - unsigned long seg_len; - physaddr seg_addr; -}; - -typedef struct bt_mbx_out { - physaddr ccb_addr; - unsigned char dummy[3]; - unsigned char cmd; -} BT_MBO; - -typedef struct bt_mbx_in { - physaddr ccb_addr; - unsigned char btstat; - unsigned char sdstat; - unsigned char dummy; - unsigned char stat; -} BT_MBI; - -struct bt_mbx { - BT_MBO mbo[BT_MBX_SIZE]; -#define BT_MBO_FREE 0x0 /* MBO intry is free */ -#define BT_MBO_START 0x1 /* MBO activate entry */ -#define BT_MBO_ABORT 0x2 /* MBO abort entry */ - BT_MBI mbi[BT_MBX_SIZE]; -#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 */ - BT_MBO *tmbo; /* Target Mail Box out */ - BT_MBI *tmbi; /* Target Mail Box in */ -}; - - -struct bt_ccb { - unsigned char opcode; -#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 w/sg */ -#define BT_RESET_CCB 0x81 /* SCSI Bus reset */ - unsigned :3, data_in:1, data_out:1,:3; - unsigned char scsi_cmd_length; - unsigned char req_sense_length; - unsigned long data_length; - physaddr data_addr; - unsigned char dummy[2]; - unsigned char host_stat; -#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 */ - unsigned char target_stat; - unsigned char target; - unsigned char lun; - unsigned char scsi_cmd[12]; /* 12 bytes (bytes only) */ - unsigned char dummy2[1]; - unsigned char link_id; - physaddr link_addr; - physaddr sense_ptr; - struct scsi_sense_data scsi_sense; - struct bt_scat_gath scat_gath[BT_NSEG]; - struct bt_ccb *next; - struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ - struct bt_mbx_out *mbx; /* pointer to mail box */ - int flags; -#define CCB_FREE 0 -#define CCB_ACTIVE 1 -#define CCB_ABORTED 2 - struct bt_ccb *nexthash; /* if two hash the same */ - physaddr hashkey; /*physaddr of this ccb */ -}; - -struct bt_data { - int bt_base; /* base port for each board */ - struct bt_mbx bt_mbx; /* all our mailboxes */ - struct bt_ccb *bt_ccb_free; /* list of free CCBs */ - struct bt_ccb *ccbhash[CCB_HASH_SIZE]; /* phys to kv hash */ - int bt_int; /* int. read off board */ - int bt_dma; /* DMA channel read of board */ - int bt_scsi_dev; /* adapters scsi id */ - int numccbs; /* how many we have malloc'd */ - int bt_bounce; /* should we bounce? */ - int unit; /* The zero in bt0 */ - struct scsi_link sc_link; /* prototype for devs */ -}; - -extern struct bt_data *btdata[NBT]; - -extern u_long bt_unit; - -struct bt_data *bt_alloc __P((int unit, u_long iobase)); -void bt_free __P((struct bt_data *bt)); -void bt_intr __P((void *arg)); -int bt_init __P((struct bt_data *bt)); -int bt_attach __P((struct bt_data *bt)); - -#endif /* _BT_H_ */ |