summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1995-10-26 23:57:18 +0000
committergibbs <gibbs@FreeBSD.org>1995-10-26 23:57:18 +0000
commitd765a11e8116129e9894feca8248f51fc2ec88c0 (patch)
tree073776e9be1a9fc1548bfb316f3c9a9a1af995c6
parent52751dc395020f119e477790814ed95d8901820b (diff)
downloadFreeBSD-src-d765a11e8116129e9894feca8248f51fc2ec88c0.zip
FreeBSD-src-d765a11e8116129e9894feca8248f51fc2ec88c0.tar.gz
Properly deal with the Ultra series of adapters. We should now understand
the new seeprom format and negotiate up to 20MHz sync if set in SCSI-Select. Reduce the complexity of the timeout code by running it at splhigh(). Fix a bug that caused rescheduled timeouts at 0 clock ticks in the future causing an infinite loop. Obtained from: Timeout bug noticed by David Greenman and wcarchive.
-rw-r--r--sys/i386/scsi/aic7xxx.c183
-rw-r--r--sys/i386/scsi/aic7xxx.h10
2 files changed, 108 insertions, 85 deletions
diff --git a/sys/i386/scsi/aic7xxx.c b/sys/i386/scsi/aic7xxx.c
index 5969e42..9a0e6ab 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.37 1995/08/23 23:03:17 gibbs Exp $
+ * $Id: aic7xxx.c,v 1.38 1995/09/05 23:52:02 gibbs Exp $
*/
/*
* TODO:
@@ -62,7 +62,6 @@ void ahc_loadseq __P((u_long iobase));
int32 ahc_scsi_cmd();
timeout_t ahc_timeout;
void ahc_done __P((int unit, struct scb *scbp));
-void ahc_timeout_done __P((int unit, struct scb *scbp));
struct scb *ahc_get_scb __P((int unit, int flags));
void ahc_free_scb();
void ahc_scb_timeout __P((int unit, struct ahc_data *ahc, struct scb *scb));
@@ -151,6 +150,20 @@ struct scsi_device ahc_dev =
#define SCSIRSTO 0x01
/*
+ * SCSI Transfer Control 0 Register (pp. 3-13).
+ * Controls the SCSI module data path.
+ */
+#define SXFRCTL0 0xc01ul
+#define DFON 0x80
+#define DFPEXP 0x40
+#define ULTRAEN 0x20
+#define CLRSTCNT 0x10
+#define SPIOEN 0x80
+#define SCAMEN 0x40
+#define CLRCHN 0x20
+/* UNUSED 0x01 */
+
+/*
* SCSI Transfer Control 1 Register (pp. 3-14,15).
* Controls the SCSI module data path.
*/
@@ -641,7 +654,8 @@ struct seeprom_config {
/*
* Host Adapter Control Bits
*/
-/* UNUSED 0x0003 */
+/* UNUSED 0x0001 */
+#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable (Ultra cards) */
#define CFSTERM 0x0004 /* SCSI low byte termination (non-wide cards) */
#define CFWSTERM 0x0008 /* SCSI high byte termination (wide card) */
#define CFSPARITY 0x0010 /* SCSI parity */
@@ -757,17 +771,23 @@ static struct {
*/
static struct {
short sxfr;
+ /* Rates in Ultra mode have bit 8 of sxfr set */
+#define ULTRA_SXFR 0x100
short period; /* in ns */
char *rate;
} ahc_syncrates[] = {
- { 0x00, 100, "10.0" },
- { 0x10, 125, "8.0" },
- { 0x20, 150, "6.67" },
- { 0x30, 175, "5.7" },
- { 0x40, 200, "5.0" },
- { 0x50, 225, "4.4" },
- { 0x60, 250, "4.0" },
- { 0x70, 275, "3.6" }
+ { 0x100, 50, "20.0" },
+ { 0x110, 62, "16.0" },
+ { 0x120, 75, "13.4" },
+ { 0x140, 100, "10.0" },
+ { 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" }
};
static int ahc_num_syncrates =
@@ -842,10 +862,37 @@ void ahc_scsirate(scsirate, period, offset, unit, target )
int unit, target;
{
int i;
+ struct ahc_data *ahc = ahcdata[unit];
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) {
+ if (!(ahc_syncrates[i].sxfr & ULTRA_SXFR)) {
+ printf("ahc%d: target %d requests "
+ "%sMB/s transfers, but adapter "
+ "in Ultra mode can only sync at "
+ "10MB/s or above\n", unit,
+ target, ahc_syncrates[i].rate);
+ break; /* Use Async */
+ }
+ }
+ else {
+ if (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) | (offset & 0x0f);
if(bootverbose) {
printf("ahc%d: target %d synchronous at %sMB/s,"
@@ -1816,7 +1863,10 @@ ahc_init(unit)
}
case AHC_AIC7850:
case AHC_AIC7870:
+ case AHC_AIC7880:
+ case AHC_394U:
case AHC_394:
+ case AHC_294U:
case AHC_294:
host_id = 0x07; /* default to SCSI ID 7 for 7850 */
if (ahc->type & AHC_AIC7870) {
@@ -1877,7 +1927,15 @@ ahc_init(unit)
break;
default:
};
-
+ if(ahc->type & AHC_ULTRA) {
+ printf("Ultra ");
+ if(have_seeprom) {
+ /* Should we enable Ultra mode? */
+ if(!(sc.adapter_control & CFULTRAEN))
+ /* Treat it like a normal card */
+ ahc->type &= ~AHC_ULTRA;
+ }
+ }
/* Determine channel configuration and who we are on the scsi bus. */
switch ( (sblkctl = inb(SBLKCTL + iobase) & 0x0a) ) {
case 0:
@@ -2011,7 +2069,7 @@ ahc_init(unit)
}
}
- /* Set the SCSI Id, SXFRCTL1, and SIMODE1, for both channels */
+ /* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels*/
if( ahc->type & AHC_TWIN)
{
/*
@@ -2022,6 +2080,8 @@ ahc_init(unit)
scsi_conf = inb(HA_SCSICONF + 1 + iobase) & (ENSPCHK|STIMESEL);
outb(SXFRCTL1 + iobase, scsi_conf|ENSTIMER|ACTNEGEN|STPWEN);
outb(SIMODE1 + iobase, ENSELTIMO|ENSCSIPERR);
+ if(ahc->type & AHC_ULTRA)
+ outb(SXFRCTL0 + iobase, ULTRAEN);
/* Reset the bus */
outb(SCSISEQ + iobase, SCSIRSTO);
@@ -2035,6 +2095,8 @@ ahc_init(unit)
scsi_conf = inb(HA_SCSICONF + iobase) & (ENSPCHK|STIMESEL);
outb(SXFRCTL1 + iobase, scsi_conf|ENSTIMER|ACTNEGEN|STPWEN);
outb(SIMODE1 + iobase, ENSELTIMO|ENSCSIPERR);
+ if(ahc->type & AHC_ULTRA)
+ outb(SXFRCTL0 + iobase, ULTRAEN);
/* Reset the bus */
outb(SCSISEQ + iobase, SCSIRSTO);
@@ -2629,8 +2691,7 @@ ahc_scb_timeout(unit, ahc, scb)
outsb(SCBARRAY+iobase,scb,SCB_DOWN_SIZE);
outb(SCBCNT + iobase, 0);
ahc_add_waiting_scb(iobase, scb, list_second);
- timeout(ahc_timeout, (caddr_t)scb,
- (2 * hz) / 1000);
+ timeout(ahc_timeout, (caddr_t)scb, (2 * hz));
#ifdef AHC_DEBUG
if(ahc_debug & AHC_SHOWABORTS) {
sc_print_addr(scb->xs->sc_link);
@@ -2669,8 +2730,7 @@ ahc_scb_timeout(unit, ahc, scb)
active_scbp->flags |= SCB_DEVICE_RESET|SCB_ABORTED;
if(active_scbp != scb)
untimeout(ahc_timeout, (caddr_t)active_scbp);
- timeout(ahc_timeout, (caddr_t)active_scbp,
- (2 * hz) / 1000);
+ timeout(ahc_timeout, (caddr_t)active_scbp, (2 * hz));
outb(HA_FLAGS + iobase, flags | ACTIVE_MSG);
outb(HA_MSG_LEN + iobase, 1);
outb(HA_MSG_START + iobase, MSG_BUS_DEVICE_RESET);
@@ -2712,8 +2772,14 @@ ahc_timeout(void *arg1)
struct scb *scb = (struct scb *)arg1;
int unit;
struct ahc_data *ahc;
- int s, h;
- s = splbio();
+ int s;
+ s = splhigh();
+
+ if (!(scb->flags & SCB_ACTIVE)) {
+ /* Previous timeout took care of me already */
+ splx(s);
+ return;
+ }
unit = scb->xs->sc_link->adapter_unit;
ahc = ahcdata[unit];
@@ -2722,45 +2788,26 @@ ahc_timeout(void *arg1)
,scb->xs->sc_link->lun
,scb->xs->sc_link->device->name
,scb->xs->sc_link->dev_unit);
- h = splhigh();
- if(ahc->in_timeout){
- scb->next = ahc->timedout_scb;
- ahc->timedout_scb = scb;
- splx(h);
- splx(s);
- return;
- }
- else
- ahc->in_timeout = 1;
- splx(h);
- while(scb) {
#ifdef SCSIDEBUG
- show_scsi_cmd(scb->xs);
+ show_scsi_cmd(scb->xs);
#endif
#ifdef AHC_DEBUG
- if (ahc_debug & AHC_SHOWSCBS)
- ahc_print_active_scb(ahc);
+ if (ahc_debug & AHC_SHOWSCBS)
+ ahc_print_active_scb(ahc);
#endif /*AHC_DEBUG */
- /*
- * If it's immediate, don't try to abort it
- */
- if (scb->flags & SCB_IMMED) {
- scb->xs->retries = 0; /* I MEAN IT ! */
- ahc_timeout_done(unit, scb);
- }
- else {
- /* abort the operation that has timed out */
- ahc_scb_timeout( unit, ahc, scb );
- }
- h = splhigh();
- scb = ahc->timedout_scb;
- if(scb)
- ahc->timedout_scb = scb->next;
- splx(h);
+ /*
+ * If it's immediate, don't try to abort it
+ */
+ if (scb->flags & SCB_IMMED) {
+ scb->xs->retries = 0; /* I MEAN IT ! */
+ ahc_done(unit, scb);
+ }
+ else {
+ /* abort the operation that has timed out */
+ ahc_scb_timeout( unit, ahc, scb );
}
- ahc->in_timeout = 0;
- splx(s);
+ splx(s);
}
@@ -2804,7 +2851,7 @@ ahc_reset_device(unit, ahc, target, channel, timedout_scb, xs_error)
scbp->xs->error |= xs_error;
if(scbp->position != timedout_scb)
untimeout(ahc_timeout, (caddr_t)scbp);
- ahc_timeout_done (unit, scbp);
+ ahc_done (unit, scbp);
outb(SCBPTR + iobase, scbp->position);
outb(SCBARRAY + iobase, SCB_NEEDDMA);
i--;
@@ -2861,7 +2908,7 @@ ahc_reset_device(unit, ahc, target, channel, timedout_scb, xs_error)
scbp->xs->error |= xs_error;
if(scbp->position != timedout_scb)
untimeout(ahc_timeout, (caddr_t)scbp);
- ahc_timeout_done (unit, scbp);
+ ahc_done (unit, scbp);
found++;
}
}
@@ -2924,7 +2971,7 @@ ahc_abort_wscb (unit, scbp, prev, iobase, timedout_scb, xs_error)
scbp->xs->error |= xs_error;
if(scbp->position != timedout_scb)
untimeout(ahc_timeout, (caddr_t)scbp);
- ahc_timeout_done (unit, scbp);
+ ahc_done (unit, scbp);
return next;
}
@@ -3053,29 +3100,3 @@ ahc_match_scb (scb, target, channel)
else
return ((chan == channel) && (targ == target));
}
-
-void
-ahc_timeout_done (unit, scbp)
- int unit;
- struct scb *scbp;
-{
- struct ahc_data *ahc = ahcdata[unit];
- struct scb **prev_scb;
- struct scb *cur_scb;
- int h;
-
- h = splhigh();
- prev_scb = &ahc->timedout_scb;
- cur_scb = ahc->timedout_scb;
-
- while(cur_scb) {
- if(cur_scb == scbp) {
- *prev_scb = cur_scb->next;
- break;
- }
- prev_scb = &cur_scb->next;
- cur_scb = cur_scb->next;
- }
- splx(h);
- ahc_done(unit, scbp);
-}
diff --git a/sys/i386/scsi/aic7xxx.h b/sys/i386/scsi/aic7xxx.h
index c18217c..4b64b15 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.12 1995/08/05 17:32:55 gibbs Exp $
+ * $Id: aic7xxx.h,v 1.13 1995/09/05 23:52:03 gibbs Exp $
*/
#ifndef _AIC7XXX_H_
@@ -51,16 +51,20 @@ struct ahc_dma_seg {
typedef enum {
AHC_NONE = 0x000,
+ AHC_ULTRA = 0x001, /* Supports 20MHz Transfers */
AHC_WIDE = 0x002, /* Wide Channel */
AHC_TWIN = 0x008, /* Twin Channel */
AHC_AIC7770 = 0x010,
AHC_AIC7850 = 0x020,
AHC_AIC7870 = 0x040,
+ AHC_AIC7880 = 0x041,
AHC_AIC78X0 = 0x060, /* PCI Based Controller */
AHC_274 = 0x110, /* EISA Based Controller */
AHC_284 = 0x210, /* VL/ISA Based Controller */
AHC_294 = 0x440, /* PCI Based Controller */
- AHC_394 = 0x840 /* Twin Channel PCI Controller */
+ AHC_294U = 0x441, /* ULTRA PCI Based Controller */
+ AHC_394 = 0x840, /* Twin Channel PCI Controller */
+ AHC_394U = 0x841, /* Twin, ULTRA Channel PCI Controller */
}ahc_type;
typedef enum {
@@ -147,8 +151,6 @@ struct ahc_data {
u_long baseport;
struct scb *scbarray[AHC_SCB_MAX]; /* Mirror boards scbarray */
struct scb *free_scb;
- struct scb *timedout_scb;
- int in_timeout;
int our_id; /* our scsi id */
int our_id_b; /* B channel scsi id */
int vect;
OpenPOWER on IntegriCloud