summaryrefslogtreecommitdiffstats
path: root/sys/i386/scsi
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1995-04-27 17:47:17 +0000
committergibbs <gibbs@FreeBSD.org>1995-04-27 17:47:17 +0000
commit6d4922284e443a79fe57e4f1cf48e7a3b3acacf1 (patch)
tree6c1b59ca108457f29cdacd794e902e17b40a388c /sys/i386/scsi
parent59c33f4bae158ee6d37c79fab9b10137727af2ce (diff)
downloadFreeBSD-src-6d4922284e443a79fe57e4f1cf48e7a3b3acacf1.zip
FreeBSD-src-6d4922284e443a79fe57e4f1cf48e7a3b3acacf1.tar.gz
Additions to support the WAITING_SCB list that the sequencer maintains.
It is the kernel driver's responsibility to do the list manipulation whenever a selection timeout or a request sense occurs. Print out the interrupt type that the device has been set to. It seems that one of the Asus motherboards botches this and David thought a diagnostic would be nice. Fix a bug in my diagnostic code that David found. Reviewed by: Wcarchive and David Greenman
Diffstat (limited to 'sys/i386/scsi')
-rw-r--r--sys/i386/scsi/aic7xxx.c113
-rw-r--r--sys/i386/scsi/aic7xxx.h12
2 files changed, 90 insertions, 35 deletions
diff --git a/sys/i386/scsi/aic7xxx.c b/sys/i386/scsi/aic7xxx.c
index c6a739a..fae9c76 100644
--- a/sys/i386/scsi/aic7xxx.c
+++ b/sys/i386/scsi/aic7xxx.c
@@ -24,7 +24,7 @@
*
* commenced: Sun Sep 27 18:14:01 PDT 1992
*
- * $Id: aic7xxx.c,v 1.21 1995/04/15 21:37:32 gibbs Exp $
+ * $Id: aic7xxx.c,v 1.22 1995/04/23 22:04:57 gibbs Exp $
*/
/*
* TODO:
@@ -77,7 +77,7 @@ int ahc_unit = 0;
#define AHC_SHOWMISC 0x0001
#define AHC_SHOWCMDS 0x0002
#define AHC_SHOWSCBS 0x0004
-/*#define AHC_DEBUG*/
+/* #define AHC_DEBUG */
int ahc_debug = AHC_SHOWMISC;
/**** bit definitions for SCSIDEF ****/
@@ -459,6 +459,7 @@ struct scsi_device ahc_dev =
*/
#define HA_ARG_1 0xc4aul
#define HA_RETURN_1 0xc4aul
+#define SEND_SENSE 0x80
#define SEND_WDTR 0x80
#define SEND_SDTR 0x80
#define SEND_REJ 0x40
@@ -470,7 +471,6 @@ struct scsi_device ahc_dev =
#define SINGLE_BUS 0x00
#define TWIN_BUS 0x01
#define WIDE_BUS 0x02
-#define SENSE 0x10
#define ACTIVE_MSG 0x20
#define IDENTIFY_SEEN 0x40
#define RESELECTING 0x80
@@ -478,6 +478,8 @@ struct scsi_device ahc_dev =
#define HA_ACTIVE0 0xc54ul
#define HA_ACTIVE1 0xc55ul
#define SAVED_TCL 0xc56ul
+#define WAITING_SCBH 0xc57ul
+#define WAITING_SCBT 0xc58ul
#define HA_SCSICONF 0xc5aul
#define INTDEF 0xc5cul
@@ -705,7 +707,6 @@ ahc_attach(unit)
*/
printf("ahc%d: Probing channel A\n", unit);
scsi_attachdevs(&(ahc->sc_link));
-
if(ahc->type & AHC_TWIN) {
/* Configure the second scsi bus */
ahc->sc_link_b = ahc->sc_link;
@@ -713,7 +714,6 @@ ahc_attach(unit)
printf("ahc%d: Probing Channel B\n", unit);
scsi_attachdevs(&(ahc->sc_link_b));
}
-
return 1;
}
@@ -725,8 +725,7 @@ ahc_send_scb( ahc, scb )
u_long iobase = ahc->baseport;
PAUSE_SEQUENCER(ahc);
- outb(QINFIFO + iobase, scb->position);
-
+ outb(QINFIFO + iobase, scb->position);
UNPAUSE_SEQUENCER(ahc);
}
@@ -839,7 +838,7 @@ ahcintr(unit)
offset = inb(ACCUM + iobase);
scsi_id = inb(SCSIID + iobase) >> 0x4;
ahc_scsirate(&rate, transfer, offset, unit,
- scsi_id);
+ scsi_id);
if(inb(SBLKCTL + iobase) & 0x08)
/* B channel */
scsi_id += 8;
@@ -1059,6 +1058,8 @@ ahcintr(unit)
if((xs->error == XS_NOERROR) &&
!(scb->flags & SCB_SENSE)) {
u_char flags;
+ u_char head;
+ u_char tail;
struct ahc_dma_seg *sg = scb->ahc_dma;
struct scsi_sense *sc = &(scb->sense_cmd);
u_char control = scb->control;
@@ -1073,7 +1074,7 @@ ahcintr(unit)
#endif
bzero(scb, SCB_DOWN_SIZE);
scb->flags |= SCB_SENSE;
- scb->control = control & SCB_TE;
+ scb->control = (control & SCB_TE);
sc->op_code = REQUEST_SENSE;
sc->byte2 = xs->sc_link->lun << 5;
sc->length = sizeof(struct scsi_sense_data);
@@ -1091,13 +1092,35 @@ ahcintr(unit)
outb(SCBCNT + iobase, 0x80);
outsb(SCBARRAY+iobase,scb,SCB_DOWN_SIZE);
outb(SCBCNT + iobase, 0);
+ outb(SCBARRAY+iobase+30,SCB_LIST_NULL);
- flags = inb(HA_FLAGS + iobase);
- /*
- * Have the sequencer handle the sense
- * request
+ /*
+ * Add this SCB to the "waiting for
+ * selection" list.
*/
- outb(HA_FLAGS + iobase, flags | SENSE);
+ head = inb(WAITING_SCBH + iobase);
+ tail = inb(WAITING_SCBT + iobase);
+ if(head & SCB_LIST_NULL) {
+ /* List was empty */
+ head = scb->position;
+ tail = SCB_LIST_NULL;
+ }
+ else if(tail & SCB_LIST_NULL) {
+ /* List had one element */
+ tail = scb->position;
+ outb(SCBPTR+iobase,head);
+ outb(SCBARRAY+iobase+30,
+ tail);
+ }
+ else {
+ outb(SCBPTR+iobase,tail);
+ tail = scb->position;
+ outb(SCBARRAY+iobase+30,
+ tail);
+ }
+ outb(WAITING_SCBH + iobase, head);
+ outb(WAITING_SCBT + iobase, tail);
+ outb(HA_RETURN_1 + iobase, SEND_SENSE);
break;
}
/*
@@ -1108,6 +1131,7 @@ ahcintr(unit)
* we already had.
*/
scb->flags &= ~SCB_SENSE;
+ outb(HA_RETURN_1 + iobase, 0);
if(xs->error == XS_NOERROR)
xs->error = XS_DRIVER_STUFFUP;
break;
@@ -1212,16 +1236,18 @@ clear:
if (status & SELTO) {
u_char active;
+ u_char waiting;
u_char flags;
u_long active_port = HA_ACTIVE0 + iobase;
- outb(SCSISEQ + iobase, 0);
+ outb(SCSISEQ + iobase, ENRSELI);
xs->error = XS_TIMEOUT;
/*
* Clear any pending messages for the timed out
* target, and mark the target as free
*/
flags = inb( HA_FLAGS + iobase );
- outb(HA_FLAGS + iobase, flags & ~ACTIVE_MSG);
+ outb(HA_FLAGS + iobase,
+ flags & ~ACTIVE_MSG);
if (scb->target_channel_lun & 0x88)
active_port++;
@@ -1234,9 +1260,15 @@ clear:
outb(CLRSINT1 + iobase, CLRSELTIMEO);
- RESTART_SEQUENCER(ahc);
-
outb(CLRINT + iobase, CLRSCSIINT);
+
+ /* Shift the waiting for selection queue forward */
+ waiting = inb(WAITING_SCBH + iobase);
+ outb(SCBPTR + iobase, waiting);
+ waiting = inb(SCBARRAY + iobase + 30);
+ outb(WAITING_SCBH + iobase, waiting);
+
+ RESTART_SEQUENCER(ahc);
}
if (status & SCSIPERR) {
@@ -1370,8 +1402,8 @@ ahc_init(unit)
{
struct ahc_data *ahc = ahcdata[unit];
u_long iobase = ahc->baseport;
- u_char scsi_conf, sblkctl;
- int intdef, i, max_targ = 16, wait;
+ u_char scsi_conf, sblkctl, i;
+ int intdef, max_targ = 16, wait;
/*
* Assume we have a board at this stage
@@ -1496,6 +1528,12 @@ ahc_init(unit)
else
printf("aic7870, ");
printf("%d SCBs\n", ahc->maxscbs);
+
+ if(ahc->pause & IRQMS)
+ printf("ahc%d: Using Level Sensitive Interrupts\n", unit);
+ else
+ printf("ahc%d: Using Edge Triggered Interrupts\n", unit);
+
if(!(ahc->type & AHC_AIC7870)){
/*
* The 294x cards are PCI, so we get their interrupt from the PCI
@@ -1594,6 +1632,15 @@ ahc_init(unit)
ahc->wdtrpending = 0;
ahc->tagenable = 0;
+ /*
+ * Clear the control byte for every SCB so that the sequencer
+ * doesn't get confused and think that one of them is valid
+ */
+ for(i = 0; i < ahc->maxscbs; i++) {
+ outb(SCBPTR + iobase, i);
+ outb(SCBARRAY + iobase, 0);
+ }
+
#ifdef AHC_DEBUG
printf("NEEDSDTR == 0x%x\nNEEDWDTR == 0x%x\n", ahc->needsdtr,
ahc->needwdtr);
@@ -1607,6 +1654,9 @@ ahc_init(unit)
outb( HA_ACTIVE0 + iobase, 0 );
outb( HA_ACTIVE1 + iobase, 0 );
+ /* We don't have any waiting selections */
+ outb( WAITING_SCBH + iobase, SCB_LIST_NULL );
+ outb( WAITING_SCBT + iobase, SCB_LIST_NULL );
/*
* Load the Sequencer program and Enable the adapter.
* Place the aic7770 in fastmode which makes a big
@@ -1893,10 +1943,10 @@ ahc_get_scb(unit, flags)
physaddr scbaddr = KVTOPHYS(scbp);
u_long iobase = ahc->baseport;
u_char curscb;
- bzero(scbp, sizeof(struct scb));
+ bzero(scbp, sizeof(struct scb));
scbp->position = ahc->numscbs;
- ahc->numscbs++;
- scbp->flags = SCB_ACTIVE;
+ ahc->numscbs++;
+ scbp->flags = SCB_ACTIVE;
/*
* Place in the scbarray
* Never is removed. Position
@@ -1907,23 +1957,26 @@ ahc_get_scb(unit, flags)
ahc->scbarray[scbp->position] = scbp;
/*
- * Initialize the host memory location
+ * Initialize the host memory location
* of this SCB down on the board and
- * flag that it should be DMA's before
- * reference.
- */
+ * flag that it should be DMA's before
+ * reference. Also set its psuedo
+ * next pointer (for use in the psuedo
+ * list of SCBs waiting for selection)
+ * to SCB_LIST_NULL.
+ */
scbp->control = SCB_NEEDDMA;
scbp->host_scb = scbaddr;
+ scbp->next_waiting = SCB_LIST_NULL;
PAUSE_SEQUENCER(ahc);
curscb = inb(SCBPTR + iobase);
outb(SCBPTR + iobase, scbp->position);
outb(SCBCNT + iobase, 0x80);
- outsb(SCBARRAY+iobase,scbp,30);
+ outsb(SCBARRAY+iobase,scbp,31);
outb(SCBCNT + iobase, 0);
outb(SCBPTR + iobase, curscb);
UNPAUSE_SEQUENCER(ahc);
scbp->control = 0;
-
} else {
printf("ahc%d: Can't malloc SCB\n", unit);
}
@@ -2130,7 +2183,7 @@ ahc_timeout(void *arg1)
#endif
#ifdef AHC_DEBUG
if (ahc_debug & AHC_SHOWSCBS)
- ahc_print_active_scb(unit);
+ ahc_print_active_scb(ahc);
#endif /*AHC_DEBUG */
/*
diff --git a/sys/i386/scsi/aic7xxx.h b/sys/i386/scsi/aic7xxx.h
index c96c696..8108803 100644
--- a/sys/i386/scsi/aic7xxx.h
+++ b/sys/i386/scsi/aic7xxx.h
@@ -20,7 +20,7 @@
* 4. Modifications may be freely made to this file if the above conditions
* are met.
*
- * $Id: aic7xxx.h,v 1.5 1995/03/31 13:54:41 gibbs Exp $
+ * $Id: aic7xxx.h,v 1.6 1995/04/23 22:04:58 gibbs Exp $
*/
#ifndef _AIC7XXX_H_
@@ -70,9 +70,7 @@ struct scb {
#define SCB_NEEDWDTR 0x80 /* Initiate Wide Negotiation */
#define SCB_NEEDSDTR 0x40 /* Initiate Sync Negotiation */
#define SCB_TE 0x20 /* Tag enable */
-#define SCB_NEEDDMA 0x08 /* SCB needs to be DMA'd from
- * from host memory
- */
+#define SCB_NEEDDMA 0x08 /* Refresh SCB from host ram */
#define SCB_DIS 0x04
#define SCB_TAG_TYPE 0x3
#define SIMPLE_QUEUE 0x0
@@ -99,12 +97,16 @@ struct scb {
* a request sense.
*/
/*30*/ physaddr host_scb __attribute__ ((packed));
+/*31*/ u_char next_waiting; /* Used to thread SCBs awaiting
+ * selection
+ */
+#define SCB_LIST_NULL 0x10 /* SCB list equivelent to NULL */
#if 0
/*
* No real point in transferring this to the
* SCB registers.
*/
- unsigned char RESERVED[2];
+ unsigned char RESERVED[1];
#endif
/*-----------------end of hardware supported fields----------------*/
struct scb *next; /* in free list */
OpenPOWER on IntegriCloud