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.
This commit is contained in:
parent
fca911ecf3
commit
396614a8b4
@ -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));
|
||||
@ -150,6 +149,20 @@ struct scsi_device ahc_dev =
|
||||
#define ENAUTOATNP 0x02
|
||||
#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);
|
||||
}
|
||||
ahc->in_timeout = 0;
|
||||
splx(s);
|
||||
else {
|
||||
/* abort the operation that has timed out */
|
||||
ahc_scb_timeout( unit, ahc, scb );
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user