summaryrefslogtreecommitdiffstats
path: root/sys/i386/scsi
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1995-01-16 16:33:47 +0000
committergibbs <gibbs@FreeBSD.org>1995-01-16 16:33:47 +0000
commitcd232c506dc892f127bbf3eb3bdb5a0f241536bd (patch)
tree952ea58d6ffe8204d7660b736dd859d6b9b4e026 /sys/i386/scsi
parent6617f0bfe4d1654732497ad58c96fbfb228130df (diff)
downloadFreeBSD-src-cd232c506dc892f127bbf3eb3bdb5a0f241536bd.zip
FreeBSD-src-cd232c506dc892f127bbf3eb3bdb5a0f241536bd.tar.gz
Add $Ids. Use DMA for downloading SCBs to the sequencer. Implement SDTR,
WDTR, and message reject handlers so they don't need to exist in the sequencer. All three of these cases are not on the critical path, so it makes little sense to use up precious sequencer ram for them.
Diffstat (limited to 'sys/i386/scsi')
-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 939de07..02cb5ff 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 23fa9bc..c009abb 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;
OpenPOWER on IntegriCloud