aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/i386/scsi/aic7xxx.c191
-rw-r--r--sys/i386/scsi/aic7xxx.h20
2 files changed, 125 insertions, 86 deletions
diff --git a/sys/i386/scsi/aic7xxx.c b/sys/i386/scsi/aic7xxx.c
index 939de0735b4a..02cb5ffaab58 100644
--- a/sys/i386/scsi/aic7xxx.c
+++ b/sys/i386/scsi/aic7xxx.c
@@ -24,14 +24,13 @@
*
* commenced: Sun Sep 27 18:14:01 PDT 1992
*
- * $Id: aic7xxx.c,v 1.9 1995/01/13 02:24:30 gibbs Exp $
+ * $Id: aic7xxx.c,v 1.10 1995/01/13 02:27:08 gibbs Exp $
*/
/*
* TODO:
* Add target reset capabilities
* Implement Target Mode
* Implement Tagged Queuing
- * 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
@@ -46,8 +45,6 @@
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/user.h>
-#include <i386/isa/isa.h>
-#include <i386/isa/isa_device.h>
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#include <machine/cpufunc.h>
@@ -320,12 +317,13 @@ struct scsi_device ahc_dev =
#define INTSTAT 0xc91ul
#define SEQINT_MASK 0xf0 /* SEQINT Status Codes */
#define BAD_PHASE 0x00
-#define MSG_REJECT 0x10
+#define SEND_REJECT 0x10
#define NO_IDENT 0x20
#define NO_MATCH 0x30
#define MSG_SDTR 0x40
-#define BAD_STATUS 0x50
-#define MSG_WDTR 0x60
+#define MSG_WDTR 0x50
+#define MSG_REJECT 0x60
+#define BAD_STATUS 0x70
#define BRKADRINT 0x08
#define SCSIINT 0x04
#define CMDCMPLT 0x02
@@ -434,16 +432,10 @@ struct scsi_device ahc_dev =
#define HA_SIGSTATE 0xc4dul
-#define HA_NEEDWDTR0 0xc34ul
-#define HA_NEEDWDTR1 0xc35ul
-#define HA_NEEDSDTR0 0xc4eul
-#define HA_NEEDSDTR1 0xc4ful
-
#define HA_SCBCOUNT 0xc56ul
#define HA_FLAGS 0xc57ul
#define TWIN_BUS 0x01
#define WIDE_BUS 0x02
-#define CHECK_DTR 0x08
#define SENSE 0x10
#define ACTIVE_MSG 0x20
#define IDENTIFY_SEEN 0x40
@@ -688,15 +680,6 @@ ahc_attach(unit)
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;
}
@@ -710,17 +693,7 @@ ahc_send_scb( ahc, scb )
PAUSE_SEQUENCER(ahc);
- old_scbptr = inb(SCBPTR + iobase);
- outb(SCBPTR + iobase, scb->position);
-
- outb(SCBCNT + iobase, SCBAUTO);
-
- outsb(SCBARRAY + iobase, scb, SCB_DOWN_SIZE);
-
- outb(SCBCNT + iobase, 0);
-
outb(QINFIFO + iobase, scb->position);
- outb(SCBPTR + iobase, old_scbptr);
UNPAUSE_SEQUENCER(ahc);
}
@@ -789,7 +762,7 @@ ahcintr(unit)
panic("ahc%d: unknown scsi bus phase. "
"Attempting to continue\n", unit);
break;
- case MSG_REJECT:
+ case SEND_REJECT:
printf("ahc%d: Warning - "
"message reject, message type: 0x%x\n", unit,
inb(HA_REJBYTE + iobase));
@@ -816,6 +789,7 @@ ahcintr(unit)
}
active = inb(active_port);
active &= ~(0x01 << (target & 0x07));
+ outb(SCBARRAY + iobase, SCB_NEEDDMA);
outb(active_port, active);
outb(CLRSINT1 + iobase, CLRSELTIMEO);
RESTART_SEQUENCER(ahc);
@@ -824,7 +798,6 @@ ahcintr(unit)
case MSG_SDTR:
{
int loc;
- u_short needsdtr;
u_char scsi_id, offset, rate, targ_scratch;
/*
* Help the sequencer to translate the
@@ -849,19 +822,14 @@ ahcintr(unit)
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))
+ if(ahc->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);
+ ahc->needsdtr &= ~(0x01 << scsi_id);
+
outb(HA_RETURN_1 + iobase, 0);
}
else{
@@ -876,36 +844,26 @@ ahcintr(unit)
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))
+ if(ahc->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);
+ ahc->needwdtr &= ~(0x01 << scsi_id);
outb(HA_RETURN_1 + iobase, 0);
switch(bus_width)
{
@@ -951,6 +909,52 @@ ahcintr(unit)
outb(SCSIRATE + iobase, scratch);
break;
}
+ case MSG_REJECT:
+ {
+ /*
+ * 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;
+ u_char scsi_id = inb(SCSIID + iobase) >> 0x4;
+ u_short mask;
+
+ if(inb(SBLKCTL + iobase) & 0x08)
+ /* B channel */
+ scsi_id += 8;
+
+ targ_scratch = inb(HA_TARG_SCRATCH + iobase
+ + scsi_id);
+
+ mask = (0x01 << scsi_id);
+ if(ahc->needsdtr & mask){
+ /* note asynch xfers and clear flag */
+ targ_scratch &= 0xf0;
+ ahc->needsdtr &= ~mask;
+ printf("ahc%d: target %d refusing "
+ "syncronous negotiation. Using "
+ "asyncronous transfers\n",
+ unit, scsi_id);
+ }
+ if(ahc->needwdtr & mask){
+ /* note 8bit xfers and clear flag */
+ targ_scratch &= 0x7f;
+ ahc->needwdtr &= ~mask;
+ printf("ahc%d: target %d refusing "
+ "WIDE negotiation. Using "
+ "8bit transfers\n",
+ unit, scsi_id);
+ }
+ outb(HA_TARG_SCRATCH + iobase + scsi_id,
+ targ_scratch);
+ /*
+ * Otherwise, we ignore it.
+ */
+ break;
+ }
case BAD_STATUS:
{
int scb_index, saved_scb_index;
@@ -1016,6 +1020,7 @@ ahcintr(unit)
#endif
bzero(scb, SCB_DOWN_SIZE);
scb->flags |= SCB_SENSE;
+ scb->control = SCB_NEEDDMA;
sc->op_code = REQUEST_SENSE;
sc->byte2 = xs->sc_link->lun << 5;
sc->length = sizeof(struct scsi_sense_data);
@@ -1029,18 +1034,17 @@ ahcintr(unit)
scb->cmdpointer = KVTOPHYS(sc);
scb->cmdlen = sizeof(*sc);
- /*
- * Download new command.
- */
- outb(SCBCNT + iobase, 0x80);
+ 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);
+ break;
}
/*
* Clear the SCB_SENSE Flag and have
@@ -1125,7 +1129,10 @@ clear:
~(0x01 << (xs->sc_link->target & 0x07));
outb(active_port, active);
+ outb(SCBARRAY + iobase, SCB_NEEDDMA);
+
outb(CLRSINT1 + iobase, CLRSELTIMEO);
+
RESTART_SEQUENCER(ahc);
outb(CLRINT + iobase, CLRINTSTAT);
@@ -1279,14 +1286,13 @@ ahc_init(unit)
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:
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 + iobase, WIDE_BUS|CHECK_DTR);
+ outb(HA_FLAGS + iobase, WIDE_BUS);
break;
case 8:
ahc->our_id = (inb(HA_SCSICONF + iobase) & HSCSIID);
@@ -1294,7 +1300,7 @@ ahc_init(unit)
printf("Twin Channel, A SCSI Id=%d, B SCSI Id=%d, ",
ahc->our_id, ahc->our_id_b);
ahc->type += 1;
- outb(HA_FLAGS + iobase, TWIN_BUS|CHECK_DTR);
+ outb(HA_FLAGS + iobase, TWIN_BUS);
break;
default:
printf(" Unsupported adapter type. Ignoring\n");
@@ -1366,17 +1372,17 @@ ahc_init(unit)
* negotiation to that target so we don't activate the needsdr
* flag.
*/
- ahc->needsdtr = 0;
- ahc->needwdtr = 0;
+ ahc->needsdtr_orig = 0;
+ ahc->needwdtr_orig = 0;
for(i = 0; i < 16; i++){
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 */
+ ahc->needsdtr_orig |= (0x01 << i);
+ /* Default to a syncronous offset of 15 */
target_settings |= 0x0f;
}
if(target_settings & 0x80){
- ahc->needwdtr |= (0x01 << i);
+ ahc->needwdtr_orig |= (0x01 << i);
/*
* We'll set the Wide flag when we
* are successful with Wide negotiation,
@@ -1387,10 +1393,8 @@ ahc_init(unit)
}
outb(HA_TARG_SCRATCH+i+iobase,target_settings);
}
- 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);
+ ahc->needsdtr = ahc->needsdtr_orig;
+ ahc->needwdtr = ahc->needwdtr_orig;
/*
* Set the number of availible SCBs
*/
@@ -1440,12 +1444,14 @@ ahc_scsi_cmd(xs)
int thiskv;
physaddr thisphys, nextphys;
int unit = xs->sc_link->adapter_unit;
+ u_short mask = (0x01 << (xs->sc_link->target
+ | ((u_long)xs->sc_link->fordriver & 0x08)));
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
+ * 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
@@ -1479,13 +1485,17 @@ ahc_scsi_cmd(xs)
scb->xs = xs;
if (flags & SCSI_RESET) {
- /* AR: Needs Implementation */
+ /* XXX: Needs Implementation */
printf("ahc0: SCSI_RESET called.\n");
}
/*
* Put all the arguments for the xfer in the scb
*/
+ if(ahc->needsdtr & mask)
+ scb->control |= SCB_NEEDSDTR;
+ if(ahc->needwdtr & mask)
+ scb->control |= SCB_NEEDWDTR;
scb->target_channel_lun = ((xs->sc_link->target << 4) & 0xF0) |
((u_long)xs->sc_link->fordriver & 0x08) |
xs->sc_link->lun & 0x07;
@@ -1663,6 +1673,9 @@ ahc_get_scb(unit, flags)
scbp = (struct scb *) malloc(sizeof(struct scb),
M_TEMP, M_NOWAIT);
if (scbp) {
+ physaddr scbaddr = KVTOPHYS(scbp);
+ u_long iobase = ahc->baseport;
+ u_char curscb;
bzero(scbp, sizeof(struct scb));
scbp->position = ahc->numscbs;
ahc->numscbs++;
@@ -1675,6 +1688,25 @@ ahc_get_scb(unit, flags)
* load it into.
*/
ahc->scbarray[scbp->position] = scbp;
+
+ /*
+ * Initialize the host memory location
+ * of this SCB down on the board and
+ * flag that it should be DMA's before
+ * reference.
+ */
+ scbp->control = SCB_NEEDDMA;
+ scbp->host_scb = scbaddr;
+ PAUSE_SEQUENCER(ahc);
+ curscb = inb(SCBPTR + iobase);
+ outb(SCBPTR + iobase, scbp->position);
+ outb(SCBCNT + iobase, 0x80);
+ outsb(SCBARRAY+iobase,scbp,30);
+ outb(SCBCNT + iobase, 0);
+ outb(SCBPTR + iobase, curscb);
+ UNPAUSE_SEQUENCER(ahc);
+ scbp->control = 0;
+
} else {
printf("ahc%d: Can't malloc SCB\n", unit);
} goto gottit;
@@ -1804,26 +1836,25 @@ ahc_abort_scb( unit, ahc, scb )
* If there's a message in progress,
* reset the bus and have all devices renegotiate.
*/
+ int i;
u_char flags;
if(scb->target_channel_lun & 0x08){
- outb(HA_NEEDSDTR1 + iobase, ahc->needsdtr >> 8);
+ ahc->needsdtr |= (ahc->needsdtr_orig & 0xff00);
outb(HA_ACTIVE1, 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);
+ ahc->needsdtr = ahc->needsdtr_orig;
+ ahc->needwdtr = ahc->needwdtr_orig;
outb(HA_ACTIVE0, 0);
outb(HA_ACTIVE1, 0);
}
else{
- outb(HA_NEEDSDTR0 + iobase, ahc->needsdtr & 0xff);
+ ahc->needsdtr = ahc->needsdtr_orig;
outb(HA_ACTIVE0, 0);
}
- flags = inb(HA_FLAGS + iobase);
- outb(HA_FLAGS + iobase, flags | CHECK_DTR);
+
+ /* Reset the bus */
outb(SCSISEQ + iobase, SCSIRSTO);
DELAY(50);
outb(SCSISEQ + iobase, 0);
diff --git a/sys/i386/scsi/aic7xxx.h b/sys/i386/scsi/aic7xxx.h
index 23fa9bc643d9..c009abb88422 100644
--- a/sys/i386/scsi/aic7xxx.h
+++ b/sys/i386/scsi/aic7xxx.h
@@ -19,6 +19,8 @@
* Justin T. Gibbs.
* 4. Modifications may be freely made to this file if the above conditions
* are met.
+ *
+ * $Id$
*/
#ifndef _AIC7XXX_H_
@@ -68,8 +70,11 @@ typedef enum {
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_NEEDWDTR 0x80 /* Initiate Wide Negotiation */
+#define SCB_NEEDSDTR 0x40 /* Initiate Sync Negotiation */
+#define SCB_NEEDDMA 0x08 /* SCB needs to be DMA'd from
+ * from host memory
+ */
#define SCB_TE 0x20 /* Tag enable */
#define SCB_WAITING 0x06
#define SCB_DIS 0x04
@@ -86,16 +91,17 @@ struct scb {
/*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 */
+#define SCB_DOWN_SIZE 19 /* amount to actually download */
/*23*/ physaddr data __attribute__ ((packed));
/*26*/ u_char datalen[3];
#define SCB_UP_SIZE 26 /* amount to actually upload */
+/*30*/ physaddr host_scb __attribute__ ((packed));
#if 0
/*
* No real point in transferring this to the
* SCB registers.
*/
- unsigned char RESERVED[6];
+ unsigned char RESERVED[2];
#endif
/*-----------------end of hardware supported fields----------------*/
struct scb *next; /* in free list */
@@ -126,8 +132,10 @@ struct ahc_data {
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 */
+ u_short needsdtr_orig; /* Targets we initiate sync neg with */
+ u_short needwdtr_orig; /* Targets we initiate wide neg with */
+ u_short needsdtr; /* Current list of negotiated targets */
+ u_short needwdtr; /* Current list of negotiated targets */
int numscbs;
u_char maxscbs;
int unpause;