summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1996-10-06 16:38:45 +0000
committergibbs <gibbs@FreeBSD.org>1996-10-06 16:38:45 +0000
commit39f7c443bbd76efad82b8db4e30b4e321c972e56 (patch)
treebb2a2dd6b395ce14a39949957308cc784a27b63a
parent5afa2e19b158c07804a73b685e7a539a7377f53a (diff)
downloadFreeBSD-src-39f7c443bbd76efad82b8db4e30b4e321c972e56.zip
FreeBSD-src-39f7c443bbd76efad82b8db4e30b4e321c972e56.tar.gz
Bring aic7xxx driver bug fixes from 'SCSI' into current.
-rw-r--r--sys/dev/aic7xxx/aic7xxx.seq193
-rw-r--r--sys/dev/aic7xxx/aic7xxx_reg.h42
-rw-r--r--sys/i386/eisa/aic7770.c16
-rw-r--r--sys/i386/scsi/aic7xxx.c1824
-rw-r--r--sys/i386/scsi/aic7xxx.h37
-rw-r--r--sys/pci/aic7870.c24
6 files changed, 1058 insertions, 1078 deletions
diff --git a/sys/dev/aic7xxx/aic7xxx.seq b/sys/dev/aic7xxx/aic7xxx.seq
index 36ff790..f67069d 100644
--- a/sys/dev/aic7xxx/aic7xxx.seq
+++ b/sys/dev/aic7xxx/aic7xxx.seq
@@ -39,12 +39,14 @@
*
*-M************************************************************************/
-VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.41 1996/06/08 06:54:06 gibbs Exp $"
+VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.42 1996/06/09 17:29:11 gibbs Exp $"
#if defined(__NetBSD__)
#include "../../../../dev/ic/aic7xxxreg.h"
+#include "../../../../scsi/scsi_message.h"
#elif defined(__FreeBSD__)
#include "../../dev/aic7xxx/aic7xxx_reg.h"
+#include "../../scsi/scsi_message.h"
#endif
/*
@@ -186,45 +188,36 @@ start_selection:
* Messages are stored in scratch RAM starting with a length byte
* followed by the message itself.
*/
- test SCB_CMDLEN,0xff jnz mk_identify /* 0 Length Command? */
-
-/*
- * The kernel has sent us an SCB with no command attached. This implies
- * that the kernel wants to send a message of some sort to this target,
- * so we interrupt the driver, allow it to fill the message buffer, and
- * then go back into the arbitration loop
- */
- mvi INTSTAT,AWAITING_MSG
- jmp wait_for_selection
mk_identify:
and A,DISCENB,SCB_CONTROL /* mask off disconnect privledge */
and MSG0,0x7,SCB_TCL /* lun */
or MSG0,A /* or in disconnect privledge */
- or MSG0,MSG_IDENTIFY
+ or MSG0,MSG_IDENTIFYFLAG
mvi MSG_LEN, 1
- test SCB_CONTROL,0xb0 jz !message /* WDTR, SDTR or TAG?? */
/*
* Send a tag message if TAG_ENB is set in the SCB control block.
* Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
*/
-
mk_tag:
+ test SCB_CONTROL,TAG_ENB jz mk_message
mvi DINDEX, MSG1
- test SCB_CONTROL,TAG_ENB jz mk_tag_done
and DINDIR,0x23,SCB_CONTROL
mov DINDIR,SCB_TAG
add MSG_LEN,COMP_MSG0,DINDEX /* update message length */
-mk_tag_done:
+/*
+ * Interrupt the driver, and allow it to tweak the message buffer
+ * if it asks.
+ */
+mk_message:
+ test SCB_CONTROL,MK_MESSAGE jz wait_for_selection
- test SCB_CONTROL,0x90 jz !message /* NEEDWDTR|NEEDSDTR */
- mov DINDEX call mk_dtr /* build DTR message if needed */
+ mvi INTSTAT,AWAITING_MSG
-!message:
wait_for_selection:
test SSTAT0,SELDO jnz select
test SSTAT0,SELDI jz wait_for_selection
@@ -511,7 +504,7 @@ p_status:
*/
p_mesgout:
test MSG_LEN, 0xff jnz p_mesgout_start
- mvi MSG_NOP call mk_mesg /* build NOP message */
+ mvi MSG_NOOP call mk_mesg /* build NOP message */
p_mesgout_start:
/*
@@ -569,13 +562,13 @@ p_mesgin:
mvi A call inb_first /* read the 1st message byte */
mov REJBYTE,A /* save it for the driver */
- test A,MSG_IDENTIFY jnz mesgin_identify
+ test A,MSG_IDENTIFYFLAG jnz mesgin_identify
cmp A,MSG_DISCONNECT je mesgin_disconnect
- cmp A,MSG_SDPTRS je mesgin_sdptrs
+ cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs
cmp ALLZEROS,A je mesgin_complete
- cmp A,MSG_RDPTRS je mesgin_rdptrs
+ cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs
cmp A,MSG_EXTENDED je mesgin_extended
- cmp A,MSG_REJECT je mesgin_reject
+ cmp A,MSG_MESSAGE_REJECT je mesgin_reject
rej_mesgin:
/*
@@ -589,7 +582,7 @@ rej_mesgin:
or SCSISIGO,ATNO /* turn on ATNO */
mvi INTSTAT,SEND_REJECT /* let driver know */
- mvi MSG_REJECT call mk_mesg
+ mvi MSG_MESSAGE_REJECT call mk_mesg
mesgin_done:
call inb_last /*ack & turn auto PIO back on*/
@@ -665,51 +658,38 @@ complete:
/*
- * Is it an extended message? We only support the synchronous and wide data
- * transfer request messages, which will probably be in response to
- * WDTR or SDTR message outs from us. If it's not SDTR or WDTR, reject it -
- * apparently this can be done after any message in byte, according
- * to the SCSI-2 spec.
+ * Is it an extended message? Copy the message to our message buffer and
+ * notify the host. The host will tell us whether to reject this message,
+ * respond to it with the message that the host placed in our message buffer,
+ * or simply to do nothing.
*/
mesgin_extended:
- mvi ARG_1 call inb_next /* extended message length */
- mvi REJBYTE_EXT call inb_next /* extended message code */
-
- cmp REJBYTE_EXT,MSG_SDTR je p_mesginSDTR
- cmp REJBYTE_EXT,MSG_WDTR je p_mesginWDTR
- jmp rej_mesgin
-
-p_mesginWDTR:
- cmp ARG_1,2 jne rej_mesgin /* extended mesg length=2 */
- mvi ARG_1 call inb_next /* Width of bus */
- mvi INTSTAT,WDTR_MSG /* let driver know */
- test RETURN_1,0xff jz mesgin_done /* Do we need to send WDTR? */
- cmp RETURN_1,SEND_REJ je rej_mesgin /*
- * Bus width was too large
- * Reject it.
- */
-
-/* We didn't initiate the wide negotiation, so we must respond to the request */
- and RETURN_1,0x7f /* Clear the SEND_WDTR Flag */
- mvi DINDEX,MSG0
- mvi MSG0 call mk_wdtr /* build WDTR message */
- or SCSISIGO,ATNO /* turn on ATNO */
- jmp mesgin_done
-
-p_mesginSDTR:
- cmp ARG_1,3 jne rej_mesgin /* extended mesg length=3 */
- mvi ARG_1 call inb_next /* xfer period */
- mvi A call inb_next /* REQ/ACK offset */
- mvi INTSTAT,SDTR_MSG /* call driver to convert */
-
- test RETURN_1,0xff jz mesgin_done /* Do we need to mk_sdtr/rej */
- cmp RETURN_1,SEND_REJ je rej_mesgin /*
- * Requested SDTR too small
- * Reject it.
- */
- clr ARG_1 /* Use the scratch ram rate */
- mvi DINDEX, MSG0
- mvi MSG0 call mk_sdtr
+ mvi MSGIN_EXT_LEN call inb_next
+ mvi MSGIN_EXT_OPCODE call inb_next
+ mov A, MSGIN_EXT_LEN
+ dec A /* Length counts the op code */
+ mvi SINDEX, MSGIN_EXT_BYTE0
+mesgin_extended_loop:
+ test A, 0xFF jz mesgin_extended_intr
+ cmp SINDEX, MSGIN_EXT_LASTBYTE je mesgin_extended_dump
+ call inb_next
+ dec A
+/*
+ * We pass the arg to inb in SINDEX, but DINDEX is the one incremented
+ * so update SINDEX with DINDEX's value before looping again.
+ */
+ mov DINDEX jmp mesgin_extended_loop
+mesgin_extended_dump:
+/* We have no more storage space, so dump the rest */
+ test A, 0xFF jz mesgin_extended_intr
+ mvi NONE call inb_next
+ dec A
+ jmp mesgin_extended_dump
+mesgin_extended_intr:
+ mvi INTSTAT,EXTENDED_MSG /* let driver know */
+ cmp RETURN_1,SEND_REJ je rej_mesgin
+ cmp RETURN_1,SEND_MSG jne mesgin_done
+/* The kernel has setup a message to be sent */
or SCSISIGO,ATNO /* turn on ATNO */
jmp mesgin_done
@@ -783,11 +763,11 @@ mesgin_identify:
*/
mvi ARG_1,SCB_LIST_NULL /* Default to no-tag */
snoop_tag_loop:
- test SSTAT1,BUSFREE jnz use_findSCB
- test SSTAT1,REQINIT jz snoop_tag_loop
- test SSTAT1,PHASEMIS jnz use_findSCB
- mvi A call inb_first
- cmp A,MSG_SIMPLE_TAG jne use_findSCB
+ test SSTAT1,BUSFREE jnz use_findSCB
+ test SSTAT1,REQINIT jz snoop_tag_loop
+ test SSTAT1,PHASEMIS jnz use_findSCB
+ mvi A call inb_first
+ cmp A,MSG_SIMPLE_Q_TAG jne use_findSCB
get_tag:
mvi ARG_1 call inb_next /* tag value */
/*
@@ -947,7 +927,7 @@ dma5:
and DFCNTRL,WIDEODD
dma6:
test DFCNTRL,0x38 jnz dma6 /* SCSIENACK|SDMAENACK|HDMAENACK */
-
+return:
ret
/*
@@ -1087,68 +1067,3 @@ ndx_dtr:
or A,0x08 /* Channel B entries add 8 */
ndx_dtr_2:
add SINDEX,TARG_SCRATCH,A ret
-
-/*
- * If we need to negotiate transfer parameters, build the WDTR or SDTR message
- * starting at the address passed in SINDEX. DINDEX is modified on return.
- * The SCSI-II spec requires that Wide negotiation occur first and you can
- * only negotiat one or the other at a time otherwise in the event of a message
- * reject, you wouldn't be able to tell which message was the culpret.
- */
-mk_dtr:
- test SCB_CONTROL,NEEDWDTR jnz mk_wdtr_16bit
- mvi ARG_1, MAXOFFSET /* Force an offset of 15 or 8 if WIDE */
-
-mk_sdtr:
- mvi DINDIR,1 /* extended message */
- mvi DINDIR,3 /* extended message length = 3 */
- mvi DINDIR,1 /* SDTR code */
- call sdtr_to_rate
- mov DINDIR,RETURN_1 /* REQ/ACK transfer period */
- cmp ARG_1, MAXOFFSET je mk_sdtr_max_offset
- and DINDIR,0x0f,SINDIR /* Sync Offset */
-
-mk_sdtr_done:
- add MSG_LEN,COMP_MSG0,DINDEX ret /* update message length */
-
-mk_sdtr_max_offset:
-/*
- * We're initiating sync negotiation, so request the max offset we can (15 or 8)
- */
- /* Talking to a WIDE device? */
- test SCSIRATE, WIDEXFER jnz wmax_offset
- mvi DINDIR, MAX_OFFSET_8BIT
- jmp mk_sdtr_done
-
-wmax_offset:
- mvi DINDIR, MAX_OFFSET_16BIT
- jmp mk_sdtr_done
-
-mk_wdtr_16bit:
- mvi ARG_1,BUS_16_BIT
-mk_wdtr:
- mvi DINDIR,1 /* extended message */
- mvi DINDIR,2 /* extended message length = 2 */
- mvi DINDIR,3 /* WDTR code */
- mov DINDIR,ARG_1 /* bus width */
-
- add MSG_LEN,COMP_MSG0,DINDEX ret /* update message length */
-
-sdtr_to_rate:
- call ndx_dtr /* index scratch space for target */
- shr A,SINDIR,0x4
- dec SINDEX /* Preserve SINDEX */
- and A,0x7
- clr RETURN_1
-sdtr_to_rate_loop:
- test A,0x0f jz sdtr_to_rate_done
- add RETURN_1,0x19
- dec A
- jmp sdtr_to_rate_loop
-sdtr_to_rate_done:
- shr RETURN_1,0x2
- add RETURN_1,0x19
- test SXFRCTL0,ULTRAEN jz return
- shr RETURN_1,0x1
-return:
- ret
diff --git a/sys/dev/aic7xxx/aic7xxx_reg.h b/sys/dev/aic7xxx/aic7xxx_reg.h
index b9cd5d2..c4c9ad4 100644
--- a/sys/dev/aic7xxx/aic7xxx_reg.h
+++ b/sys/dev/aic7xxx/aic7xxx_reg.h
@@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: aic7xxx_reg.h,v 1.11 1996/05/21 18:32:23 gibbs Exp $
+ * $Id: aic7xxx_reg.h,v 1.12 1996/06/09 17:29:12 gibbs Exp $
*/
/*
@@ -407,8 +407,7 @@
#define SEND_REJECT 0x11 /* sending a message reject */
#define NO_IDENT 0x21 /* no IDENTIFY after reconnect*/
#define NO_MATCH 0x31 /* no cmd match for reconnect */
-#define SDTR_MSG 0x41 /* SDTR message received */
-#define WDTR_MSG 0x51 /* WDTR message received */
+#define EXTENDED_MSG 0x41 /* Extended message received */
#define REJECT_MSG 0x61 /* Reject message received */
#define BAD_STATUS 0x71 /* Bad status from target */
#define RESIDUAL 0x81 /* Residual byte count != 0 */
@@ -527,10 +526,9 @@
*/
#define SCBARRAY 0x0a0
#define SCB_CONTROL 0x0a0
-#define NEEDWDTR 0x80
+#define MK_MESSAGE 0x80
#define DISCENB 0x40
#define TAG_ENB 0x20
-#define NEEDSDTR 0x10
#define DISCONNECTED 0x04
#define SCB_TAG_TYPE 0x03
#define SCB_TCL 0x0a1
@@ -682,10 +680,8 @@
*/
#define LASTPHASE 0x03d
#define ARG_1 0x03e
-#define MAXOFFSET 0x01
#define RETURN_1 0x03f
-#define SEND_WDTR 0x80
-#define SEND_SDTR 0x60
+#define SEND_MSG 0x80
#define SEND_SENSE 0x40
#define SEND_REJ 0x20
#define SCB_PAGEDIN 0x10
@@ -747,6 +743,19 @@
#define ULTRA_ENB 0x052
#define ULTRA_ENB_B 0x053
+#define MSGIN_EXT_LEN 0x054
+#define MSGIN_EXT_OPCODE 0x055
+#define MSGIN_EXT_BYTE0 0x056
+#define MSGIN_EXT_BYTE1 0x057
+#define MSGIN_EXT_LASTBYTE 0x058 /*
+ * We don't use this location, but
+ * continue to store bytes until
+ * we reach this address (avoids
+ * a more complicated compare).
+ * So, we can store at most 2
+ * bytes for now.
+ */
+
#define SCSICONF 0x05a
#define RESET_SCSI 0x40
@@ -757,23 +766,6 @@
#define BIOSDISABLED 0x30
#define CHANNEL_B_PRIMARY 0x08
-/* Message codes */
-#define MSG_EXTENDED 0x01
-#define MSG_SDTR 0x01
-#define MSG_WDTR 0x03
-#define MSG_SDPTRS 0x02
-#define MSG_RDPTRS 0x03
-#define MSG_DISCONNECT 0x04
-#define MSG_INITIATOR_DET_ERROR 0x05
-#define MSG_ABORT 0x06
-#define MSG_REJECT 0x07
-#define MSG_NOP 0x08
-#define MSG_MSG_PARITY_ERROR 0x09
-#define MSG_BUS_DEVICE_RESET 0x0c
-#define MSG_ABORT_TAG 0x0d
-#define MSG_SIMPLE_TAG 0x20
-#define MSG_IDENTIFY 0x80
-
/* WDTR Message values */
#define BUS_8_BIT 0x00
#define BUS_16_BIT 0x01
diff --git a/sys/i386/eisa/aic7770.c b/sys/i386/eisa/aic7770.c
index 51933ab..9a2f646f 100644
--- a/sys/i386/eisa/aic7770.c
+++ b/sys/i386/eisa/aic7770.c
@@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: aic7770.c,v 1.30 1996/08/28 18:00:25 bde Exp $
+ * $Id: aic7770.c,v 1.31 1996/09/06 23:06:55 phk Exp $
*/
#if defined(__FreeBSD__)
@@ -133,24 +133,14 @@ aic7770probe(void)
eisa_add_iospace(e_dev, iobase, AHC_EISA_IOSIZE, RESVADDR_NONE);
intdef = inb(INTDEF + iobase);
- switch (intdef & 0xf) {
+ irq = intdef & 0xf;
+ switch (irq) {
case 9:
- irq = 9;
- break;
case 10:
- irq = 10;
- break;
case 11:
- irq = 11;
- break;
case 12:
- irq = 12;
- break;
case 14:
- irq = 14;
- break;
case 15:
- irq = 15;
break;
default:
printf("aic7770 at slot %d: illegal "
diff --git a/sys/i386/scsi/aic7xxx.c b/sys/i386/scsi/aic7xxx.c
index c678fa6..e4c648a 100644
--- a/sys/i386/scsi/aic7xxx.c
+++ b/sys/i386/scsi/aic7xxx.c
@@ -31,7 +31,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: aic7xxx.c,v 1.75 1996/06/23 20:02:37 gibbs Exp $
+ * $Id: aic7xxx.c,v 1.76 1996/10/01 03:01:06 pst Exp $
*/
/*
* TODO:
@@ -126,6 +126,7 @@
#include <sys/proc.h>
#include <scsi/scsi_all.h>
+#include <scsi/scsi_message.h>
#if defined(__NetBSD__)
#include <scsi/scsi_debug.h>
#endif
@@ -155,7 +156,7 @@
#define DEBUGTARG DEBUGTARGET
#if DEBUGTARG < 0 /* Negative numbrs for disabling cause warnings */
#undef DEBUGTARG
-#define DEBUGTARG 9
+#define DEBUGTARG 17
#endif
#endif /* defined(__NetBSD__) */
@@ -190,6 +191,10 @@ int ahc_broken_cache = 1;
static void ahcminphys __P((struct buf *bp));
static int32_t ahc_scsi_cmd __P((struct scsi_xfer *xs));
+static inline void pause_sequencer __P((struct ahc_data *ahc));
+static inline void unpause_sequencer __P((struct ahc_data *ahc,
+ int unpause_always));
+static inline void restart_sequencer __P((struct ahc_data *ahc));
static struct scsi_adapter ahc_switch =
{
@@ -218,30 +223,44 @@ static struct scsi_device ahc_dev =
#endif
};
-/*
- * Since the sequencer can disable pausing in a critical section, we
- * must loop until it actually stops.
- * XXX Should add a timeout in here??
- */
-#define PAUSE_SEQUENCER(ahc) \
- AHC_OUTB(ahc, HCNTRL, ahc->pause); \
- \
- while ((AHC_INB(ahc, HCNTRL) & PAUSE) == 0) \
+static inline void
+pause_sequencer(ahc)
+ struct ahc_data *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)
;
+}
-#define UNPAUSE_SEQUENCER(ahc) \
- AHC_OUTB(ahc, HCNTRL, ahc->unpause )
+static inline void
+unpause_sequencer(ahc, unpause_always)
+ struct ahc_data *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
*/
-#define RESTART_SEQUENCER(ahc) \
- do { \
- AHC_OUTB(ahc, SEQCTL, SEQRESET|FASTMODE); \
- } while((AHC_INB(ahc, SEQADDR0) != 0) \
- || (AHC_INB(ahc, SEQADDR1) != 0)); \
- \
- UNPAUSE_SEQUENCER(ahc);
+static inline void
+restart_sequencer(ahc)
+ struct ahc_data *ahc;
+{
+ do {
+ AHC_OUTB(ahc, SEQCTL, SEQRESET|FASTMODE);
+ } while((AHC_INB(ahc, SEQADDR0) != 0)
+ || (AHC_INB(ahc, SEQADDR1) != 0));
+
+ unpause_sequencer(ahc, /*unpause_always*/TRUE);
+}
#if defined(__NetBSD__)
/*
@@ -270,6 +289,7 @@ static inline void ahc_fetch_scb __P((struct ahc_data *ahc, struct scb *scb));
static inline void ahc_page_scb __P((struct ahc_data *ahc, struct scb *out_scb,
struct scb *in_scb));
static inline void ahc_run_waiting_queues __P((struct ahc_data *ahc));
+static void ahc_handle_seqint __P((struct ahc_data *ahc, u_int8_t intstat));
static struct scb *
ahc_get_scb __P((struct ahc_data *ahc, int flags));
static void ahc_loadseq __P((struct ahc_data *ahc));
@@ -286,9 +306,9 @@ static int ahc_reset_device __P((struct ahc_data *ahc, int target,
u_int32_t xs_error));
static void ahc_reset_current_bus __P((struct ahc_data *ahc));
static void ahc_run_done_queue __P((struct ahc_data *ahc));
-static void ahc_scsirate __P((struct ahc_data* ahc, u_char *scsirate,
- int period, int offset, char channel,
- int target));
+static void ahc_scsirate __P((struct ahc_data* 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;
@@ -299,6 +319,10 @@ static void ahc_busy_target __P((struct ahc_data *ahc,
int target, char channel));
static void ahc_unbusy_target __P((struct ahc_data *ahc,
int target, char channel));
+static void ahc_construct_sdtr __P((struct ahc_data *ahc, int start_byte,
+ u_int8_t period, u_int8_t offset));
+static void ahc_construct_wdtr __P((struct ahc_data *ahc, int start_byte,
+ u_int8_t bus_width));
#if defined(__FreeBSD__)
@@ -360,20 +384,20 @@ static struct {
short sxfr;
/* Rates in Ultra mode have bit 8 of sxfr set */
#define ULTRA_SXFR 0x100
- short period; /* in ns */
+ int period; /* in ns/4 */
char *rate;
} ahc_syncrates[] = {
- { 0x100, 50, "20.0" },
- { 0x110, 62, "16.0" },
- { 0x120, 75, "13.4" },
- { 0x000, 100, "10.0" },
- { 0x010, 125, "8.0" },
- { 0x020, 150, "6.67" },
- { 0x030, 175, "5.7" },
- { 0x040, 200, "5.0" },
- { 0x050, 225, "4.4" },
- { 0x060, 250, "4.0" },
- { 0x070, 275, "3.6" }
+ { 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 =
@@ -383,7 +407,6 @@ static int ahc_num_syncrates =
* Allocate a controller structures for a new device and initialize it.
* ahc_reset should be called before now since we assume that the card
* is paused.
- *
*/
#if defined(__FreeBSD__)
struct ahc_data *
@@ -507,73 +530,81 @@ ahc_reset(devname, bc, ioh)
*/
static void
ahc_scsirate(ahc, scsirate, period, offset, channel, target )
- struct ahc_data *ahc;
- u_char *scsirate;
- short period;
- u_char offset;
- char channel;
- int target;
+ struct ahc_data *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;
- for (i = 0; i < ahc_num_syncrates; i++) {
- u_char ultra_enb;
- u_char sxfrctl0;
- u_long ultra_enb_addr;
+ i = ahc_num_syncrates; /* Default to async */
+
+ if (*period >= ahc_syncrates[0].period && *offset != 0) {
+ for (i = 0; i < ahc_num_syncrates; i++) {
- if ((ahc_syncrates[i].period - period) >= 0) {
- /*
- * Watch out for Ultra speeds when ultra is not
- * enabled and vice-versa.
- */
- if(!(ahc->type & AHC_ULTRA)
- && (ahc_syncrates[i].sxfr & ULTRA_SXFR)) {
+ if (*period <= ahc_syncrates[i].period) {
/*
- * 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.
+ * Watch out for Ultra speeds when ultra is not
+ * enabled and vice-versa.
*/
- continue;
- }
- *scsirate = (ahc_syncrates[i].sxfr) | (offset & 0x0f);
-
- /*
- * 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 (ahc_syncrates[i].sxfr & ULTRA_SXFR) {
- ultra_enb |= 0x01 << (target & 0x07);
- sxfrctl0 |= ULTRAEN;
- }
- else {
- ultra_enb &= ~(0x01 << (target & 0x07));
- sxfrctl0 &= ~ULTRAEN;
- }
- AHC_OUTB(ahc, ultra_enb_addr, ultra_enb);
- AHC_OUTB(ahc, SXFRCTL0, sxfrctl0);
-
- if(bootverbose) {
- printf("%s: target %d synchronous at %sMHz,"
- " offset = 0x%x\n",
- ahc_name(ahc), target,
- ahc_syncrates[i].rate, offset );
+ 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;
}
- return;
}
}
- /* Default to asyncronous transfers. Also reject this SDTR request. */
- *scsirate = 0;
- if(bootverbose) {
- printf("%s: target %d using asyncronous transfers\n",
- ahc_name(ahc), target );
+ if (i >= ahc_num_syncrates) {
+ /* Use asyncronous transfers. */
+ *scsirate = 0;
+ *period = 0;
+ *offset = 0;
+ if(bootverbose)
+ printf("%s: target %d using asyncronous 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 |= ULTRAEN;
}
+ else {
+ ultra_enb &= ~(0x01 << (target & 0x07));
+ sxfrctl0 &= ~ULTRAEN;
+ }
+ AHC_OUTB(ahc, ultra_enb_addr, ultra_enb);
+ AHC_OUTB(ahc, SXFRCTL0, sxfrctl0);
}
#if defined(__NetBSD__)
@@ -780,7 +811,7 @@ ahc_run_waiting_queues(ahc)
if(!(ahc->assigned_scbs.stqh_first || ahc->waiting_scbs.stqh_first))
return;
- PAUSE_SEQUENCER(ahc);
+ pause_sequencer(ahc);
cur_scb = AHC_INB(ahc, SCBPTR);
/*
@@ -884,7 +915,7 @@ ahc_run_waiting_queues(ahc)
}
/* Restore old position */
AHC_OUTB(ahc, SCBPTR, cur_scb);
- UNPAUSE_SEQUENCER(ahc);
+ unpause_sequencer(ahc, /*unpause_always*/FALSE);
}
/*
@@ -950,761 +981,10 @@ ahc_intr(arg)
(AHC_INB(ahc, SEQADDR1) << 8) |
AHC_INB(ahc, SEQADDR0));
}
- if (intstat & SEQINT) {
- u_short targ_mask;
- u_char target = (AHC_INB(ahc, SCSIID) >> 4) & 0x0f;
- u_char scratch_offset = target;
- char 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:
- if(ahc->flags & AHC_PAGESCBS) {
- /* SCB Page-in request */
- u_char tag;
- u_char next;
- u_char disc_scb;
- struct scb *outscb;
- u_char arg_1 = AHC_INB(ahc, ARG_1);
-
- /*
- * We should succeed, so set this now.
- * If we don't, and one of the methods
- * we use to aquire an SCB calls ahc_done,
- * we may wind up in our start routine
- * and unpause the adapter without giving
- * it the correct return value, which will
- * cause a hang.
- */
- AHC_OUTB(ahc, RETURN_1, SCB_PAGEDIN);
-
- if(arg_1 == SCB_LIST_NULL) {
- /* Non-tagged command */
- int index = target |
- (channel == 'B' ? SELBUSB : 0);
- scb = ahc->pagedout_ntscbs[index];
- }
- else
- scb = ahc->scbarray[arg_1];
-
- if(!(scb->flags & SCB_PAGED_OUT))
- panic("%s: Request to page in a"
- "non paged out SCB.",
- ahc_name(ahc));
- /*
- * Now to pick the SCB to page out.
- * Either take a free SCB, an assigned SCB,
- * an SCB that just completed, the first
- * one on the disconnected SCB list, or
- * as a last resort a queued SCB.
- */
- if(ahc->free_scbs.stqh_first) {
- outscb = ahc->free_scbs.stqh_first;
- STAILQ_REMOVE_HEAD(&ahc->free_scbs,
- links);
- scb->position = outscb->position;
- outscb->position = SCB_LIST_NULL;
- STAILQ_INSERT_HEAD(&ahc->page_scbs,
- outscb, links);
- AHC_OUTB(ahc, SCBPTR, scb->position);
- ahc_send_scb(ahc, scb);
- scb->flags &= ~SCB_PAGED_OUT;
- goto pagein_done;
- }
- if(ahc->assigned_scbs.stqh_first) {
- outscb = ahc->assigned_scbs.stqh_first;
- STAILQ_REMOVE_HEAD(&ahc->assigned_scbs,
- links);
- outscb->flags ^= SCB_ASSIGNEDQ
- |SCB_WAITINGQ;
- scb->position = outscb->position;
- outscb->position = SCB_LIST_NULL;
- STAILQ_INSERT_HEAD(&ahc->waiting_scbs,
- outscb, links);
- AHC_OUTB(ahc, SCBPTR, scb->position);
- ahc_send_scb(ahc, scb);
- scb->flags &= ~SCB_PAGED_OUT;
- goto pagein_done;
- }
- if(intstat & CMDCMPLT) {
- int scb_index;
-
- AHC_OUTB(ahc, CLRINT, CLRCMDINT);
- scb_index = AHC_INB(ahc, QOUTFIFO);
- if(!(AHC_INB(ahc, QOUTCNT) & ahc->qcntmask))
- intstat &= ~CMDCMPLT;
-
- outscb = ahc->scbarray[scb_index];
- if (!outscb || !(outscb->flags & SCB_ACTIVE)) {
- printf("%s: WARNING "
- "no command for scb %d (cmdcmplt)\n",
- ahc_name(ahc),
- scb_index);
- /* Fall through in hopes of finding another SCB */
- }
- else {
- scb->position = outscb->position;
- outscb->position = SCB_LIST_NULL;
- AHC_OUTB(ahc, SCBPTR, scb->position);
- ahc_send_scb(ahc, scb);
- scb->flags &= ~SCB_PAGED_OUT;
- untimeout(ahc_timeout, (caddr_t)outscb);
- ahc_done(ahc, outscb);
- goto pagein_done;
- }
- }
- disc_scb = AHC_INB(ahc, DISCONNECTED_SCBH);
- if(disc_scb != SCB_LIST_NULL) {
- AHC_OUTB(ahc, SCBPTR, disc_scb);
- tag = AHC_INB(ahc, SCB_TAG);
- outscb = ahc->scbarray[tag];
- next = AHC_INB(ahc, SCB_NEXT);
- if(next != SCB_LIST_NULL) {
- AHC_OUTB(ahc, SCBPTR, next);
- AHC_OUTB(ahc, SCB_PREV,
- SCB_LIST_NULL);
- AHC_OUTB(ahc, SCBPTR, disc_scb);
- }
- AHC_OUTB(ahc, DISCONNECTED_SCBH, next);
- ahc_page_scb(ahc, outscb, scb);
- }
- else if(AHC_INB(ahc, QINCNT) & ahc->qcntmask) {
- /* Pull one of our queued commands as a last resort */
- disc_scb = AHC_INB(ahc, QINFIFO);
- AHC_OUTB(ahc, SCBPTR, disc_scb);
- tag = AHC_INB(ahc, SCB_TAG);
- outscb = ahc->scbarray[tag];
- if((outscb->control & 0x23) != TAG_ENB) {
- /*
- * This is not a simple tagged command
- * so its position in the queue
- * matters. Take the command at the
- * end of the queue instead.
- */
- int i;
- u_char saved_queue[AHC_SCB_MAX];
- u_char queued = AHC_INB(ahc, QINCNT) & ahc->qcntmask;
-
- /* Count the command we removed already */
- saved_queue[0] = disc_scb;
- queued++;
-
- /* Empty the input queue */
- for (i = 1; i < queued; i++)
- saved_queue[i] = AHC_INB(ahc, QINFIFO);
-
- /* Put everyone back put the last entry */
- queued--;
- for (i = 0; i < queued; i++)
- AHC_OUTB(ahc, QINFIFO, saved_queue[i]);
-
- AHC_OUTB(ahc, SCBPTR, saved_queue[queued]);
- tag = AHC_INB(ahc, SCB_TAG);
- outscb = ahc->scbarray[tag];
- }
- untimeout(ahc_timeout, (caddr_t)outscb);
- scb->position = outscb->position;
- outscb->position = SCB_LIST_NULL;
- STAILQ_INSERT_HEAD(&ahc->waiting_scbs,
- outscb, links);
- outscb->flags |= SCB_WAITINGQ;
- ahc_send_scb(ahc, scb);
- scb->flags &= ~SCB_PAGED_OUT;
- }
- else {
- panic("Page-in request with no candidates");
- AHC_OUTB(ahc, RETURN_1, 0);
- }
-pagein_done:
- }
- else {
- printf("%s:%c:%d: no active SCB for "
- "reconnecting target - "
- "issuing ABORT\n",
- ahc_name(ahc), channel, target);
- printf("SAVED_TCL == 0x%x\n",
- AHC_INB(ahc, SAVED_TCL));
- ahc_unbusy_target(ahc, target, channel);
- AHC_OUTB(ahc, SCB_CONTROL, 0);
- AHC_OUTB(ahc, CLRSINT1, CLRSELTIMEO);
- AHC_OUTB(ahc, RETURN_1, 0);
- }
- break;
- case SEND_REJECT:
- {
- u_char rejbyte = AHC_INB(ahc, REJBYTE);
- if(( rejbyte & 0xf0) == 0x20) {
- /* Tagged Message */
- printf("\n%s:%c:%d: Tagged message "
- "received without identify. "
- "Disabling tagged commands "
- "for this target.\n",
- ahc_name(ahc),
- channel, target);
- ahc->tagenable &= ~targ_mask;
- }
- else
- printf("%s:%c:%d: Warning - "
- "unknown message recieved from "
- "target (0x%x - 0x%x). Rejecting\n",
- ahc_name(ahc), channel, target,
- rejbyte,
- AHC_INB(ahc, REJBYTE_EXT));
- break;
- }
- case NO_IDENT:
- panic("%s:%c:%d: Target did not send an IDENTIFY "
- "message. SAVED_TCL == 0x%x\n",
- ahc_name(ahc), channel, target,
- AHC_INB(ahc, SAVED_TCL));
- break;
- case BAD_PHASE:
- printf("%s:%c:%d: unknown scsi bus phase. "
- "Attempting to continue\n",
- ahc_name(ahc), channel, target);
- break;
- case SDTR_MSG:
- {
- short period;
- u_char offset, rate;
- u_char targ_scratch;
- u_char maxoffset;
- /*
- * 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
- */
- period = AHC_INB(ahc, ARG_1) << 2;
- offset = AHC_INB(ahc, ACCUM);
- targ_scratch = AHC_INB(ahc, TARG_SCRATCH
- + scratch_offset);
- if(targ_scratch & WIDEXFER)
- maxoffset = 0x08;
- else
- maxoffset = 0x0f;
- ahc_scsirate(ahc, &rate, period,
- MIN(offset, maxoffset),
- channel, target);
- /* Preserve the WideXfer flag */
- targ_scratch = rate | (targ_scratch & WIDEXFER);
- AHC_OUTB(ahc, TARG_SCRATCH + scratch_offset,
- targ_scratch);
- AHC_OUTB(ahc, SCSIRATE, targ_scratch);
- if( (targ_scratch & 0x0f) == 0 )
- {
- /*
- * The requested rate was so low
- * that asyncronous transfers are
- * faster (not to mention the
- * controller won't support them),
- * so we issue a message reject to
- * ensure we go to asyncronous
- * transfers.
- */
- AHC_OUTB(ahc, RETURN_1, SEND_REJ);
- }
- /* See if we initiated Sync Negotiation */
- else if(ahc->sdtrpending & targ_mask)
- {
- /*
- * Don't send an SDTR back to
- * the target
- */
- AHC_OUTB(ahc, RETURN_1, 0);
- }
- else{
- /*
- * Send our own SDTR in reply
- */
-#ifdef AHC_DEBUG
- if(ahc_debug & AHC_SHOWMISC)
- printf("Sending SDTR!!\n");
-#endif
- AHC_OUTB(ahc, RETURN_1, SEND_SDTR);
- }
- /*
- * Negate the flags
- */
- ahc->needsdtr &= ~targ_mask;
- ahc->sdtrpending &= ~targ_mask;
- break;
- }
- case WDTR_MSG:
- {
- u_char scratch, bus_width;
-
- bus_width = AHC_INB(ahc, ARG_1);
+ if (intstat & SEQINT)
+ ahc_handle_seqint(ahc, intstat);
- scratch = AHC_INB(ahc, TARG_SCRATCH
- + scratch_offset);
-
- if(ahc->wdtrpending & targ_mask)
- {
- /*
- * 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 |= 0x80;
- 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 |= 0x80;
- }
- else
- bus_width = BUS_8_BIT;
- break;
- default:
- break;
- }
- AHC_OUTB(ahc, RETURN_1,
- bus_width | SEND_WDTR);
- }
- ahc->needwdtr &= ~targ_mask;
- ahc->wdtrpending &= ~targ_mask;
- AHC_OUTB(ahc, TARG_SCRATCH + scratch_offset,
- scratch);
- AHC_OUTB(ahc, SCSIRATE, scratch);
- 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_char targ_scratch;
-
- targ_scratch = AHC_INB(ahc, TARG_SCRATCH
- + scratch_offset);
-
- if(ahc->wdtrpending & targ_mask){
- /* note 8bit xfers and clear flag */
- targ_scratch &= 0x7f;
- ahc->needwdtr &= ~targ_mask;
- ahc->wdtrpending &= ~targ_mask;
- printf("%s:%c:%d: refuses "
- "WIDE negotiation. Using "
- "8bit transfers\n",
- ahc_name(ahc),
- channel, target);
- }
- else if(ahc->sdtrpending & targ_mask){
- /* note asynch xfers and clear flag */
- targ_scratch &= 0xf0;
- ahc->needsdtr &= ~targ_mask;
- ahc->sdtrpending &= ~targ_mask;
- printf("%s:%c:%d: refuses "
- "syncronous negotiation. Using "
- "asyncronous 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:
- {
- int scb_index;
-
- /* 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.
- */
-
- scb_index = AHC_INB(ahc, SCB_TAG);
- scb = ahc->scbarray[scb_index];
-
- /*
- * 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;
-
- scb->status = AHC_INB(ahc, SCB_TARGET_STATUS);
-
-#ifdef AHC_DEBUG
- if((ahc_debug & AHC_SHOWSCBS)
- && xs->sc_link->target == DEBUGTARG)
- ahc_print_scb(scb);
-#endif
- xs->status = scb->status;
- switch(scb->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("requests Check Status\n");
- }
-#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);
-#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 = KVTOPHYS(&xs->sense);
- sg->len = sizeof(struct scsi_sense_data);
-
- scb->control &= DISCENB;
- scb->status = 0;
- scb->SG_segment_count = 1;
- scb->SG_list_pointer = KVTOPHYS(sg);
- scb->data = sg->addr;
- scb->datalen = sg->len;
-#ifdef AHC_BROKEN_CACHE
- if (ahc_broken_cache)
- INVALIDATE_CACHE();
-#endif
- scb->cmdpointer = KVTOPHYS(sc);
- scb->cmdlen = sizeof(*sc);
-
- scb->flags |= SCB_SENSE;
- ahc_send_scb(ahc, scb);
- /*
- * Ensure that the target is "BUSY"
- * so we don't get overlapping
- * commands if we happen to be doing
- * tagged I/O.
- */
- ahc_busy_target(ahc, target, channel);
-
- /*
- * Make us the next command to run
- */
- ahc_add_waiting_scb(ahc, scb);
- AHC_OUTB(ahc, RETURN_1, SEND_SENSE);
- 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_BUSY:
- xs->error = XS_BUSY;
- sc_print_addr(xs->sc_link);
- printf("Target Busy\n");
- break;
- case SCSI_QUEUE_FULL:
- /*
- * The upper level SCSI code will someday
- * handle this properly.
- */
- sc_print_addr(xs->sc_link);
- printf("Queue Full\n");
- scb->flags |= SCB_ASSIGNEDQ;
- STAILQ_INSERT_TAIL(&ahc->assigned_scbs,
- scb, links);
- break;
- default:
- sc_print_addr(xs->sc_link);
- printf("unexpected targ_status: %x\n",
- scb->status);
- xs->error = XS_DRIVER_STUFFUP;
- break;
- }
- break;
- }
- case RESIDUAL:
- {
- int scb_index;
- scb_index = AHC_INB(ahc, SCB_TAG);
- scb = ahc->scbarray[scb_index];
- xs = scb->xs;
- /*
- * Don't clobber valid resid info with
- * a resid coming from a check sense
- * operation.
- */
- if(!(scb->flags & SCB_SENSE)) {
- int resid_sgs;
-
- /*
- * Remainder of the SG where the transfer
- * stopped.
- */
- xs->resid =
- (AHC_INB(ahc, SCB_RESID_DCNT2)<<16) |
- (AHC_INB(ahc, SCB_RESID_DCNT1)<<8) |
- AHC_INB(ahc, SCB_RESID_DCNT0);
-
- /*
- * Add up the contents of all residual
- * SG segments that are after the SG where
- * the transfer stopped.
- */
- resid_sgs = AHC_INB(ahc, SCB_RESID_SGCNT) - 1;
- while(resid_sgs > 0) {
- int sg;
-
- sg = scb->SG_segment_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
-#ifdef AHC_DEBUG
- if(ahc_debug & AHC_SHOWMISC) {
- sc_print_addr(xs->sc_link);
- printf("Handled Residual of %ld bytes\n"
- ,xs->resid);
- }
-#endif
- }
- break;
- }
- case ABORT_TAG:
- {
- int scb_index;
- scb_index = AHC_INB(ahc, SCB_TAG);
- scb = ahc->scbarray[scb_index];
- xs = scb->xs;
- /*
- * We didn't recieve a valid tag back from
- * the target on a reconnect.
- */
- sc_print_addr(xs->sc_link);
- printf("invalid tag recieved -- sending ABORT_TAG\n");
- xs->error = XS_DRIVER_STUFFUP;
- untimeout(ahc_timeout, (caddr_t)scb);
- ahc_done(ahc, scb);
- break;
- }
- case AWAITING_MSG:
- {
- int scb_index;
- scb_index = AHC_INB(ahc, SCB_TAG);
- scb = ahc->scbarray[scb_index];
- /*
- * This SCB had a zero length command, informing
- * the sequencer that we wanted to send a special
- * message to this target. We only do this for
- * BUS_DEVICE_RESET messages currently.
- */
- if(scb->flags & SCB_DEVICE_RESET)
- {
- AHC_OUTB(ahc, MSG0,
- MSG_BUS_DEVICE_RESET);
- AHC_OUTB(ahc, MSG_LEN, 1);
- printf("Bus Device Reset Message Sent\n");
- }
- else
- panic("ahc_intr: AWAITING_MSG for an SCB that "
- "does not have a waiting message");
- break;
- }
- case IMMEDDONE:
- {
- /*
- * Take care of device reset messages
- */
- u_char scbindex = AHC_INB(ahc, SCB_TAG);
- scb = ahc->scbarray[scbindex];
- if(scb->flags & SCB_DEVICE_RESET) {
- u_char targ_scratch;
- int found;
- /*
- * Go back to async/narrow transfers and
- * renegotiate.
- */
- ahc_unbusy_target(ahc, target, channel);
- 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, SCB_LIST_NULL,
- XS_NOERROR);
- sc_print_addr(scb->xs->sc_link);
- printf("Bus Device Reset delivered. "
- "%d SCBs aborted\n", found);
- ahc->in_timeout = FALSE;
- ahc_run_done_queue(ahc);
- }
- else
- panic("ahc_intr: Immediate complete for "
- "unknown operation.");
- 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_char scbindex = AHC_INB(ahc, SCB_TAG);
- u_int32_t overrun;
- scb = ahc->scbarray[scbindex];
- overrun = AHC_INB(ahc, STCNT0)
- | (AHC_INB(ahc, STCNT1) << 8)
- | (AHC_INB(ahc, STCNT2) << 16);
- overrun = 0x00ffffff - overrun;
- sc_print_addr(scb->xs->sc_link);
- printf("data overrun of %d bytes detected."
- " Forcing a retry.\n", overrun);
- /*
- * 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
- 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 leave this section.
- */
- UNPAUSE_SEQUENCER(ahc);
- }
-
-
- if (intstat & SCSIINT) {
+ if (intstat & SCSIINT) {
int scb_index = AHC_INB(ahc, SCB_TAG);
status = AHC_INB(ahc, SSTAT1);
@@ -1728,7 +1008,7 @@ clear:
"valid during scsiint 0x%x scb(%d)\n",
ahc_name(ahc), status, scb_index);
AHC_OUTB(ahc, CLRSINT1, status);
- UNPAUSE_SEQUENCER(ahc);
+ unpause_sequencer(ahc, /*unpause_always*/TRUE);
AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
scb = NULL;
}
@@ -1738,7 +1018,7 @@ clear:
* queue an appropriate message
*/
char *phase;
- u_char mesg_out = MSG_NOP;
+ u_char mesg_out = MSG_NOOP;
u_char lastphase = AHC_INB(ahc, LASTPHASE);
xs = scb->xs;
@@ -1750,7 +1030,7 @@ clear:
break;
case P_DATAIN:
phase = "Data-In";
- mesg_out = MSG_INITIATOR_DET_ERROR;
+ mesg_out = MSG_INITIATOR_DET_ERR;
break;
case P_COMMAND:
phase = "Command";
@@ -1760,17 +1040,17 @@ clear:
break;
case P_STATUS:
phase = "Status";
- mesg_out = MSG_INITIATOR_DET_ERROR;
+ mesg_out = MSG_INITIATOR_DET_ERR;
break;
case P_MESGIN:
phase = "Message-In";
- mesg_out = MSG_MSG_PARITY_ERROR;
+ mesg_out = MSG_PARITY_ERROR;
break;
default:
phase = "unknown";
break;
}
- printf("parity error during %s phase.\n", phase);
+ printf("parity error during %s phase.\n", phase);
/*
* We've set the hardware to assert ATN if we
@@ -1779,7 +1059,7 @@ clear:
* the appropriate message. "In" phases have set
* mesg_out to something other than MSG_NOP.
*/
- if(mesg_out != MSG_NOP) {
+ if(mesg_out != MSG_NOOP) {
AHC_OUTB(ahc, MSG0, mesg_out);
AHC_OUTB(ahc, MSG_LEN, 1);
}
@@ -1824,13 +1104,13 @@ clear:
waiting = AHC_INB(ahc, SCB_NEXT);
AHC_OUTB(ahc, WAITING_SCBH, waiting);
- RESTART_SEQUENCER(ahc);
+ restart_sequencer(ahc);
}
else if (!(status & BUSFREE)) {
sc_print_addr(scb->xs->sc_link);
printf("Unknown SCSIINT. Status = 0x%x\n", status);
AHC_OUTB(ahc, CLRSINT1, status);
- UNPAUSE_SEQUENCER(ahc);
+ unpause_sequencer(ahc, /*unpause_always*/TRUE);
AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
scb = NULL;
}
@@ -1868,6 +1148,766 @@ clear:
#endif
}
+static void
+ahc_handle_seqint(ahc, intstat)
+ struct ahc_data *ahc;
+ u_int8_t intstat;
+{
+ struct scb *scb;
+ u_short targ_mask;
+ u_char target = (AHC_INB(ahc, SCSIID) >> 4) & 0x0f;
+ u_char scratch_offset = target;
+ char 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:
+ if (ahc->flags & AHC_PAGESCBS) {
+ /* SCB Page-in request */
+ u_char tag;
+ u_char next;
+ u_char disc_scb;
+ struct scb *outscb;
+ u_char arg_1 = AHC_INB(ahc, ARG_1);
+
+ /*
+ * We should succeed, so set this now.
+ * If we don't, and one of the methods
+ * we use to aquire an SCB calls ahc_done,
+ * we may wind up in our start routine
+ * and unpause the adapter without giving
+ * it the correct return value, which will
+ * cause a hang.
+ */
+ AHC_OUTB(ahc, RETURN_1, SCB_PAGEDIN);
+
+ if (arg_1 == SCB_LIST_NULL) {
+ /* Non-tagged command */
+ int index;
+
+ index = target|(channel == 'B' ? SELBUSB : 0);
+ scb = ahc->pagedout_ntscbs[index];
+ } else
+ scb = ahc->scbarray[arg_1];
+
+ if (!(scb->flags & SCB_PAGED_OUT))
+ panic("%s: Request to page in a non paged out "
+ "SCB.", ahc_name(ahc));
+ /*
+ * Now to pick the SCB to page out.
+ * Either take a free SCB, an assigned SCB,
+ * an SCB that just completed, the first
+ * one on the disconnected SCB list, or
+ * as a last resort a queued SCB.
+ */
+ if (ahc->free_scbs.stqh_first) {
+ outscb = ahc->free_scbs.stqh_first;
+ STAILQ_REMOVE_HEAD(&ahc->free_scbs, links);
+ scb->position = outscb->position;
+ outscb->position = SCB_LIST_NULL;
+ STAILQ_INSERT_HEAD(&ahc->page_scbs, outscb,
+ links);
+ AHC_OUTB(ahc, SCBPTR, scb->position);
+ ahc_send_scb(ahc, scb);
+ scb->flags &= ~SCB_PAGED_OUT;
+ goto pagein_done;
+ }
+ if (intstat & CMDCMPLT) {
+ int scb_index;
+
+ AHC_OUTB(ahc, CLRINT, CLRCMDINT);
+ scb_index = AHC_INB(ahc, QOUTFIFO);
+ if (!(AHC_INB(ahc, QOUTCNT) & ahc->qcntmask))
+ intstat &= ~CMDCMPLT;
+
+ outscb = ahc->scbarray[scb_index];
+ if (!outscb || !(outscb->flags & SCB_ACTIVE)) {
+ printf("%s: WARNING no command for "
+ "scb %d (cmdcmplt)\n",
+ ahc_name(ahc),
+ scb_index);
+ /*
+ * Fall through in hopes of finding
+ * another SCB
+ */
+ } else {
+ scb->position = outscb->position;
+ outscb->position = SCB_LIST_NULL;
+ AHC_OUTB(ahc, SCBPTR, scb->position);
+ ahc_send_scb(ahc, scb);
+ scb->flags &= ~SCB_PAGED_OUT;
+ untimeout(ahc_timeout,
+ (caddr_t)outscb);
+ ahc_done(ahc, outscb);
+ goto pagein_done;
+ }
+ }
+ disc_scb = AHC_INB(ahc, DISCONNECTED_SCBH);
+ if (disc_scb != SCB_LIST_NULL) {
+ AHC_OUTB(ahc, SCBPTR, disc_scb);
+ tag = AHC_INB(ahc, SCB_TAG);
+ outscb = ahc->scbarray[tag];
+ next = AHC_INB(ahc, SCB_NEXT);
+ if (next != SCB_LIST_NULL) {
+ AHC_OUTB(ahc, SCBPTR, next);
+ AHC_OUTB(ahc, SCB_PREV,
+ SCB_LIST_NULL);
+ AHC_OUTB(ahc, SCBPTR, disc_scb);
+ }
+ AHC_OUTB(ahc, DISCONNECTED_SCBH, next);
+ ahc_page_scb(ahc, outscb, scb);
+ } else if (AHC_INB(ahc, QINCNT) & ahc->qcntmask) {
+ /*
+ * Pull one of our queued commands
+ * as a last resort
+ */
+ disc_scb = AHC_INB(ahc, QINFIFO);
+ AHC_OUTB(ahc, SCBPTR, disc_scb);
+ tag = AHC_INB(ahc, SCB_TAG);
+ outscb = ahc->scbarray[tag];
+ if ((outscb->control & 0x23) != TAG_ENB) {
+ /*
+ * This is not a simple tagged command
+ * so its position in the queue
+ * matters. Take the command at the
+ * end of the queue instead.
+ */
+ int i;
+ u_char saved_queue[AHC_SCB_MAX];
+ u_char queued = AHC_INB(ahc, QINCNT)
+ & ahc->qcntmask;
+
+ /*
+ * Count the command we removed
+ * already
+ */
+ saved_queue[0] = disc_scb;
+ queued++;
+
+ /* Empty the input queue */
+ for (i = 1; i < queued; i++)
+ saved_queue[i] = AHC_INB(ahc, QINFIFO);
+
+ /*
+ * Put everyone back but the
+ * last entry
+ */
+ queued--;
+ for (i = 0; i < queued; i++)
+ AHC_OUTB(ahc, QINFIFO,
+ saved_queue[i]);
+
+ AHC_OUTB(ahc, SCBPTR,
+ saved_queue[queued]);
+ tag = AHC_INB(ahc, SCB_TAG);
+ outscb = ahc->scbarray[tag];
+ }
+ untimeout(ahc_timeout, (caddr_t)outscb);
+ scb->position = outscb->position;
+ outscb->position = SCB_LIST_NULL;
+ STAILQ_INSERT_HEAD(&ahc->waiting_scbs,
+ outscb, links);
+ outscb->flags |= SCB_WAITINGQ;
+ ahc_send_scb(ahc, scb);
+ scb->flags &= ~SCB_PAGED_OUT;
+ }
+ else {
+ panic("Page-in request with no candidates");
+ AHC_OUTB(ahc, RETURN_1, 0);
+ }
+ pagein_done:
+ } else {
+ printf("%s:%c:%d: no active SCB for reconnecting "
+ "target - issuing ABORT\n",
+ ahc_name(ahc), channel, target);
+ printf("SAVED_TCL == 0x%x\n",
+ AHC_INB(ahc, SAVED_TCL));
+ ahc_unbusy_target(ahc, target, channel);
+ AHC_OUTB(ahc, SCB_CONTROL, 0);
+ AHC_OUTB(ahc, CLRSINT1, CLRSELTIMEO);
+ AHC_OUTB(ahc, RETURN_1, 0);
+ }
+ break;
+ case SEND_REJECT:
+ {
+ u_char rejbyte = AHC_INB(ahc, REJBYTE);
+ printf("%s:%c:%d: Warning - unknown message recieved from "
+ "target (0x%x). Rejecting\n",
+ ahc_name(ahc), channel, target, rejbyte);
+ break;
+ }
+ case NO_IDENT:
+ panic("%s:%c:%d: Target did not send an IDENTIFY message. "
+ "SAVED_TCL == 0x%x\n",
+ ahc_name(ahc), channel, target,
+ AHC_INB(ahc, SAVED_TCL));
+ break;
+ case BAD_PHASE:
+ 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;
+
+ message_length = AHC_INB(ahc, MSGIN_EXT_LEN);
+ message_code = AHC_INB(ahc, MSGIN_EXT_OPCODE);
+ switch(message_code) {
+ case MSG_EXT_SDTR:
+ {
+ u_int8_t period;
+ u_int8_t 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);
+ ahc->sdtrpending &= ~targ_mask;
+ break;
+ }
+ period = AHC_INB(ahc, MSGIN_EXT_BYTE0);
+ offset = AHC_INB(ahc, MSGIN_EXT_BYTE1);
+ targ_scratch = AHC_INB(ahc, TARG_SCRATCH
+ + scratch_offset);
+ if (targ_scratch & WIDEXFER)
+ maxoffset = MAX_OFFSET_16BIT;
+ else
+ maxoffset = MAX_OFFSET_8BIT;
+ offset = MIN(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 */
+ if (ahc->sdtrpending & targ_mask) {
+ /*
+ * Don't send an SDTR back to
+ * the target
+ */
+ AHC_OUTB(ahc, RETURN_1, 0);
+ } else {
+ /*
+ * Send our own SDTR in reply
+ */
+#ifdef AHC_DEBUG
+ if(ahc_debug & AHC_SHOWMISC)
+ printf("Sending SDTR!!\n");
+#endif
+ ahc_construct_sdtr(ahc, /*start_byte*/0,
+ period, offset);
+ AHC_OUTB(ahc, RETURN_1, SEND_MSG);
+ }
+ /*
+ * Negate the flags
+ */
+ ahc->needsdtr &= ~targ_mask;
+ ahc->sdtrpending &= ~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);
+ ahc->wdtrpending &= ~targ_mask;
+ break;
+ }
+
+ bus_width = AHC_INB(ahc, MSGIN_EXT_BYTE0);
+ scratch = AHC_INB(ahc, TARG_SCRATCH
+ + scratch_offset);
+
+ if (ahc->wdtrpending & targ_mask) {
+ /*
+ * 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->wdtrpending &= ~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);
+ }
+ }
+ 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_char targ_scratch;
+
+ targ_scratch = AHC_INB(ahc, TARG_SCRATCH
+ + scratch_offset);
+
+ if (ahc->wdtrpending & targ_mask){
+ /* note 8bit xfers and clear flag */
+ targ_scratch &= 0x7f;
+ ahc->needwdtr &= ~targ_mask;
+ ahc->wdtrpending &= ~targ_mask;
+ printf("%s:%c:%d: refuses WIDE negotiation. Using "
+ "8bit transfers\n", ahc_name(ahc),
+ channel, target);
+ } else if(ahc->sdtrpending & targ_mask){
+ /* note asynch xfers and clear flag */
+ targ_scratch &= 0xf0;
+ ahc->needsdtr &= ~targ_mask;
+ ahc->sdtrpending &= ~targ_mask;
+ printf("%s:%c:%d: refuses syncronous negotiation. "
+ "Using asyncronous 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:
+ {
+ int scb_index;
+ struct scsi_xfer *xs;
+
+ /* 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.
+ */
+
+ scb_index = AHC_INB(ahc, SCB_TAG);
+ scb = ahc->scbarray[scb_index];
+
+ /*
+ * 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;
+
+ scb->status = AHC_INB(ahc, SCB_TARGET_STATUS);
+
+#ifdef AHC_DEBUG
+ if((ahc_debug & AHC_SHOWSCBS)
+ && xs->sc_link->target == DEBUGTARGET)
+ ahc_print_scb(scb);
+#endif
+ xs->status = scb->status;
+ switch(scb->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("requests Check Status\n");
+ }
+#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);
+#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 = KVTOPHYS(&xs->sense);
+ sg->len = sizeof(struct scsi_sense_data);
+
+ scb->control &= DISCENB;
+ scb->status = 0;
+ scb->SG_segment_count = 1;
+ scb->SG_list_pointer = KVTOPHYS(sg);
+ scb->data = sg->addr;
+ scb->datalen = sg->len;
+#ifdef AHC_BROKEN_CACHE
+ if (ahc_broken_cache)
+ INVALIDATE_CACHE();
+#endif
+ scb->cmdpointer = KVTOPHYS(sc);
+ scb->cmdlen = sizeof(*sc);
+
+ scb->flags |= SCB_SENSE;
+ ahc_send_scb(ahc, scb);
+ /*
+ * Ensure that the target is "BUSY"
+ * so we don't get overlapping
+ * commands if we happen to be doing
+ * tagged I/O.
+ */
+ ahc_busy_target(ahc, target, channel);
+
+ /*
+ * Make us the next command to run
+ */
+ ahc_add_waiting_scb(ahc, scb);
+ AHC_OUTB(ahc, RETURN_1, SEND_SENSE);
+ 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_BUSY:
+ xs->error = XS_BUSY;
+ sc_print_addr(xs->sc_link);
+ printf("Target Busy\n");
+ break;
+ case SCSI_QUEUE_FULL:
+ /*
+ * The upper level SCSI code will someday
+ * handle this properly.
+ */
+ sc_print_addr(xs->sc_link);
+ printf("Queue Full\n");
+ scb->flags |= SCB_ASSIGNEDQ;
+ STAILQ_INSERT_TAIL(&ahc->assigned_scbs,scb, links);
+ AHC_OUTB(ahc, RETURN_1, SEND_SENSE);
+ break;
+ default:
+ sc_print_addr(xs->sc_link);
+ printf("unexpected targ_status: %x\n", scb->status);
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+ break;
+ }
+ case RESIDUAL:
+ {
+ int scb_index;
+ struct scsi_xfer *xs;
+
+ scb_index = AHC_INB(ahc, SCB_TAG);
+ scb = ahc->scbarray[scb_index];
+ xs = scb->xs;
+ /*
+ * Don't clobber valid resid info with
+ * a resid coming from a check sense
+ * operation.
+ */
+ if (!(scb->flags & SCB_SENSE)) {
+ int resid_sgs;
+
+ /*
+ * Remainder of the SG where the transfer
+ * stopped.
+ */
+ xs->resid = (AHC_INB(ahc, SCB_RESID_DCNT2)<<16) |
+ (AHC_INB(ahc, SCB_RESID_DCNT1)<<8) |
+ AHC_INB(ahc, SCB_RESID_DCNT0);
+
+ /*
+ * Add up the contents of all residual
+ * SG segments that are after the SG where
+ * the transfer stopped.
+ */
+ resid_sgs = AHC_INB(ahc, SCB_RESID_SGCNT) - 1;
+ while (resid_sgs > 0) {
+ int sg;
+
+ sg = scb->SG_segment_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
+#ifdef AHC_DEBUG
+ if (ahc_debug & AHC_SHOWMISC) {
+ sc_print_addr(xs->sc_link);
+ printf("Handled Residual of %ld bytes\n"
+ ,xs->resid);
+ }
+#endif
+ }
+ break;
+ }
+ case ABORT_TAG:
+ {
+ int scb_index;
+ struct scsi_xfer *xs;
+
+ scb_index = AHC_INB(ahc, SCB_TAG);
+ scb = ahc->scbarray[scb_index];
+ xs = scb->xs;
+ /*
+ * We didn't recieve a valid tag back from
+ * the target on a reconnect.
+ */
+ sc_print_addr(xs->sc_link);
+ printf("invalid tag recieved -- sending ABORT_TAG\n");
+ xs->error = XS_DRIVER_STUFFUP;
+ untimeout(ahc_timeout, (caddr_t)scb);
+ ahc_done(ahc, scb);
+ break;
+ }
+ case AWAITING_MSG:
+ {
+ int scb_index;
+ scb_index = AHC_INB(ahc, SCB_TAG);
+ scb = ahc->scbarray[scb_index];
+ /*
+ * This SCB had a zero length command, informing
+ * the sequencer that we wanted to send a special
+ * message to this target. We only do this for
+ * BUS_DEVICE_RESET messages currently.
+ */
+ if (scb->flags & SCB_DEVICE_RESET) {
+ AHC_OUTB(ahc, MSG0,
+ MSG_BUS_DEV_RESET);
+ AHC_OUTB(ahc, MSG_LEN, 1);
+ printf("Bus Device Reset Message Sent\n");
+ } else if (scb->flags & SCB_MSGOUT_WDTR) {
+ ahc_construct_wdtr(ahc, AHC_INB(ahc, MSG_LEN),
+ BUS_16_BIT);
+ } else if (scb->flags & SCB_MSGOUT_SDTR) {
+ u_int8_t target_scratch;
+ u_int8_t ultraenable;
+ int sxfr;
+ int i;
+
+ /* Pull the user defined setting */
+ target_scratch = AHC_INB(ahc, TARG_SCRATCH
+ + scratch_offset);
+
+ sxfr = target_scratch & SXFR;
+ if (scratch_offset < 8)
+ ultraenable = AHC_INB(ahc, ULTRA_ENB);
+ else
+ ultraenable = AHC_INB(ahc, ULTRA_ENB + 1);
+
+ if (ultraenable & targ_mask)
+ /* Want an ultra speed in the table */
+ sxfr |= 0x100;
+
+ for (i = 0; i < ahc_num_syncrates; i++)
+ if (target_scratch == ahc_syncrates[i].sxfr)
+ break;
+
+ ahc_construct_sdtr(ahc, AHC_INB(ahc, MSG_LEN),
+ 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 IMMEDDONE:
+ {
+ /*
+ * Take care of device reset messages
+ */
+ u_char scbindex = AHC_INB(ahc, SCB_TAG);
+ scb = ahc->scbarray[scbindex];
+ if (scb->flags & SCB_DEVICE_RESET) {
+ u_char targ_scratch;
+ int found;
+ /*
+ * Go back to async/narrow transfers and
+ * renegotiate.
+ */
+ ahc_unbusy_target(ahc, target, channel);
+ 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, SCB_LIST_NULL,
+ XS_NOERROR);
+ sc_print_addr(scb->xs->sc_link);
+ printf("Bus Device Reset delivered. "
+ "%d SCBs aborted\n", found);
+ ahc->in_timeout = FALSE;
+ ahc_run_done_queue(ahc);
+ } else
+ panic("ahc_intr: Immediate complete for "
+ "unknown operation.");
+ 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_char scbindex = AHC_INB(ahc, SCB_TAG);
+ u_int32_t overrun;
+ scb = ahc->scbarray[scbindex];
+ overrun = AHC_INB(ahc, STCNT0)
+ | (AHC_INB(ahc, STCNT1) << 8)
+ | (AHC_INB(ahc, STCNT2) << 16);
+ overrun = 0x00ffffff - overrun;
+ sc_print_addr(scb->xs->sc_link);
+ printf("data overrun of %d bytes detected."
+ " Forcing a retry.\n", overrun);
+ /*
+ * 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
+ 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);
+}
+
/*
* We have a scb which has been processed by the
* adaptor, now we look to see how the operation
@@ -1955,9 +1995,9 @@ int
ahc_init(ahc)
struct ahc_data *ahc;
{
- u_char scsi_conf, sblkctl, i;
- u_short ultraenable = 0;
- int max_targ = 15;
+ u_int8_t scsi_conf, sblkctl, i;
+ u_int16_t ultraenable = 0;
+ int max_targ = 15;
/*
* Assume we have a board at this stage and it has been reset.
*/
@@ -2253,7 +2293,7 @@ ahc_init(ahc)
AHC_OUTB(ahc, SEQCTL, FASTMODE);
- UNPAUSE_SEQUENCER(ahc);
+ unpause_sequencer(ahc, /*unpause_always*/TRUE);
/*
* Note that we are going and return (to probe)
@@ -2328,8 +2368,10 @@ ahc_scsi_cmd(xs)
}
SC_DEBUG(xs->sc_link, SDEV_DB3, ("start scb(%p)\n", scb));
scb->xs = xs;
- if (flags & SCSI_RESET)
+ if (flags & SCSI_RESET) {
scb->flags |= SCB_DEVICE_RESET|SCB_IMMED;
+ scb->control |= MK_MESSAGE;
+ }
/*
* Put all the arguments for the xfer in the scb
*/
@@ -2346,12 +2388,14 @@ ahc_scsi_cmd(xs)
scb->control |= DISCENB;
if((ahc->needwdtr & mask) && !(ahc->wdtrpending & mask))
{
- scb->control |= NEEDWDTR;
+ scb->control |= MK_MESSAGE;
+ scb->flags |= SCB_MSGOUT_WDTR;
ahc->wdtrpending |= mask;
}
else if((ahc->needsdtr & mask) && !(ahc->sdtrpending & mask))
{
- scb->control |= NEEDSDTR;
+ scb->control |= MK_MESSAGE;
+ scb->flags |= SCB_MSGOUT_SDTR;
ahc->sdtrpending |= mask;
}
scb->tcl = ((xs->sc_link->target << 4) & 0xF0) |
@@ -2458,13 +2502,13 @@ ahc_scsi_cmd(xs)
/* We already have a valid slot */
u_char curscb;
- PAUSE_SEQUENCER(ahc);
+ pause_sequencer(ahc);
curscb = AHC_INB(ahc, SCBPTR);
AHC_OUTB(ahc, SCBPTR, scb->position);
ahc_send_scb(ahc, scb);
AHC_OUTB(ahc, SCBPTR, curscb);
AHC_OUTB(ahc, QINFIFO, scb->position);
- UNPAUSE_SEQUENCER(ahc);
+ unpause_sequencer(ahc, /*unpause_always*/FALSE);
scb->flags |= SCB_ACTIVE;
if (!(flags & SCSI_NOMASK)) {
timeout(ahc_timeout, (caddr_t)scb,
@@ -2537,7 +2581,7 @@ ahc_free_scb(ahc, scb, flags)
else if((wscb = ahc->waiting_scbs.stqh_first) != NULL) {
STAILQ_REMOVE_HEAD(&ahc->waiting_scbs, links);
wscb->position = scb->position;
- STAILQ_INSERT_HEAD(&ahc->assigned_scbs, wscb, links);
+ STAILQ_INSERT_TAIL(&ahc->assigned_scbs, wscb, links);
wscb->flags ^= SCB_WAITINGQ|SCB_ASSIGNEDQ;
/*
@@ -2734,7 +2778,7 @@ ahc_timeout(arg)
* Ensure that the card doesn't do anything
* behind our back.
*/
- PAUSE_SEQUENCER(ahc);
+ pause_sequencer(ahc);
sc_print_addr(scb->xs->sc_link);
printf("timed out ");
@@ -2802,7 +2846,7 @@ ahc_timeout(arg)
scb->flags |= SCB_ABORTED|SCB_SENTORDEREDTAG;
ahc->orderedtag |= 0xFF;
timeout(ahc_timeout, (caddr_t)scb, (5 * hz));
- UNPAUSE_SEQUENCER(ahc);
+ unpause_sequencer(ahc, /*unpause_always*/FALSE);
printf("Ordered Tag queued\n");
goto done;
}
@@ -2865,6 +2909,7 @@ ahc_timeout(arg)
}
scb->flags |= SCB_DEVICE_RESET|SCB_ABORTED;
scb->control &= DISCENB;
+ scb->control |= MK_MESSAGE;
scb->cmdlen = 0;
scb->SG_segment_count = 0;
scb->SG_list_pointer = 0;
@@ -2876,13 +2921,13 @@ ahc_timeout(arg)
sc_print_addr(scb->xs->sc_link);
printf("BUS DEVICE RESET message queued.\n");
AHC_OUTB(ahc, SCBPTR, active_scb);
- UNPAUSE_SEQUENCER(ahc);
+ unpause_sequencer(ahc, /*unpause_always*/FALSE);
goto done;
}
/* Is the active SCB really active? */
else if((active_scbp->flags & SCB_ACTIVE) && bus_state){
AHC_OUTB(ahc, MSG_LEN, 1);
- AHC_OUTB(ahc, MSG0, MSG_BUS_DEVICE_RESET);
+ AHC_OUTB(ahc, MSG0, MSG_BUS_DEV_RESET);
AHC_OUTB(ahc, SCSISIGO, bus_state|ATNO);
sc_print_addr(active_scbp->xs->sc_link);
printf("asserted ATN - device reset in "
@@ -2899,7 +2944,7 @@ ahc_timeout(arg)
timeout(ahc_timeout, (caddr_t)active_scbp,
(2 * hz));
AHC_OUTB(ahc, SCBPTR, active_scb);
- UNPAUSE_SEQUENCER(ahc);
+ unpause_sequencer(ahc, /*unpause_always*/FALSE);
goto done;
}
}
@@ -3207,7 +3252,7 @@ ahc_reset_channel(ahc, channel, timedout_scb, xs_error, initiate_reset)
AHC_OUTB(ahc, CLRSINT1, CLRSCSIRSTI|CLRSELTIMEO);
AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
AHC_OUTB(ahc, SBLKCTL, sblkctl);
- UNPAUSE_SEQUENCER(ahc);
+ unpause_sequencer(ahc, /*unpause_always*/TRUE);
}
/* Case 2: A command from this bus is active or we're idle */
else {
@@ -3217,7 +3262,7 @@ ahc_reset_channel(ahc, channel, timedout_scb, xs_error, initiate_reset)
}
AHC_OUTB(ahc, CLRSINT1, CLRSCSIRSTI|CLRSELTIMEO);
AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
- RESTART_SEQUENCER(ahc);
+ restart_sequencer(ahc);
}
ahc_run_done_queue(ahc);
return found;
@@ -3251,3 +3296,32 @@ ahc_match_scb (scb, target, channel)
else
return ((chan == channel) && (targ == target));
}
+
+
+static void
+ahc_construct_sdtr(ahc, start_byte, period, offset)
+ struct ahc_data *ahc;
+ int start_byte;
+ u_int8_t period;
+ u_int8_t offset;
+{
+ AHC_OUTB(ahc, MSG0 + start_byte, MSG_EXTENDED);
+ AHC_OUTB(ahc, MSG1 + start_byte, MSG_EXT_SDTR_LEN);
+ AHC_OUTB(ahc, MSG2 + start_byte, MSG_EXT_SDTR);
+ AHC_OUTB(ahc, MSG3 + start_byte, period);
+ AHC_OUTB(ahc, MSG4 + start_byte, offset);
+ AHC_OUTB(ahc, MSG_LEN, start_byte + 5);
+}
+
+static void
+ahc_construct_wdtr(ahc, start_byte, bus_width)
+ struct ahc_data *ahc;
+ int start_byte;
+ u_int8_t bus_width;
+{
+ AHC_OUTB(ahc, MSG0 + start_byte, MSG_EXTENDED);
+ AHC_OUTB(ahc, MSG1 + start_byte, MSG_EXT_WDTR_LEN);
+ AHC_OUTB(ahc, MSG2 + start_byte, MSG_EXT_WDTR);
+ AHC_OUTB(ahc, MSG3 + start_byte, bus_width);
+ AHC_OUTB(ahc, MSG_LEN, start_byte + 4);
+}
diff --git a/sys/i386/scsi/aic7xxx.h b/sys/i386/scsi/aic7xxx.h
index 6bc3445..33d0261 100644
--- a/sys/i386/scsi/aic7xxx.h
+++ b/sys/i386/scsi/aic7xxx.h
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: aic7xxx.h,v 1.27 1996/05/10 16:21:05 gibbs Exp $
+ * $Id: aic7xxx.h,v 1.28 1996/05/30 07:19:59 gibbs Exp $
*/
#ifndef _AIC7XXX_H_
@@ -90,14 +90,14 @@
*/
-typedef unsigned long int physaddr;
+typedef u_int32_t physaddr;
#if defined(__FreeBSD__)
extern u_long ahc_unit;
#endif
struct ahc_dma_seg {
- physaddr addr;
- long len;
+ physaddr addr;
+ u_int32_t len;
};
typedef enum {
@@ -113,6 +113,7 @@ typedef enum {
AHC_AIC78X0 = 0x060, /* PCI Based Controller */
AHC_274 = 0x110, /* EISA Based Controller */
AHC_284 = 0x210, /* VL/ISA Based Controller */
+ AHC_294AU = 0x421, /* aic7860 based '2940' */
AHC_294 = 0x440, /* PCI Based Controller */
AHC_294U = 0x441, /* ULTRA PCI Based Controller */
AHC_394 = 0x840, /* Twin Channel PCI Controller */
@@ -143,18 +144,20 @@ typedef enum {
}ahc_flag;
typedef enum {
- SCB_FREE = 0x000,
- SCB_ACTIVE = 0x001,
- SCB_ABORTED = 0x002,
- SCB_DEVICE_RESET = 0x004,
- SCB_IMMED = 0x008,
- SCB_SENSE = 0x010,
- SCB_TIMEDOUT = 0x020,
- SCB_QUEUED_FOR_DONE = 0x040,
- SCB_PAGED_OUT = 0x080,
- SCB_WAITINGQ = 0x100,
- SCB_ASSIGNEDQ = 0x200,
- SCB_SENTORDEREDTAG = 0x400
+ SCB_FREE = 0x0000,
+ SCB_ACTIVE = 0x0001,
+ SCB_ABORTED = 0x0002,
+ SCB_DEVICE_RESET = 0x0004,
+ SCB_IMMED = 0x0008,
+ SCB_SENSE = 0x0010,
+ SCB_TIMEDOUT = 0x0020,
+ SCB_QUEUED_FOR_DONE = 0x0040,
+ SCB_PAGED_OUT = 0x0080,
+ SCB_WAITINGQ = 0x0100,
+ SCB_ASSIGNEDQ = 0x0200,
+ SCB_SENTORDEREDTAG = 0x0400,
+ SCB_MSGOUT_SDTR = 0x0800,
+ SCB_MSGOUT_WDTR = 0x1000
}scb_flag;
/*
@@ -173,7 +176,7 @@ struct scb {
/*8*/ u_char residual_SG_segment_count;
/*9*/ u_char residual_data_count[3];
/*12*/ physaddr data;
-/*16*/ u_long datalen; /* Really only three bits, but its
+/*16*/ u_int32_t datalen; /* Really only three bits, but its
* faster to treat it as a long on
* a quad boundary.
*/
diff --git a/sys/pci/aic7870.c b/sys/pci/aic7870.c
index f2436a6..0705f32 100644
--- a/sys/pci/aic7870.c
+++ b/sys/pci/aic7870.c
@@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: aic7870.c,v 1.36 1996/05/30 07:20:17 gibbs Exp $
+ * $Id: aic7870.c,v 1.37 1996/06/08 06:55:55 gibbs Exp $
*/
#if defined(__FreeBSD__)
@@ -81,6 +81,7 @@
#define PCI_DEVICE_ID_ADAPTEC_3940U 0x82789004ul
#define PCI_DEVICE_ID_ADAPTEC_2944U 0x84789004ul
#define PCI_DEVICE_ID_ADAPTEC_2940U 0x81789004ul
+#define PCI_DEVICE_ID_ADAPTEC_2940AU 0x61789004ul
#define PCI_DEVICE_ID_ADAPTEC_3940 0x72789004ul
#define PCI_DEVICE_ID_ADAPTEC_2944 0x74789004ul
#define PCI_DEVICE_ID_ADAPTEC_2940 0x71789004ul
@@ -216,6 +217,9 @@ aic7870_probe (pcici_t tag, pcidi_t type)
case PCI_DEVICE_ID_ADAPTEC_2940:
return ("Adaptec 2940 SCSI host adapter");
break;
+ case PCI_DEVICE_ID_ADAPTEC_2940AU:
+ return ("Adaptec 2940A Ultra SCSI host adapter");
+ break;
case PCI_DEVICE_ID_ADAPTEC_AIC7880:
return ("Adaptec aic7880 Ultra SCSI host adapter");
break;
@@ -258,6 +262,7 @@ ahc_pci_probe(parent, match, aux)
case PCI_DEVICE_ID_ADAPTEC_3940U:
case PCI_DEVICE_ID_ADAPTEC_2944U:
case PCI_DEVICE_ID_ADAPTEC_2940U:
+ case PCI_DEVICE_ID_ADAPTEC_2940AU:
case PCI_DEVICE_ID_ADAPTEC_3940:
case PCI_DEVICE_ID_ADAPTEC_2944:
case PCI_DEVICE_ID_ADAPTEC_2940:
@@ -345,6 +350,9 @@ ahc_pci_attach(parent, self, aux)
case PCI_DEVICE_ID_ADAPTEC_2940:
ahc_t = AHC_294;
break;
+ case PCI_DEVICE_ID_ADAPTEC_2940AU:
+ ahc_t = AHC_294AU;
+ break;
case PCI_DEVICE_ID_ADAPTEC_AIC7880:
ahc_t = AHC_AIC7880;
break;
@@ -439,11 +447,12 @@ ahc_pci_attach(parent, self, aux)
return;
}
intrstr = pci_intr_string(pa->pa_pc, ih);
- ahc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ahc_intr, ahc
#ifdef __OpenBSD__
- , ahc->sc_dev.dv_xname
+ ahc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ahc_intr, ahc,
+ ahc->sc_dev.dv_xname);
+#else
+ ahc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ahc_intr, ahc);
#endif
- );
if (ahc->sc_ih == NULL) {
printf("%s: couldn't establish interrupt",
ahc->sc_dev.dv_xname);
@@ -487,14 +496,11 @@ ahc_pci_attach(parent, self, aux)
load_seeprom(ahc);
break;
}
+ case AHC_294AU:
case AHC_AIC7860:
{
id_string = "aic7860 ";
- /*
- * Use defaults, if the chip wasn't initialized by
- * a BIOS.
- */
- ahc->flags |= AHC_USEDEFAULTS;
+ load_seeprom(ahc);
break;
}
case AHC_AIC7850:
OpenPOWER on IntegriCloud