summaryrefslogtreecommitdiffstats
path: root/sys/i386/scsi
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1995-01-13 02:24:31 +0000
committergibbs <gibbs@FreeBSD.org>1995-01-13 02:24:31 +0000
commit7052076816082a5d7fe6e9aa280ef22606287b4d (patch)
tree06586cf09a2f9010109e2532d4a47b42a41fc9f2 /sys/i386/scsi
parent00d4d48c053e97244b1f81a79deda7e5fd88aea6 (diff)
downloadFreeBSD-src-7052076816082a5d7fe6e9aa280ef22606287b4d.zip
FreeBSD-src-7052076816082a5d7fe6e9aa280ef22606287b4d.tar.gz
Generic support for the entire aic7x70 line of adaptors. No one else
came up with a directory place ment more me, so now we have i386/scsi.
Diffstat (limited to 'sys/i386/scsi')
-rw-r--r--sys/i386/scsi/aic7xxx.c926
-rw-r--r--sys/i386/scsi/aic7xxx.h142
2 files changed, 619 insertions, 449 deletions
diff --git a/sys/i386/scsi/aic7xxx.c b/sys/i386/scsi/aic7xxx.c
index cedaede..a28bcaa 100644
--- a/sys/i386/scsi/aic7xxx.c
+++ b/sys/i386/scsi/aic7xxx.c
@@ -1,8 +1,12 @@
/*
- * Driver for the 27/284X series adaptec SCSI controllers
- * Copyright (c) 1994 Justin T. Gibbs.
+ * Generic driver for the aic7xxx based adaptec SCSI controllers
+ * Copyright (c) 1994, 1995 Justin T. Gibbs.
* All rights reserved.
*
+ * Product specific probe and attach routines can be found in:
+ * i386/isa/aic7770.c 27/284X and aic7770 motherboard controllers
+ * i386/pci/aic7870.c 294x and aic7870 motherboard controllers
+ *
* Portions of this driver are based on the FreeBSD 1742 Driver:
*
* Written by Julian Elischer (julian@tfs.com)
@@ -20,15 +24,14 @@
*
* commenced: Sun Sep 27 18:14:01 PDT 1992
*
- * $Id: aic7770.c,v 1.7 1994/11/29 23:06:54 gibbs Exp $
+ * $Id: aic7770.c,v 1.8 1994/12/31 19:31:56 gibbs Exp $
*/
/*
* TODO:
- * Add support for dual and wide busses
+ * Add target reset capabilities
* Implement Target Mode
* Implement Tagged Queuing
- * Add target reset capabilities
- * Add support for the 294X series cards
+ * Test support for the 294X series cards
*
* This driver is very stable, and seems to offer performance
* comprable to the 1742 FreeBSD driver. I have not experienced
@@ -36,13 +39,6 @@
* sense, it is untested.
*/
-#define AHC_SCB_MAX 16 /*
- * Up to 16 SCBs on some types of aic7xxx based
- * boards. The aic7770 family only have 4
- */
-
-#include "ahc.h" /* for NAHC from config */
-
#include <sys/param.h>
#include <sys/systm.h>
@@ -52,75 +48,39 @@
#include <sys/user.h>
#include <i386/isa/isa.h>
#include <i386/isa/isa_device.h>
-#include <machine/cpufunc.h>
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
-#include <sys/devconf.h>
+#include <machine/cpufunc.h>
+#include <i386/isa/aic7xxx.h>
-#define AHC_NSEG 256 /* number of dma segments supported */
#define PAGESIZ 4096
-/* #define AHCDEBUG */
-
-typedef unsigned long int physaddr;
-
#include <sys/kernel.h>
#define KVTOPHYS(x) vtophys(x)
-typedef enum {
- AHC_274, /* Single Channel */
- AHC_274T, /* Twin Channel */
- AHC_274W, /* Wide Channel */
- AHC_284, /* VL Single Channel */
- AHC_284T, /* VL Twin Channel */
- AHC_284W, /* VL Wide Channel - Do these exist?? */
-}ahc_type;
-
-int ahcprobe();
-int ahcprobe1 __P((struct isa_device *dev, ahc_type type));
-int ahc_attach();
+struct ahc_data *ahcdata[NAHC];
+
int ahc_init __P((int unit));
-void ahc_loadseq __P((int port));
-int ahcintr();
+void ahc_loadseq __P((u_long iobase));
int32 ahc_scsi_cmd();
timeout_t ahc_timeout;
void ahc_done();
struct scb *ahc_get_scb __P((int unit, int flags));
void ahc_free_scb();
+void ahc_abort_scb __P((int unit, struct ahc_data *ahc, struct scb *scb));
void ahcminphys();
struct scb *ahc_scb_phys_kv();
u_int32 ahc_adapter_info();
-#define MAX_SLOTS 16 /* max slots on the EISA bus */
-static ahc_slot = 0; /* slot last board was found in */
-static ahc_unit = 0;
+int ahc_unit = 0;
/* Different debugging levels - only one so-far */
#define AHC_SHOWMISC 0x0001
int ahc_debug = AHC_SHOWMISC;
-/*
- * Standard EISA Host ID regs (Offset from slot base)
- */
-
-#define HID0 0xC80 /* 0,1: msb of ID2, 2-7: ID1 */
-#define HID1 0xC81 /* 0-4: ID3, 5-7: LSB ID2 */
-#define HID2 0xC82 /* product, 0=174[20] 1 = 1744 */
-#define HID3 0xC83 /* firmware revision */
/**** bit definitions for SCSIDEF ****/
-#define HSCSIID 0x07 /* our SCSI ID */
-
-typedef struct
-{
- ahc_type type;
- unsigned char id; /* The Last EISA Host ID reg */
-} ahc_sig;
-
-#define CHAR1(B1,B2) (((B1>>2) & 0x1F) | '@')
-#define CHAR2(B1,B2) (((B1<<3) & 0x18) | ((B2>>5) & 0x7)|'@')
-#define CHAR3(B1,B2) ((B2 & 0x1F) | '@')
-
-struct isa_driver ahcdriver = {ahcprobe, ahc_attach, "ahc"};
+#define HSCSIID 0x07 /* our SCSI ID */
+#define HWSCSIID 0x0f /* our SCSI ID if Wide Bus */
struct scsi_adapter ahc_switch =
{
@@ -145,26 +105,6 @@ struct scsi_device ahc_dev =
{ 0, 0 }
};
-static struct kern_devconf kdc_ahc[NAHC] = { {
- 0, 0, 0, /* filled in by dev_attach */
- "ahc", 0, { MDDT_ISA, 0, "bio" },
- isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,
- &kdc_isa0, /* parent */
- 0, /* parentdata */
- DC_BUSY, /* host adapters are always ``in use'' */
- "Adaptec aic7770 based SCSI host adapter"
-} };
-
-static inline void
-ahc_registerdev(struct isa_device *id)
-{
- if(id->id_unit)
- kdc_ahc[id->id_unit] = kdc_ahc[0];
- kdc_ahc[id->id_unit].kdc_unit = id->id_unit;
- kdc_ahc[id->id_unit].kdc_parentdata = id;
- dev_attach(&kdc_ahc[id->id_unit]);
-}
-
/*
* All of these should be in a separate header file shared by the sequencer
@@ -172,7 +112,7 @@ ahc_registerdev(struct isa_device *id)
* add an additional 0xc00 offset when using them in the kernel driver. The
* aic7770 assembler must be modified to allow include files as well. All
* page numbers refer to the Adaptec AIC-7770 Data Book availible from
- * Adaptec's Technical Documents Department 1-800-634-2766
+ * Adaptec's Technical Documents Department 1-800-934-2766
*/
/* -------------------- AIC-7770 offset definitions ----------------------- */
@@ -181,7 +121,7 @@ ahc_registerdev(struct isa_device *id)
* SCSI Sequence Control (p. 3-11).
* Each bit, when set starts a specific SCSI sequence on the bus
*/
-#define SCSISEQ 0xc00
+#define SCSISEQ 0xc00ul
#define TEMODEO 0x80
#define ENSELO 0x40
#define ENSELI 0x20
@@ -195,7 +135,7 @@ ahc_registerdev(struct isa_device *id)
* SCSI Control Signal Read Register (p. 3-15).
* Reads the actual state of the SCSI bus pins
*/
-#define SCSISIGI 0xc03
+#define SCSISIGI 0xc03ul
#define CDI 0x80
#define IOI 0x40
#define MSGI 0x20
@@ -211,7 +151,7 @@ ahc_registerdev(struct isa_device *id)
* those signals that are allowed in the current mode (Initiator/Target) are
* asserted.
*/
-#define SCSISIGO 0xc03
+#define SCSISIGO 0xc03ul
#define CDO 0x80
#define IOO 0x40
#define MSGO 0x20
@@ -221,12 +161,15 @@ ahc_registerdev(struct isa_device *id)
#define REQO 0x02
#define ACKO 0x01
+/* XXX document this thing */
+#define SCSIRATE 0xc04ul
+
/*
* SCSI ID (p. 3-18).
* Contains the ID of the board and the current target on the
* selected channel
*/
-#define SCSIID 0xc05
+#define SCSIID 0xc05ul
#define TID 0xf0 /* Target ID mask */
#define OID 0x0f /* Our ID mask */
@@ -235,7 +178,7 @@ ahc_registerdev(struct isa_device *id)
* Contains one set of SCSI Interrupt codes
* These are most likely of interest to the sequencer
*/
-#define SSTAT0 0xc0b
+#define SSTAT0 0xc0bul
#define TARGET 0x80 /* Board is a target */
#define SELDO 0x40 /* Selection Done */
#define SELDI 0x20 /* Board has been selected */
@@ -249,7 +192,7 @@ ahc_registerdev(struct isa_device *id)
* Clear SCSI Interrupt 1 (p. 3-23)
* Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
*/
-#define CLRSINT1 0xc0c
+#define CLRSINT1 0xc0cul
#define CLRSELTIMEO 0x80
#define CLRATNO 0x40
#define CLRSCSIRSTI 0x20
@@ -263,7 +206,7 @@ ahc_registerdev(struct isa_device *id)
* SCSI Status 1 (p. 3-24)
* These interrupt bits are of interest to the kernel driver
*/
-#define SSTAT1 0xc0c
+#define SSTAT1 0xc0cul
#define SELTO 0x80
#define ATNTARG 0x40
#define SCSIRSTI 0x20
@@ -278,7 +221,7 @@ ahc_registerdev(struct isa_device *id)
* Upper four bits are the device id. The ONEBIT is set when the re/selecting
* device did not set its own ID.
*/
-#define SELID 0xc19
+#define SELID 0xc19ul
#define SELID_MASK 0xf0
#define ONEBIT 0x08
/* UNUSED 0x07 */
@@ -290,7 +233,7 @@ ahc_registerdev(struct isa_device *id)
* register. SELWIDE allows for the coexistence of 8bit and 16bit devices
* on a wide bus.
*/
-#define SBLKCTL 0xc1f
+#define SBLKCTL 0xc1ful
/* UNUSED 0xc0 */
#define AUTOFLUSHDIS 0x20
/* UNUSED 0x10 */
@@ -303,7 +246,7 @@ ahc_registerdev(struct isa_device *id)
* Sequencer Control (p. 3-33)
* Error detection mode and speed configuration
*/
-#define SEQCTL 0xc60
+#define SEQCTL 0xc60ul
#define PERRORDIS 0x80
#define PAUSEDIS 0x40
#define FAILDIS 0x20
@@ -320,26 +263,28 @@ ahc_registerdev(struct isa_device *id)
* four bytes in sucessesion. The SEQADDRs will increment after the most
* significant byte is written
*/
-#define SEQRAM 0xc61
+#define SEQRAM 0xc61ul
/*
* Sequencer Address Registers (p. 3-35)
* Only the first bit of SEQADDR1 holds addressing information
*/
-#define SEQADDR0 0xc62
-#define SEQADDR1 0xc63
+#define SEQADDR0 0xc62ul
+#define SEQADDR1 0xc63ul
#define SEQADDR1_MASK 0x01
/*
* Accumulator
* We cheat by passing arguments in the Accumulator up to the kernel driver
*/
-#define ACCUM 0xc64
+#define ACCUM 0xc64ul
+
+#define SINDEX 0xc65ul
/*
* Board Control (p. 3-43)
*/
-#define BCTL 0xc84
+#define BCTL 0xc84ul
/* RSVD 0xf0 */
#define ACE 0x08 /* Support for external processors */
/* RSVD 0x06 */
@@ -349,7 +294,7 @@ ahc_registerdev(struct isa_device *id)
* Host Control (p. 3-47) R/W
* Overal host control of the device.
*/
-#define HCNTRL 0xc87
+#define HCNTRL 0xc87ul
/* UNUSED 0x80 */
#define POWRDN 0x40
/* UNUSED 0x20 */
@@ -366,20 +311,21 @@ ahc_registerdev(struct isa_device *id)
* SCB Pointer (p. 3-49)
* Gate one of the four SCBs into the SCBARRAY window.
*/
-#define SCBPTR 0xc90
+#define SCBPTR 0xc90ul
/*
* Interrupt Status (p. 3-50)
* Status for system interrupts
*/
-#define INTSTAT 0xc91
+#define INTSTAT 0xc91ul
#define SEQINT_MASK 0xf0 /* SEQINT Status Codes */
#define BAD_PHASE 0x00
#define MSG_REJECT 0x10
#define NO_IDENT 0x20
#define NO_MATCH 0x30
-#define TRANS_RATE 0x40
+#define MSG_SDTR 0x40
#define BAD_STATUS 0x50
+#define MSG_WDTR 0x60
#define BRKADRINT 0x08
#define SCSIINT 0x04
#define CMDCMPLT 0x02
@@ -391,7 +337,7 @@ ahc_registerdev(struct isa_device *id)
* Reporting of catastrophic errors. You usually cannot recover from
* these without a full board reset.
*/
-#define ERROR 0xc92
+#define ERROR 0xc92ul
/* UNUSED 0xf0 */
#define PARERR 0x08
#define ILLOPCODE 0x04
@@ -401,7 +347,7 @@ ahc_registerdev(struct isa_device *id)
/*
* Clear Interrupt Status (p. 3-52)
*/
-#define CLRINT 0xc92
+#define CLRINT 0xc92ul
#define CLRBRKADRINT 0x08
#define CLRINTSTAT 0x04 /* UNDOCUMENTED - must be unpaused */
#define CLRCMDINT 0x02
@@ -412,7 +358,7 @@ ahc_registerdev(struct isa_device *id)
* Byte offset into the SCB Array and an optional bit to allow auto
* incrementing of the address during download and upload operations
*/
-#define SCBCNT 0xc9a
+#define SCBCNT 0xc9aul
#define SCBAUTO 0x80
#define SCBCNT_MASK 0x1f
@@ -420,30 +366,34 @@ ahc_registerdev(struct isa_device *id)
* Queue In FIFO (p. 3-60)
* Input queue for queued SCBs (commands that the seqencer has yet to start)
*/
-#define QINFIFO 0xc9b
+#define QINFIFO 0xc9bul
/*
* Queue In Count (p. 3-60)
* Number of queued SCBs
*/
-#define QINCNT 0xc9c
+#define QINCNT 0xc9cul
/*
* Queue Out FIFO (p. 3-61)
* Queue of SCBs that have completed and await the host
*/
-#define QOUTFIFO 0xc9d
+#define QOUTFIFO 0xc9dul
/*
* Queue Out Count (p. 3-61)
* Number of queued SCBs in the Out FIFO
*/
-#define QOUTCNT 0xc9e
+#define QOUTCNT 0xc9eul
-#define SCBARRAY 0xca0
+#define SCBARRAY 0xca0ul
/* ---------------- END AIC-7770 Register Definitions ----------------- */
+/* --------------------- AIC-7870-only definitions -------------------- */
+
+#define DSPCISTATUS 0xc86ul
+
/* ---------------------- Scratch RAM Offsets ------------------------- */
/* These offsets are either to values that are initialized by the board's
* BIOS or are specified by the Linux sequencer code. If I can figure out
@@ -454,51 +404,62 @@ ahc_registerdev(struct isa_device *id)
/*
* 1 byte per target starting at this address for configuration values
*/
-#define HA_TARG_SCRATCH 0xc20
+#define HA_TARG_SCRATCH 0xc20ul
/*
* The sequencer will stick the frist byte of any rejected message here so
* we can see what is getting thrown away.
*/
-#define HA_REJBYTE 0xc31
-
-/*
- * Pending message flag
- */
-#define HA_MSG_FLAGS 0xc35
+#define HA_REJBYTE 0xc31ul
/*
* Length of pending message
*/
-#define HA_MSG_LEN 0xc36
+#define HA_MSG_LEN 0xc36ul
/*
* message body
*/
-#define HA_MSG_START 0xc37 /* outgoing message body */
+#define HA_MSG_START 0xc37ul /* outgoing message body */
/*
* These are offsets into the card's scratch ram. Some of the values are
* specified in the AHA2742 technical reference manual and are initialized
* by the BIOS at boot time.
*/
-#define HA_ARG_1 0xc4c
-#define HA_RETURN_1 0xc4c
+#define HA_ARG_1 0xc4cul
+#define HA_RETURN_1 0xc4cul
+#define SEND_WDTR 0x80
+#define SEND_SDTR 0x80
+
+#define HA_SIGSTATE 0xc4dul
-#define HA_SIGSTATE 0xc4d
-#define HA_NEEDSDTR 0xc4e
+#define HA_NEEDWDTR0 0xc34ul
+#define HA_NEEDWDTR1 0xc35ul
+#define HA_NEEDSDTR0 0xc4eul
+#define HA_NEEDSDTR1 0xc4ful
-#define HA_SCBCOUNT 0xc56
-#define HA_FLAGS 0xc57
+#define HA_SCBCOUNT 0xc56ul
+#define HA_FLAGS 0xc57ul
#define TWIN_BUS 0x01
#define WIDE_BUS 0x02
-#define HA_ACTIVE 0xc58
+#define CHECK_DTR 0x08
+#define SENSE 0x10
+#define ACTIVE_MSG 0x20
+#define IDENTIFY_SEEN 0x40
+#define RESELECTING 0x80
-#define HA_SCSICONF 0xc5a
-#define INTDEF 0xc5c
-#define HA_HOSTCONF 0xc5d
+#define HA_ACTIVE0 0xc58ul
+#define HA_ACTIVE1 0xc59ul
+
+#define HA_SCSICONF 0xc5aul
+#define INTDEF 0xc5cul
+#define HA_HOSTCONF 0xc5dul
#define MSG_ABORT 0x06
+#define BUS_8_BIT 0x00
+#define BUS_16_BIT 0x01
+#define BUS_32_BIT 0x02
/*
* Since the sequencer can disable pausing in a critical section, we
@@ -520,92 +481,11 @@ ahc_registerdev(struct isa_device *id)
#define RESTART_SEQUENCER(ahc) \
do { \
outb( SEQCTL + ahc->baseport, SEQRESET|FASTMODE ); \
- } while (inw(SEQADDR0 + ahc->baseport) != 0); \
+ } while (inb(SEQADDR0 + ahc->baseport) != 0 && \
+ inb(SEQADDR1 + ahc->baseport != 0)); \
\
UNPAUSE_SEQUENCER(ahc);
-
-struct ahc_dma_seg {
- physaddr addr;
- long len;
-};
-
-/*
- * The driver keeps up to four scb structures per card in memory. Only the
- * first 26 bytes of the structure are valid for the hardware, the rest used
- * for driver level bookeeping. The "__attribute ((packed))" tags ensure that
- * gcc does not attempt to pad the long ints in the structure to word
- * boundaries since the first 26 bytes of this structure must have the correct
- * offsets for the hardware to find them. The driver should be further
- * optimized so that we only have to download the first 14 bytes since as long
- * as we always use S/G, the last fields should be zero anyway. Its mostly a
- * matter of looking through the sequencer code and ensuring that those fields
- * are cleared or loaded with a valid value before being read.
- */
-struct scb {
-/* ------------ Begin hardware supported fields ---------------- */
-/*1*/ u_char control;
-#define SCB_REJ_MDP 0x80 /* Reject MDP message */
-#define SCB_DCE 0x40 /* Disconnect enable */
-#define SCB_TE 0x20 /* Tag enable */
-#define SCB_WAITING 0x06
-#define SCB_DIS 0x04
-#define SCB_TAG_TYPE 0x3
-#define SIMPLE_QUEUE 0x0
-#define HEAD_QUEUE 0x1
-#define OR_QUEUE 0x2
-/*2*/ u_char target_channel_lun; /* 4/1/3 bits */
-/*3*/ u_char SG_segment_count;
-/*7*/ physaddr SG_list_pointer __attribute__ ((packed));
-/*11*/ physaddr cmdpointer __attribute__ ((packed));
-/*12*/ u_char cmdlen;
-/*14*/ u_char RESERVED[2]; /* must be zero */
-/*15*/ u_char target_status;
-/*18*/ u_char residual_data_count[3];
-/*19*/ u_char residual_SG_segment_count;
-/*23*/ physaddr data __attribute__ ((packed));
-/*26*/ u_char datalen[3];
-#define SCB_SIZE 26 /* amount to actually download */
-#if 0
- /*
- * No real point in transferring this to the
- * SCB registers.
- */
- unsigned char RESERVED[6];
-#endif
- /*-----------------end of hardware supported fields----------------*/
- struct scb *next; /* in free list */
- struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
- int flags;
-#define SCB_FREE 0x00
-#define SCB_ACTIVE 0x01
-#define SCB_ABORTED 0x02
-#define SCB_IMMED 0x04
-#define SCB_IMMED_FAIL 0x08
-#define SCB_SENSE 0x10
- int position; /* Position in scbarray */
- struct ahc_dma_seg ahc_dma[AHC_NSEG] __attribute__ ((packed));
- struct scsi_sense sense_cmd; /* SCSI command block */
-};
-
-struct ahc_data {
- ahc_type type;
- int flags;
-#define AHC_INIT 0x01;
- int baseport;
- struct scb *scbarray[AHC_SCB_MAX]; /* Mirror boards scbarray */
- struct scb *free_scb;
- int our_id; /* our scsi id */
- int vect;
- struct scb *immed_ecb; /* an outstanding immediete command */
- struct scsi_link sc_link;
- struct scsi_link sc_link_b; /* Second bus for Twin channel cards */
- u_short needsdtr; /* Targets we iniaitiate sync neg to */
- int numscbs;
- u_char maxscbs;
- int unpause;
-} *ahcdata[NAHC];
-
#ifdef AHCDEBUG
void
ahc_print_scb(scb)
@@ -635,7 +515,7 @@ ahc_print_active_scb(ahc)
struct ahc_data *ahc;
{
int cur_scb_offset;
- int port = ahc->baseport;
+ u_long iobase = ahc->baseport;
PAUSE_SEQUENCER(ahc);
cur_scb_offset = inb(SCBPTR + port);
UNPAUSE_SEQUENCER(ahc);
@@ -683,64 +563,15 @@ static struct {
static int ahc_num_syncrates =
sizeof(ahc_syncrates) / sizeof(ahc_syncrates[0]);
-int
-ahcprobe(struct isa_device *dev)
-{
- int port;
- int i;
- u_char sig_id[4];
-
- ahc_sig valid_ids[] = {
- /* Entries of other tested adaptors should be added here */
- AHC_274, 0x71, /*274x, Card*/
- AHC_274, 0x70, /*274x, Motherboard*/
- AHC_284, 0x56, /*284x, BIOS enabled*/
- AHC_284, 0x57, /*284x, BIOS disabled*/
- };
-
-
- ahc_slot++;
- while (ahc_slot <= MAX_SLOTS) {
- port = 0x1000 * ahc_slot;
- for( i = 0; i < sizeof(sig_id); i++ )
- {
- /*
- * An outb is required to prime these registers on
- * VL cards
- */
- outb( port + HID0, HID0 + i );
- sig_id[i] = inb(port + HID0 + i);
- }
- if (sig_id[0] == 0xff) {
- ahc_slot++;
- continue;
- }
- /* Check manufacturer's ID. */
- if ((CHAR1(sig_id[0], sig_id[1]) == 'A')
- && (CHAR2(sig_id[0], sig_id[1]) == 'D')
- && (CHAR3(sig_id[0], sig_id[1]) == 'P')
- && (sig_id[2] == 0x77)) {
- for( i = 0; i < sizeof(valid_ids)/sizeof(ahc_sig); i++)
- if ( sig_id[3] == valid_ids[i].id ) {
- dev->id_iobase = port;
- return ahcprobe1(dev, valid_ids[i].type);
- }
- }
- ahc_slot++;
- }
- return 0;
-}
-
/*
* Check if the device can be found at the port given
* and if so, determine configuration and set it up for further work.
- * As an argument, takes the isa_device structure from
- * autoconf.c.
*/
int
-ahcprobe1(dev, type)
- struct isa_device *dev;
+ahcprobe(unit, iobase, type)
+ int unit;
+ u_long iobase;
ahc_type type;
{
@@ -748,7 +579,6 @@ ahcprobe1(dev, type)
* find unit and check we have that many defined
*/
- int unit = dev->id_unit;
struct ahc_data *ahc;
if (unit >= NAHC) {
@@ -771,7 +601,7 @@ ahcprobe1(dev, type)
}
bzero(ahc, sizeof(struct ahc_data));
ahcdata[unit] = ahc;
- ahc->baseport = dev->id_iobase;
+ ahc->baseport = iobase;
ahc->type = type;
/*
@@ -786,15 +616,7 @@ ahcprobe1(dev, type)
return (0);
}
- /*
- * If it's there, put in it's interrupt vectors
- */
-
- dev->id_irq = (1 << ahc->vect);
- dev->id_drq = -1; /* use EISA dma */
-
- ahc_unit++;
- return IO_EISASIZE;
+ return (1);
}
@@ -813,8 +635,9 @@ void ahc_scsirate(scsirate, period, offset, unit, target )
if ((ahc_syncrates[i].period - period) >= 0) {
*scsirate = (ahc_syncrates[i].sxfr) | (offset & 0x0f);
- printf("ahc%d: target %d synchronous at %sMb/s\n",
- unit, target, ahc_syncrates[i].rate );
+ printf("ahc%d: target %d synchronous at %sMB/s, "
+ "offset = 0x%x\n",
+ unit, target, ahc_syncrates[i].rate, offset );
#ifdef AHCDEBUG
#endif /* AHCDEBUG */
return;
@@ -834,13 +657,11 @@ void ahc_scsirate(scsirate, period, offset, unit, target )
* Attach all the sub-devices we can find
*/
int
-ahc_attach(dev)
- struct isa_device *dev;
+ahc_attach(unit)
+ int unit;
{
- int unit = dev->id_unit;
struct ahc_data *ahc = ahcdata[unit];
-
- ahc_registerdev(dev);
+ u_char flags;
/*
* fill in the prototype scsi_link.
@@ -855,9 +676,11 @@ ahc_attach(dev)
/*
* ask the adapter what subunits are present
*/
+ printf("ahc%d: Probing channel A\n", unit);
scsi_attachdevs(&(ahc->sc_link));
- if(ahc->type == AHC_274T || ahc->type == AHC_284T) {
+ if(ahc->type == AHC_274T || ahc->type == AHC_284T
+ || ahc->type == AHC_294T) {
/* Configure the second scsi bus */
ahc->sc_link_b = ahc->sc_link;
ahc->sc_link_b.fordriver = (void *)0x0008;
@@ -865,6 +688,15 @@ ahc_attach(dev)
scsi_attachdevs(&(ahc->sc_link_b));
}
+ /*
+ * We should be done with all SDTR and WDTR messages, so
+ * lets tell the sequencer to stop checking if it should
+ * be doing them. This makes ~8 tests into 1.
+ */
+ PAUSE_SEQUENCER(ahc);
+ flags = inb(HA_FLAGS + ahc->baseport);
+ outb(HA_FLAGS + ahc->baseport, flags & ~CHECK_DTR);
+ UNPAUSE_SEQUENCER(ahc);
return 1;
}
@@ -874,35 +706,35 @@ ahc_send_scb( ahc, scb )
struct scb *scb;
{
int old_scbptr;
- int base = ahc->baseport;
+ u_long iobase = ahc->baseport;
PAUSE_SEQUENCER(ahc);
- old_scbptr = inb(SCBPTR + base);
- outb(SCBPTR + base, scb->position);
+ old_scbptr = inb(SCBPTR + iobase);
+ outb(SCBPTR + iobase, scb->position);
- outb(SCBCNT + base, SCBAUTO);
+ outb(SCBCNT + iobase, SCBAUTO);
- outsb(SCBARRAY + base, scb, SCB_SIZE);
+ outsb(SCBARRAY + iobase, scb, SCB_DOWN_SIZE);
- outb(SCBCNT + base, 0);
+ outb(SCBCNT + iobase, 0);
- outb(QINFIFO + base, scb->position);
- outb(SCBPTR + base, old_scbptr);
+ outb(QINFIFO + iobase, scb->position);
+ outb(SCBPTR + iobase, old_scbptr);
UNPAUSE_SEQUENCER(ahc);
}
static
-void ahc_getscb(base, scb)
- int base;
+void ahc_getscb(iobase, scb)
+ u_long iobase;
struct scb *scb;
{
- outb(SCBCNT + base, 0x80); /* SCBAUTO */
+ outb(SCBCNT + iobase, 0x80); /* SCBAUTO */
- insb(SCBARRAY + base, scb, SCB_SIZE);
+ insb(SCBARRAY + iobase, scb, SCB_UP_SIZE);
- outb(SCBCNT + base, 0);
+ outb(SCBCNT + iobase, 0);
}
/*
@@ -915,25 +747,42 @@ ahcintr(unit)
int intstat;
u_char status;
struct ahc_data *ahc = ahcdata[unit];
- int port = ahc->baseport;
+ u_long iobase = ahc->baseport;
struct scb *scb = NULL;
struct scsi_xfer *xs = NULL;
- intstat = inb(INTSTAT + port);
+ /*
+ * Check that we are in the "running" state, and should be
+ * receiving interrupts. The reason for doing this is that
+ * we have a choice of edge or level sensitive interrupts,
+ * and if we have the wrong type set, we'll get spurrious
+ * interrupts. Toggle to the other type if need be.
+ */
+ if(ahc->flags != AHC_RUNNING){
+ printf("ahc%d: Switching interrupt type\n", unit);
+ ahc->unpause ^= 0x8;
+ outb(HCNTRL + iobase, inb(HCNTRL + iobase) ^ 0x8);
+ return 1;
+ }
+
+ intstat = inb(INTSTAT + iobase);
if (intstat & BRKADRINT) {
/* We upset the sequencer :-( */
/* Lookup the error message */
- int i, error = inb(ERROR + port);
+ int i, error = inb(ERROR + iobase);
int num_errors = sizeof(hard_error)/sizeof(hard_error[0]);
for(i = 0; error != 1 && i < num_errors; i++)
error >>= 1;
- panic("ahc%d: brkadrint, %s at seqaddr = 0x%x\n",
- unit, hard_error[i].errmesg, inw(SEQADDR0 + port));
+ panic("ahc%d: brkadrint, %s at seqaddr = 0x%lx\n",
+ unit, hard_error[i].errmesg,
+ (inb(SEQADDR1 + iobase) << 8) |
+ inb(SEQADDR0 + iobase));
+
}
if (intstat & SEQINT) {
- unsigned char transfer, offset, rate;
+ unsigned char transfer;
switch (intstat & SEQINT_MASK) {
case BAD_PHASE:
@@ -943,18 +792,18 @@ ahcintr(unit)
case MSG_REJECT:
printf("ahc%d: Warning - "
"message reject, message type: 0x%x\n", unit,
- inb(HA_REJBYTE + port));
+ inb(HA_REJBYTE + iobase));
break;
case NO_IDENT:
panic("ahc%d: No IDENTIFY message from reconnecting "
"target %d\n",
- unit, (inb(SELID + port) >> 4) & 0xf);
+ unit, (inb(SELID + iobase) >> 4) & 0xf);
break;
case NO_MATCH:
{
u_char active;
- int active_port = HA_ACTIVE + port;
- int tcl = inb(SCBARRAY+1 + port);
+ int active_port = HA_ACTIVE0 + iobase;
+ int tcl = inb(SCBARRAY+1 + iobase);
int target = (tcl >> 4) & 0x0f;
printf("ahc%d: no active SCB for reconnecting "
"target %d, channel %c - issuing ABORT\n",
@@ -968,24 +817,140 @@ ahcintr(unit)
active = inb(active_port);
active &= ~(0x01 << (target & 0x07));
outb(active_port, active);
- outb(CLRSINT1 + port, CLRSELTIMEO);
+ outb(CLRSINT1 + iobase, CLRSELTIMEO);
RESTART_SEQUENCER(ahc);
break;
}
- case TRANS_RATE:
- /*
- * Help the sequencer to translate the negotiated
- * transfer rate. Transfer is 1/4 the period
- * in ns as is returned by the sync negotiation
- * message. So, we must multiply by four
- */
- transfer = inb(HA_ARG_1 + port) << 2;
- /* The bottom half of SCSIXFER*/
- offset = inb(ACCUM + port);
- ahc_scsirate(&rate, transfer, offset, unit,
- inb(SCSIID + port) >> 0x4);
- outb(HA_RETURN_1 + port, rate);
- break;
+ case MSG_SDTR:
+ {
+ int loc;
+ u_short needsdtr;
+ u_char scsi_id, offset, rate, targ_scratch;
+ /*
+ * Help the sequencer to translate the
+ * negotiated transfer rate. Transfer is
+ * 1/4 the period in ns as is returned by
+ * the sync negotiation message. So, we must
+ * multiply by four
+ */
+ transfer = inb(HA_ARG_1 + iobase) << 2;
+ /* The bottom half of SCSIXFER*/
+ offset = inb(ACCUM + iobase);
+ scsi_id = inb(SCSIID + iobase) >> 0x4;
+ ahc_scsirate(&rate, transfer, offset, unit,
+ scsi_id);
+ if(inb(SBLKCTL + iobase) & 0x08)
+ /* B channel */
+ scsi_id += 8;
+ targ_scratch = inb(HA_TARG_SCRATCH + iobase
+ + scsi_id);
+ /* Preserve the WideXfer flag */
+ rate |= targ_scratch & 0x80;
+ outb(HA_TARG_SCRATCH + iobase + scsi_id, rate);
+ outb(SCSIRATE + iobase, rate);
+ /* See if we initiated Sync Negotiation */
+ needsdtr = (inb(HA_NEEDSDTR1 + iobase) << 8)
+ | inb(HA_NEEDSDTR0 + iobase);
+ if(needsdtr & (0x01 << scsi_id))
+ {
+ /*
+ * Negate the flag and don't send
+ * an SDTR back to the target
+ */
+ needsdtr &= ~(0x01 << scsi_id);
+ outb(HA_NEEDSDTR0 + iobase,
+ needsdtr & 0xff);
+ outb(HA_NEEDSDTR1 + iobase,
+ needsdtr >> 8);
+ outb(HA_RETURN_1 + iobase, 0);
+ }
+ else{
+ /*
+ * Send our own SDTR in reply
+ */
+ printf("Sending SDTR!!\n");
+ outb(HA_RETURN_1 + iobase, SEND_SDTR);
+ }
+ break;
+ }
+ case MSG_WDTR:
+ {
+ int loc;
+ u_short needwdtr;
+ u_char scsi_id, scratch, bus_width;
+
+ bus_width = inb(ACCUM + iobase);
+ scsi_id = inb(SCSIID + iobase) >> 0x4;
+ needwdtr = (inb(HA_NEEDWDTR1 + iobase) << 8)
+ | inb(HA_NEEDWDTR0 + iobase);
+
+ if(inb(SBLKCTL + iobase) & 0x08)
+ /* B channel */
+ scsi_id += 8;
+
+ printf("Recieved MSG_WDTR, scsi_id = %d, "
+ "needwdtr == 0x%x\n", scsi_id, needwdtr);
+
+ scratch = inb(HA_TARG_SCRATCH + iobase
+ + scsi_id);
+
+ if(needwdtr & (0x01 << scsi_id))
+ {
+ /*
+ * Negate the flag and don't
+ * send a WDTR back to the
+ * target, since we asked first.
+ */
+ needwdtr &= ~(0x01 << scsi_id);
+ outb(HA_NEEDWDTR0 + iobase,
+ needwdtr & 0xff);
+ outb(HA_NEEDWDTR1 + iobase,
+ needwdtr >> 8);
+ outb(HA_RETURN_1 + iobase, 0);
+ switch(bus_width)
+ {
+ case BUS_8_BIT:
+ scratch &= 0x7f;
+ break;
+ case BUS_16_BIT:
+ printf("ahc%d: target "
+ "%d using 16Bit "
+ "transfers\n",
+ unit, scsi_id);
+ scratch |= 0x88;
+ scratch &= 0xf8;
+ break;
+ }
+ }
+ else {
+ /*
+ * Send our own WDTR in reply
+ */
+ printf("Will Send WDTR!!\n");
+ switch(bus_width)
+ {
+ case BUS_8_BIT:
+ scratch &= 0x7f;
+ break;
+ case BUS_32_BIT:
+ /* Negotiate 16_BITS */
+ bus_width = BUS_16_BIT;
+ case BUS_16_BIT:
+ printf("ahc%d: target "
+ "%d using 16Bit "
+ "transfers\n",
+ unit, scsi_id);
+ scratch |= 0x88;
+ scratch &= 0xf8;
+ break;
+ }
+ outb(HA_RETURN_1 + iobase,
+ bus_width | SEND_WDTR);
+ }
+ outb(HA_TARG_SCRATCH + iobase + scsi_id, scratch);
+ outb(SCSIRATE + iobase, scratch);
+ break;
+ }
case BAD_STATUS:
{
int scb_index, saved_scb_index;
@@ -998,7 +963,7 @@ ahcintr(unit)
* without error.
*/
- scb_index = inb(SCBPTR + port);
+ scb_index = inb(SCBPTR + iobase);
scb = ahc->scbarray[scb_index];
if (!scb || !(scb->flags & SCB_ACTIVE)) {
printf("ahc%d: ahcintr - referenced scb not "
@@ -1009,7 +974,7 @@ ahcintr(unit)
xs = scb->xs;
- ahc_getscb(port, scb);
+ ahc_getscb(iobase, scb);
#ifdef AHCDEBUG
if(xs->sc_link->target == DEBUGTARG)
@@ -1033,9 +998,10 @@ ahcintr(unit)
,xs->sc_link->device->name
,xs->sc_link->dev_unit);
#endif
+
if((xs->error == XS_NOERROR) &&
!(scb->flags & SCB_SENSE)) {
-
+ u_char flags;
struct ahc_dma_seg *sg = scb->ahc_dma;
struct scsi_sense *sc = &(scb->sense_cmd);
u_char tcl = scb->target_channel_lun;
@@ -1048,7 +1014,7 @@ ahcintr(unit)
,xs->sc_link->device->name
,xs->sc_link->dev_unit);
#endif
- bzero(scb, SCB_SIZE);
+ bzero(scb, SCB_DOWN_SIZE);
scb->flags |= SCB_SENSE;
sc->op_code = REQUEST_SENSE;
sc->byte2 = xs->sc_link->lun << 5;
@@ -1066,11 +1032,15 @@ ahcintr(unit)
/*
* Download new command.
*/
- outb(SCBCNT + port, 0x80);
- outsb(SCBARRAY + port, scb, SCB_SIZE);
- outb(SCBCNT + port, 0);
-
- goto clear;
+ outb(SCBCNT + iobase, 0x80);
+ outsb(SCBARRAY+iobase,scb,SCB_DOWN_SIZE);
+ outb(SCBCNT + iobase, 0);
+ flags = inb(HA_FLAGS + iobase);
+ /*
+ * Have the sequencer handle the sense
+ * request
+ */
+ outb(HA_FLAGS + iobase, flags | SENSE);
}
/*
* Clear the SCB_SENSE Flag and have
@@ -1093,14 +1063,12 @@ ahcintr(unit)
xs->error = XS_DRIVER_STUFFUP;
break;
}
- seqaddr = inw(SEQADDR0 + port);
- outw(SEQADDR0 + port, seqaddr + 1);
break;
}
default:
printf("ahc: seqint, "
"intstat == 0x%x, scsisigi = 0x%x\n",
- intstat, inb(SCSISIGI + port));
+ intstat, inb(SCSISIGI + iobase));
break;
}
clear:
@@ -1108,7 +1076,7 @@ clear:
* Clear the upper byte that holds SEQINT status
* codes and clear the SEQINT bit.
*/
- outb(CLRINT + port, CLRSEQINT);
+ outb(CLRINT + iobase, CLRSEQINT);
/*
* The sequencer is paused immediately on
@@ -1121,17 +1089,17 @@ clear:
if (intstat & SCSIINT) {
- int scb_index = inb(SCBPTR + port);
- status = inb(SSTAT1 + port);
+ int scb_index = inb(SCBPTR + iobase);
+ status = inb(SSTAT1 + iobase);
scb = ahc->scbarray[scb_index];
if (!scb || !(scb->flags & SCB_ACTIVE)) {
printf("ahc%d: ahcintr - referenced scb not "
"valid during scsiint 0x%x scb(%d)\n",
unit, status, scb_index);
- outb(CLRSINT1 + port, status);
+ outb(CLRSINT1 + iobase, status);
UNPAUSE_SEQUENCER(ahc);
- outb(CLRINT + port, CLRINTSTAT);
+ outb(CLRINT + iobase, CLRINTSTAT);
scb = NULL;
goto cmdcomplete;
}
@@ -1139,14 +1107,16 @@ clear:
if (status & SELTO) {
u_char active;
- int active_port = HA_ACTIVE + port;
- outb(SCSISEQ + port, 0);
+ u_char flags;
+ u_long active_port = HA_ACTIVE0 + iobase;
+ outb(SCSISEQ + iobase, 0);
xs->error = XS_TIMEOUT;
/*
* Clear any pending messages for the timed out
* target, and mark the target as free
*/
- outb(HA_MSG_FLAGS + port, 0);
+ flags = inb( HA_FLAGS + iobase );
+ outb(HA_FLAGS + iobase, flags & ~ACTIVE_MSG);
if (scb->target_channel_lun & 0x88)
active_port++;
@@ -1155,10 +1125,10 @@ clear:
~(0x01 << (xs->sc_link->target & 0x07));
outb(active_port, active);
- outb(CLRSINT1 + port, CLRSELTIMEO);
+ outb(CLRSINT1 + iobase, CLRSELTIMEO);
RESTART_SEQUENCER(ahc);
- outb(CLRINT + port, CLRINTSTAT);
+ outb(CLRINT + iobase, CLRINTSTAT);
}
if (status & SCSIPERR) {
@@ -1169,10 +1139,10 @@ clear:
xs->sc_link->lun);
xs->error = XS_DRIVER_STUFFUP;
- outb(CLRSINT1 + port, CLRSCSIPERR);
+ outb(CLRSINT1 + iobase, CLRSCSIPERR);
UNPAUSE_SEQUENCER(ahc);
- outb(CLRINT + port, CLRINTSTAT);
+ outb(CLRINT + iobase, CLRINTSTAT);
scb = NULL;
}
if (status & BUSFREE) {
@@ -1183,16 +1153,16 @@ clear:
*/
printf("ahc: unexpected busfree\n");
xs->error = XS_DRIVER_STUFFUP;
- outb(CLRSINT1 + port, BUSFREE); /* CLRBUSFREE */
+ outb(CLRSINT1 + iobase, BUSFREE); /* CLRBUSFREE */
#endif
}
else {
printf("ahc%d: Unknown SCSIINT. Status = 0x%x\n",
unit, status);
- outb(CLRSINT1 + port, status);
+ outb(CLRSINT1 + iobase, status);
UNPAUSE_SEQUENCER(ahc);
- outb(CLRINT + port, CLRINTSTAT);
+ outb(CLRINT + iobase, CLRINTSTAT);
scb = NULL;
}
if(scb != NULL) {
@@ -1206,24 +1176,23 @@ cmdcomplete:
int scb_index, saved_scb_index;
do {
- scb_index = inb(QOUTFIFO + port);
+ scb_index = inb(QOUTFIFO + iobase);
scb = ahc->scbarray[scb_index];
if (!scb || !(scb->flags & SCB_ACTIVE)) {
printf("ahc%d: WARNING "
"no command for scb %d (cmdcmplt)\n"
"QOUTCNT == %d\n",
- unit, scb_index, inb(QOUTCNT + port));
- outb(CLRINT + port, CLRCMDINT);
+ unit, scb_index, inb(QOUTCNT + iobase));
+ outb(CLRINT + iobase, CLRCMDINT);
continue;
}
- outb(CLRINT+ port, CLRCMDINT);
+ outb(CLRINT + iobase, CLRCMDINT);
untimeout(ahc_timeout, (caddr_t)scb);
ahc_done(unit, scb);
- } while (inb(QOUTCNT + port));
+ } while (inb(QOUTCNT + iobase));
}
-
return 1;
}
@@ -1264,7 +1233,7 @@ ahc_init(unit)
int unit;
{
struct ahc_data *ahc = ahcdata[unit];
- int port = ahc->baseport;
+ u_long iobase = ahc->baseport;
int intdef, i;
/*
@@ -1274,41 +1243,58 @@ ahc_init(unit)
#ifdef AHCDEBUG
printf("ahc%d: scb %d bytes; SCB_SIZE %d bytes, ahc_dma %d bytes\n",
- unit, sizeof(struct scb), SCB_SIZE, sizeof(struct ahc_dma_seg));
+ unit, sizeof(struct scb), SCB_DOWN_SIZE, sizeof(struct ahc_dma_seg));
#endif /* AHCDEBUG */
printf("ahc%d: reading board settings\n", unit);
- outb(HCNTRL + port, CHIPRST);
+ outb(HCNTRL + iobase, CHIPRST);
switch( ahc->type ) {
case AHC_274:
- printf("ahc%d: 274x", unit);
+ printf("ahc%d: 274x ", unit);
ahc->unpause = UNPAUSE_274X;
ahc->maxscbs = 0x4;
break;
case AHC_284:
- printf("ahc%d: 284x", unit);
+ printf("ahc%d: 284x ", unit);
ahc->unpause = UNPAUSE_284X;
ahc->maxscbs = 0x4;
break;
+ case AHC_294:
+ printf("ahc%d: 294x ", unit);
+ ahc->unpause = UNPAUSE_274X;
+ ahc->maxscbs = 0x10;
+ #define DFTHRESH 3
+ outb(DSPCISTATUS + iobase, DFTHRESH << 6);
+ /* XXX Hard coded SCSI ID for now */
+ outb(HA_SCSICONF + iobase, 0x07 | (DFTHRESH << 6));
+ /* In case we are a wide card */
+ outb(HA_SCSICONF + 1 + iobase, 0x07);
+ break;
default:
};
- /* Determine channel configuration. */
- switch ( inb(SBLKCTL + port) ) {
+ /* Determine channel configuration and who we are on the scsi bus. */
+ switch ( inb(SBLKCTL + iobase) ) {
case 0:
- printf(" Single Channel, ");
- outb(HA_FLAGS + port, 0);
+ case 0xc0: /* 294x Adaptors have the top two bits set */
+ ahc->our_id = (inb(HA_SCSICONF + iobase) & HSCSIID);
+ printf("Single Channel, SCSI Id=%d, ", ahc->our_id);
+ outb(HA_FLAGS + iobase, CHECK_DTR);
break;
case 2:
- printf(" Wide SCSI configuration - Unsupported\n");
+ case 0xc2:
+ ahc->our_id = (inb(HA_SCSICONF + 1 + iobase) & HWSCSIID);
+ printf("Wide Channel, SCSI Id=%d, ", ahc->our_id);
ahc->type += 2;
- outb(HA_FLAGS + port, WIDE_BUS);
- return(-1);
+ outb(HA_FLAGS + iobase, WIDE_BUS|CHECK_DTR);
break;
case 8:
- printf(" Twin Channel, ");
+ ahc->our_id = (inb(HA_SCSICONF + iobase) & HSCSIID);
+ ahc->our_id_b = (inb(HA_SCSICONF + 1 + iobase) & HSCSIID);
+ printf("Twin Channel, A SCSI Id=%d, B SCSI Id=%d, ",
+ ahc->our_id, ahc->our_id_b);
ahc->type += 1;
- outb(HA_FLAGS + port, TWIN_BUS);
+ outb(HA_FLAGS + iobase, TWIN_BUS|CHECK_DTR);
break;
default:
printf(" Unsupported adapter type. Ignoring\n");
@@ -1317,38 +1303,41 @@ ahc_init(unit)
/* Number of SCBs that will be used. Supposedly some newer rev
* aic7770s have more than four so maybe we can detect this in
- * the future.
+ * the future. Aic7870s have 16 SCBs.
*/
- printf("%d SCBs, ", ahc->maxscbs);
+ printf("%d SCBs\n", ahc->maxscbs);
- intdef = inb(INTDEF + port);
- switch (intdef & 0xf) {
- case 9:
- ahc->vect = 9;
- break;
- case 10:
- ahc->vect = 10;
- break;
- case 11:
- ahc->vect = 11;
- break;
- case 12:
- ahc->vect = 12;
- break;
- case 14:
- ahc->vect = 14;
- break;
- case 15:
- ahc->vect = 15;
- break;
- default:
- printf("illegal irq setting\n");
- return (EIO);
- }
+ if(ahc->type < AHC_294){
+ /* The 294x cards are PCI, so we get their interrupt from the PCI
+ * BIOS. It doesn't look like the ISA mapped interrupt is reported
+ * correctly this way either.
+ */
- /* who are we on the scsi bus? */
- ahc->our_id = (inb(HA_SCSICONF + port) & HSCSIID);
- printf("SCSI Id=%d\n", ahc->our_id);
+ intdef = inb(INTDEF + iobase);
+ switch (intdef & 0xf) {
+ case 9:
+ ahc->vect = 9;
+ break;
+ case 10:
+ ahc->vect = 10;
+ break;
+ case 11:
+ ahc->vect = 11;
+ break;
+ case 12:
+ ahc->vect = 12;
+ break;
+ case 14:
+ ahc->vect = 14;
+ break;
+ case 15:
+ ahc->vect = 15;
+ break;
+ default:
+ printf("illegal irq setting\n");
+ return (EIO);
+ }
+ }
/*
* Load the Sequencer program and Enable the adapter.
@@ -1356,15 +1345,17 @@ ahc_init(unit)
* difference when doing many small block transfers.
*/
- printf("ahc%d: Downloading Sequencer Program\n", unit);
- ahc_loadseq(port);
- outb(SEQCTL + port, FASTMODE);
- outb(BCTL + port, ENABLE);
+ printf("ahc%d: Downloading Sequencer Program...", unit);
+ ahc_loadseq(iobase);
+ printf("Done\n");
+ outb(SEQCTL + iobase, FASTMODE);
+ if (ahc->type < AHC_294)
+ outb(BCTL + iobase, ENABLE);
/* Reset the SCSI bus. Is this necessary? */
- outb(SCSISEQ + port, SCSIRSTO);
+ outb(SCSISEQ + iobase, SCSIRSTO);
DELAY(500);
- outb(SCSISEQ + port, 0);
+ outb(SCSISEQ + iobase, 0);
/*
* Look at the information that board initialization or
@@ -1376,27 +1367,45 @@ ahc_init(unit)
* flag.
*/
ahc->needsdtr = 0;
+ ahc->needwdtr = 0;
for(i = 0; i < 16; i++){
- u_char target_settings = inb(HA_TARG_SCRATCH + i + port);
- if(target_settings & 0x0f)
+ u_char target_settings = inb(HA_TARG_SCRATCH + i + iobase);
+ if(target_settings & 0x0f){
ahc->needsdtr |= (0x01 << i);
+ /* Default to a syncrounous offset of 15 */
+ target_settings |= 0x0f;
+ }
+ if(target_settings & 0x80){
+ ahc->needwdtr |= (0x01 << i);
+ /*
+ * We'll set the Wide flag when we
+ * are successful with Wide negotiation,
+ * so turn it off for now so we aren't
+ * confused.
+ */
+ target_settings &= 0x7f;
+ }
+ outb(HA_TARG_SCRATCH+i+iobase,target_settings);
}
- outw( HA_NEEDSDTR + port, ahc->needsdtr );
+ outb( HA_NEEDSDTR0 + iobase, ahc->needsdtr & 0xff);
+ outb( HA_NEEDSDTR1 + iobase, ahc->needsdtr >> 8);
+ outb( HA_NEEDWDTR0 + iobase, ahc->needwdtr & 0xff);
+ outb( HA_NEEDWDTR1 + iobase, ahc->needwdtr >> 8);
/*
- * Clear the pending messages flag
+ * Set the number of availible SCBs
*/
- outb( HA_MSG_FLAGS + port, 0);
- outb( HA_SCBCOUNT + port, ahc->maxscbs);
+ outb(HA_SCBCOUNT + iobase, ahc->maxscbs);
/* We don't have any busy targets right now */
- outw( HA_ACTIVE + port, 0 );
+ outb( HA_ACTIVE0 + iobase, 0 );
+ outb( HA_ACTIVE1 + iobase, 0 );
UNPAUSE_SEQUENCER(ahc);
/*
* Note that we are going and return (to probe)
*/
- ahc->flags |= AHC_INIT;
+ ahc->flags = AHC_INIT;
return (0);
}
@@ -1404,7 +1413,8 @@ void
ahcminphys(bp)
struct buf *bp;
{
-/* Even though the card can transfer up to 16megs per command
+/*
+ * 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
@@ -1433,7 +1443,17 @@ ahc_scsi_cmd(xs)
int bytes_this_seg, bytes_this_page, datalen, flags;
struct ahc_data *ahc = ahcdata[unit];
int s;
-
+
+ /*
+ *Set a flag that states, yes, we can receive interrupts
+ * the reason for doing this is that we have a choice of
+ * edge or level sensitive interrupts, and if we have the
+ * wrong type, we'll get spurrious interrupts. We check
+ * this flag in the interrupt handler and toggle to the
+ * other type if need be.
+ */
+ ahc->flags = AHC_RUNNING;
+
SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahc_scsi_cmd\n"));
/*
* get an scb to use. If the transfer
@@ -1567,11 +1587,10 @@ ahc_scsi_cmd(xs)
if (!(xs->flags & SCSI_SILENT))
printf("cmd fail\n");
printf("cmd fail\n");
- printf("Abort called. Someone implement me please!\n");
- xs->error = XS_DRIVER_STUFFUP;
+ ahc_abort_scb(unit,ahc,scb);
return (HAD_ERROR);
}
- } while (!(xs->flags & ITSDONE)); /* something (?) else finished */
+ } while (!(xs->flags & ITSDONE)); /* a non command complete intr */
if (xs->error) {
return (HAD_ERROR);
}
@@ -1680,23 +1699,23 @@ gottit: if (!(flags & SCSI_NOMASK))
return (scbp);
}
-void ahc_loadseq(port)
- int port;
+void ahc_loadseq(iobase)
+ u_long iobase;
{
static unsigned char seqprog[] = {
-# include "aic7770_seq.h"
+# include "aic7xxx_seq.h"
};
- outb(SEQCTL + port, PERRORDIS|SEQRESET|LOADRAM);
+ outb(SEQCTL + iobase, PERRORDIS|SEQRESET|LOADRAM);
- outsb(SEQRAM + port, seqprog, sizeof(seqprog));
+ outsb(SEQRAM + iobase, seqprog, sizeof(seqprog));
- outb(SEQCTL + port, 0);
+ outb(SEQCTL + iobase, FASTMODE|SEQRESET);
do {
- /* XXX Need a timer here? */
- outb(SEQCTL + port, SEQRESET);
+ outb(SEQCTL + iobase, SEQRESET|FASTMODE);
- } while (inw(SEQADDR0 + port) != 0);
+ } while (inb(SEQADDR0 + iobase) != 0 &&
+ inb(SEQADDR1 + iobase != 0));
}
/*
@@ -1705,9 +1724,9 @@ void ahc_loadseq(port)
int
ahc_poll(int unit, int wait)
{ /* in msec */
- struct ahc_data *ahc = ahcdata[unit];
- int port = ahc->baseport;
- int stport = INTSTAT + port;
+ struct ahc_data *ahc = ahcdata[unit];
+ u_long iobase = ahc->baseport;
+ u_long stport = INTSTAT + iobase;
retry:
while (--wait) {
@@ -1728,9 +1747,10 @@ ahc_abort_scb( unit, ahc, scb )
struct ahc_data *ahc;
struct scb *scb;
{
- int port = ahc->baseport;
+ u_long iobase = ahc->baseport;
int found = 0;
int active_scb;
+ u_char flags;
PAUSE_SEQUENCER(ahc);
/*
@@ -1739,10 +1759,10 @@ ahc_abort_scb( unit, ahc, scb )
{
int saved_queue[AHC_SCB_MAX];
int i;
- int queued = inb(QINCNT + port);
+ int queued = inb(QINCNT + iobase);
for( i = 0; i < (queued - found); i++){
- saved_queue[i] = inb(QINFIFO + port);
+ saved_queue[i] = inb(QINFIFO + iobase);
if( saved_queue[i] == scb->position ){
i--;
found = 1;
@@ -1750,14 +1770,14 @@ ahc_abort_scb( unit, ahc, scb )
}
/* Re-insert entries back into the queue */
for( queued = 0; queued < i; queued++ )
- outb(QINFIFO + port, saved_queue[queued]);
+ outb(QINFIFO + iobase, saved_queue[queued]);
if( found ){
goto done;
}
}
- active_scb = inb(SCBPTR + port);
+ active_scb = inb(SCBPTR + iobase);
/*
* Case 2: Not the active command
*/
@@ -1769,36 +1789,44 @@ ahc_abort_scb( unit, ahc, scb )
* and notify us of the abort.
*/
int scb_control;
- outb(SCBPTR + port, scb->position);
- scb_control = inb(SCBARRAY + port);
+ outb(SCBPTR + iobase, scb->position);
+ scb_control = inb(SCBARRAY + iobase);
scb_control &= ~SCB_DIS;
- outb(SCBARRAY + port, scb_control);
- outb(SCBPTR + port, active_scb);
+ outb(SCBARRAY + iobase, scb_control);
+ outb(SCBPTR + iobase, active_scb);
goto done;
}
/*
* Case 3: Currently active command
*/
- if (inb(HA_MSG_FLAGS + port) & 0x80) {
+ if ( (flags = inb(HA_FLAGS + iobase)) & ACTIVE_MSG) {
/*
* If there's a message in progress,
* reset the bus and have all devices renegotiate.
*/
+ u_char flags;
if(scb->target_channel_lun & 0x08){
- outb(HA_NEEDSDTR + 1 + port, ahc->needsdtr >> 8);
- outb(HA_ACTIVE + 1, 0);
+ outb(HA_NEEDSDTR1 + iobase, ahc->needsdtr >> 8);
+ outb(HA_ACTIVE1, 0);
}
- else if (ahc->type == AHC_274W || ahc->type == AHC_284W){
- outw(HA_NEEDSDTR, ahc->needsdtr);
- outw(HA_ACTIVE, 0);
+ else if (ahc->type == AHC_274W || ahc->type == AHC_284W
+ || ahc->type == AHC_294W){
+ outb(HA_NEEDSDTR0, ahc->needsdtr & 0xff);
+ outb(HA_NEEDSDTR1, ahc->needsdtr >> 8);
+ outb(HA_NEEDWDTR0, ahc->needwdtr & 0xff);
+ outb(HA_NEEDWDTR1, ahc->needwdtr >> 8);
+ outb(HA_ACTIVE0, 0);
+ outb(HA_ACTIVE1, 0);
}
else{
- outb(HA_NEEDSDTR + port, ahc->needsdtr & 0xff);
- outb(HA_ACTIVE, 0);
+ outb(HA_NEEDSDTR0 + iobase, ahc->needsdtr & 0xff);
+ outb(HA_ACTIVE0, 0);
}
- outb(SCSISEQ + port, SCSIRSTO);
+ flags = inb(HA_FLAGS + iobase);
+ outb(HA_FLAGS + iobase, flags | CHECK_DTR);
+ outb(SCSISEQ + iobase, SCSIRSTO);
DELAY(50);
- outb(SCSISEQ + port, 0);
+ outb(SCSISEQ + iobase, 0);
goto done;
}
@@ -1806,11 +1834,11 @@ ahc_abort_scb( unit, ahc, scb )
* Otherwise, set up an abort message and have the sequencer
* clean up
*/
- outb(HA_MSG_FLAGS + port, 0x80);
- outb(HA_MSG_LEN + port, 1);
- outb(HA_MSG_START + port, MSG_ABORT);
+ outb(HA_FLAGS + iobase, flags | ACTIVE_MSG);
+ outb(HA_MSG_LEN + iobase, 1);
+ outb(HA_MSG_START + iobase, MSG_ABORT);
- outb(SCSISIGO + port, inb(HA_SIGSTATE + port) | 0x10);
+ outb(SCSISIGO + iobase, inb(HA_SIGSTATE + iobase) | 0x10);
done:
scb->flags |= SCB_ABORTED;
@@ -1823,7 +1851,7 @@ void
ahc_timeout(void *arg1)
{
struct scb *scb = (struct scb *)arg1;
- int unit, cur_scb_offset, port;
+ int unit, cur_scb_offset;
struct ahc_data *ahc;
int s = splbio();
diff --git a/sys/i386/scsi/aic7xxx.h b/sys/i386/scsi/aic7xxx.h
new file mode 100644
index 0000000..23fa9bc
--- /dev/null
+++ b/sys/i386/scsi/aic7xxx.h
@@ -0,0 +1,142 @@
+/*
+ * 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, 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.
+ */
+
+#ifndef _AIC7XXX_H_
+#define _AIC7XXX_H_
+
+#include "ahc.h" /* for NAHC from config */
+
+#define AHC_NSEG 256 /* number of dma segments supported */
+
+#define AHC_SCB_MAX 16 /*
+ * Up to 16 SCBs on some types of aic7xxx based
+ * boards. The aic7770 family only have 4
+ */
+
+/* #define AHCDEBUG */
+
+typedef unsigned long int physaddr;
+extern int ahc_unit;
+
+struct ahc_dma_seg {
+ physaddr addr;
+ long len;
+};
+
+typedef enum {
+ AHC_274, /* Single Channel */
+ AHC_274T, /* Twin Channel */
+ AHC_274W, /* Wide Channel */
+ AHC_284, /* VL Single Channel */
+ AHC_284T, /* VL Twin Channel */
+ AHC_284W, /* VL Wide Channel - Do these exist?? */
+ AHC_294, /* PCI Single Channel */
+ AHC_294T, /* PCI Twin Channel */
+ AHC_294W /* PCI Wide Channel */
+}ahc_type;
+
+/*
+ * The driver keeps up to four scb structures per card in memory. Only the
+ * first 26 bytes of the structure are valid for the hardware, the rest used
+ * for driver level bookeeping. The "__attribute ((packed))" tags ensure that
+ * gcc does not attempt to pad the long ints in the structure to word
+ * boundaries since the first 26 bytes of this structure must have the correct
+ * offsets for the hardware to find them. The driver is further optimized
+ * so that we only have to download the first 19 bytes since as long
+ * as we always use S/G, the last fields should be zero anyway.
+ */
+struct scb {
+/* ------------ Begin hardware supported fields ---------------- */
+/*1*/ u_char control;
+#define SCB_REJ_MDP 0x80 /* Reject MDP message */
+#define SCB_DCE 0x40 /* Disconnect enable */
+#define SCB_TE 0x20 /* Tag enable */
+#define SCB_WAITING 0x06
+#define SCB_DIS 0x04
+#define SCB_TAG_TYPE 0x3
+#define SIMPLE_QUEUE 0x0
+#define HEAD_QUEUE 0x1
+#define OR_QUEUE 0x2
+/*2*/ u_char target_channel_lun; /* 4/1/3 bits */
+/*3*/ u_char SG_segment_count;
+/*7*/ physaddr SG_list_pointer __attribute__ ((packed));
+/*11*/ physaddr cmdpointer __attribute__ ((packed));
+/*12*/ u_char cmdlen;
+/*14*/ u_char RESERVED[2]; /* must be zero */
+/*15*/ u_char target_status;
+/*18*/ u_char residual_data_count[3];
+/*19*/ u_char residual_SG_segment_count;
+#define SCB_DOWN_SIZE 26 /* amount to actually download */
+/*23*/ physaddr data __attribute__ ((packed));
+/*26*/ u_char datalen[3];
+#define SCB_UP_SIZE 26 /* amount to actually upload */
+#if 0
+ /*
+ * No real point in transferring this to the
+ * SCB registers.
+ */
+ unsigned char RESERVED[6];
+#endif
+ /*-----------------end of hardware supported fields----------------*/
+ struct scb *next; /* in free list */
+ struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
+ int flags;
+#define SCB_FREE 0x00
+#define SCB_ACTIVE 0x01
+#define SCB_ABORTED 0x02
+#define SCB_IMMED 0x04
+#define SCB_IMMED_FAIL 0x08
+#define SCB_SENSE 0x10
+ int position; /* Position in scbarray */
+ struct ahc_dma_seg ahc_dma[AHC_NSEG] __attribute__ ((packed));
+ struct scsi_sense sense_cmd; /* SCSI command block */
+};
+
+struct ahc_data {
+ ahc_type type;
+ int flags;
+#define AHC_INIT 0x01
+#define AHC_RUNNING 0x02
+ u_long baseport;
+ struct scb *scbarray[AHC_SCB_MAX]; /* Mirror boards scbarray */
+ struct scb *free_scb;
+ int our_id; /* our scsi id */
+ int our_id_b; /* B channel scsi id */
+ int vect;
+ struct scb *immed_ecb; /* an outstanding immediete command */
+ struct scsi_link sc_link;
+ struct scsi_link sc_link_b; /* Second bus for Twin channel cards */
+ u_short needsdtr; /* Targets we initiate sync neg with */
+ u_short needwdtr; /* Targets we initiate wide neg with */
+ int numscbs;
+ u_char maxscbs;
+ int unpause;
+};
+
+extern struct ahc_data *ahcdata[NAHC];
+
+int ahcprobe __P((int unit, u_long io_base, ahc_type type));
+int ahc_attach __P((int unit));
+int ahcintr();
+
+#endif /* _AIC7XXX_H_ */
OpenPOWER on IntegriCloud