summaryrefslogtreecommitdiffstats
path: root/sys/i386
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1998-09-15 10:40:55 +0000
committergibbs <gibbs@FreeBSD.org>1998-09-15 10:40:55 +0000
commit79200df6729d1afbc24596e05c0bee54a2544616 (patch)
tree454f8a346e1e8ffbde91ed6c5a172835b1d7d78c /sys/i386
parent4035fc4bcc3a3a3a921bfaa090dd3f7f02b9737a (diff)
downloadFreeBSD-src-79200df6729d1afbc24596e05c0bee54a2544616.zip
FreeBSD-src-79200df6729d1afbc24596e05c0bee54a2544616.tar.gz
Obsoleted by CAM.
Diffstat (limited to 'sys/i386')
-rw-r--r--sys/i386/isa/aha1542.c1851
-rw-r--r--sys/i386/scsi/93cx6.c181
-rw-r--r--sys/i386/scsi/93cx6.h93
-rw-r--r--sys/i386/scsi/advansys.c783
-rw-r--r--sys/i386/scsi/advansys.h50
-rw-r--r--sys/i386/scsi/aic7xxx.c3867
-rw-r--r--sys/i386/scsi/aic7xxx.h403
-rw-r--r--sys/i386/scsi/bt.c1583
-rw-r--r--sys/i386/scsi/btreg.h149
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_ */
OpenPOWER on IntegriCloud