Clean up a few nits in the aic7xxx driver:

1) Make the driver "quiet" by sticking most boot messages behind
	bootverbose conditionals.  This means that you won't see the
	sync and wide negotiation, but you will find out if they fail.

2) Add support to the 93cx6 serial eeprom code to read at an abitrary
	offset.  This is needed so that we can access the second half
	of the eeprom on 3940 cards where the second channel's config
	is stored.

3) Add flags argument to ahcprobe().  This is used by the pci probe code
	to tell the generic driver that an adapter should be treated
	as a channel B device as well as notify it of the presence of
	external SCB SRAM.  These are needed for some motherboard
	implementations of the aic7870 and for the 3940 controllers.

4) Print "Channel A"/"Channel B" instead of "Single Channel" for the
	two busses of the 3940.  I received many reports of confusion
	about how the 3940 was probed since most people belived that
	only one ahc entry was needed.  This will hopefully make it
	clearer.

5) Walk the SCBs to determine just how many their are if external SCB
	ram is detected.

6) Hard code that external SCB ram is present for the 3940 since it doesn't
	use the documented reporting facility for reporting the SRAM. :(
	255 commands per channel are supported on the 3940.

7) Read the seeprom starting at addres 32 for the second channel of the
	3940 so we get the right info for that channel.

8) Clean up printing of the "Disabling tagged queuing message".

9) Queue timeouts if they occur while we are handling a timeout.  The code
	was totally unprotected in this scenario.
Reviewed by: Timeout code reviewed by David Greenman <davidg>
This commit is contained in:
gibbs 1995-09-05 23:52:03 +00:00
parent 6b92c489cf
commit ea546debb7
4 changed files with 198 additions and 94 deletions

View File

@ -18,7 +18,7 @@
* 4. Modifications may be freely made to this file if the above conditions
* are met.
*
* $Id$
* $Id: 93cx6.c,v 1.1 1995/07/04 21:16:11 gibbs Exp $
*/
/*
@ -82,6 +82,7 @@ struct seeprom_cmd {
*/
int read_seeprom (u_long offset,
u_short *buf,
u_int start_addr,
int count,
u_short CS, /* chip select */
u_short CK, /* clock */
@ -98,7 +99,7 @@ int read_seeprom (u_long offset,
* Read the requested registers of the seeprom. The loop
* will range from 0 to count-1.
*/
for (k = 0; k < count; k = k + 1) {
for (k = start_addr; k < count + start_addr; k = k + 1) {
/* Send chip select for one clock cycle. */
outb(offset, MS | CK | CS);
CLOCK_PULSE(offset, RDY);
@ -144,9 +145,10 @@ int read_seeprom (u_long offset,
CLOCK_PULSE(offset, RDY);
temp = temp ^ CK;
if (inb(offset) & DI)
buf[k] = (buf[k] << 1) | 0x1;
buf[k - start_addr] =
(buf[k - start_addr] << 1) | 0x1;
else
buf[k] = (buf[k] << 1);
buf[k - start_addr] = (buf[k - start_addr]<< 1);
outb(offset, temp);
CLOCK_PULSE(offset, RDY);
}
@ -159,7 +161,6 @@ int read_seeprom (u_long offset,
outb(offset, MS);
CLOCK_PULSE(offset, RDY);
}
#if 0
printf ("Serial EEPROM:");
for (k = 0; k < count; k = k + 1) {

View File

@ -20,7 +20,7 @@
* 4. Modifications may be freely made to this file if the above conditions
* are met.
*
* $Id$
* $Id: 93cx6.h,v 1.1 1995/07/04 21:16:12 gibbs Exp $
*/
#include <sys/param.h>
@ -43,6 +43,7 @@
*/
int read_seeprom (u_long offset,
u_short *buf,
u_int start_addr,
int count,
u_short CS,
u_short CK,

View File

@ -5,7 +5,7 @@
*
* Product specific probe and attach routines can be found in:
* i386/isa/aic7770.c 27/284X and aic7770 motherboard controllers
* /pci/aic7870.c 294x and aic7870 motherboard controllers
* /pci/aic7870.c 3940, 2940, aic7870 and aic7850 controllers
*
* Portions of this driver are based on the FreeBSD 1742 Driver:
*
@ -24,7 +24,7 @@
*
* commenced: Sun Sep 27 18:14:01 PDT 1992
*
* $Id: aic7xxx.c,v 1.36 1995/08/15 08:54:21 gibbs Exp $
* $Id: aic7xxx.c,v 1.37 1995/08/23 23:03:17 gibbs Exp $
*/
/*
* TODO:
@ -62,6 +62,7 @@ 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));
@ -778,10 +779,11 @@ static int ahc_num_syncrates =
*/
int
ahcprobe(unit, iobase, type)
ahcprobe(unit, iobase, type, flags)
int unit;
u_long iobase;
ahc_type type;
ahc_flag flags;
{
/*
@ -812,6 +814,7 @@ ahcprobe(unit, iobase, type)
ahcdata[unit] = ahc;
ahc->baseport = iobase;
ahc->type = type;
ahc->flags = flags;
/*
* Try to initialize a unit at this location
@ -844,22 +847,20 @@ void ahc_scsirate(scsirate, period, offset, unit, target )
if ((ahc_syncrates[i].period - period) >= 0) {
*scsirate = (ahc_syncrates[i].sxfr) | (offset & 0x0f);
printf("ahc%d: target %d synchronous at %sMB/s, "
"offset = 0x%x\n", unit, target,
ahc_syncrates[i].rate, offset );
/* XXX Conditional on bootverbose??? */
#ifdef AHC_DEBUG
#endif /* AHC_DEBUG */
if(bootverbose) {
printf("ahc%d: target %d synchronous at %sMB/s,"
" offset = 0x%x\n", unit, target,
ahc_syncrates[i].rate, offset );
}
return;
}
}
/* Default to asyncronous transfers. Also reject this SDTR request. */
*scsirate = 0;
printf("ahc%d: target %d using asyncronous transfers\n",
unit, target );
#ifdef AHC_DEBUG
#endif /* AHC_DEBUG */
if(bootverbose) {
printf("ahc%d: target %d using asyncronous transfers\n",
unit, target );
}
}
@ -898,7 +899,8 @@ ahc_attach(unit)
/*
* ask the adapter what subunits are present
*/
printf("ahc%d: Probing channel A\n", unit);
if(bootverbose)
printf("ahc%d: Probing channel A\n", unit);
scsi_attachdevs(scbus);
scbus = NULL; /* Upper-level SCSI code owns this now */
if(ahc->type & AHC_TWIN) {
@ -913,7 +915,8 @@ ahc_attach(unit)
scbus->adapter_link = &ahc->sc_link_b;
if(ahc->type & AHC_WIDE)
scbus->maxtarg = 15;
printf("ahc%d: Probing Channel B\n", unit);
if(bootverbose)
printf("ahc%d: Probing Channel B\n", unit);
scsi_attachdevs(scbus);
scbus = NULL; /* Upper-level SCSI code owns this now */
}
@ -1050,17 +1053,18 @@ ahcintr(unit)
case SEND_REJECT:
{
u_char rejbyte = inb(HA_REJBYTE + iobase);
printf("ahc%d:%c:%d: Warning - message "
"rejected by target: 0x%x\n",
unit, channel, target, rejbyte);
if(( rejbyte & 0xf0) == 0x20) {
/* Tagged Message */
printf("ahc%d:%c:%d: Tagged message "
printf("\nahc%d:%c:%d: Tagged message "
"rejected. Disabling tagged "
"commands for this target.\n",
unit, channel, target);
ahc->tagenable &= ~targ_mask;
}
else
printf("ahc%d:%c:%d: Warning - message "
"rejected by target: 0x%x\n",
unit, channel, target, rejbyte);
break;
}
case NO_IDENT:
@ -1168,22 +1172,24 @@ ahcintr(unit)
switch(bus_width)
{
case BUS_8_BIT:
scratch &= 0x7f;
break;
scratch &= 0x7f;
break;
case BUS_16_BIT:
if(bootverbose)
printf("ahc%d: target "
"%d using 16Bit "
"transfers\n",
unit, target);
scratch |= 0x80;
break;
scratch |= 0x80;
break;
default:
break;
}
}
else {
/*
* Send our own WDTR in reply
*/
printf("Will Send WDTR!!\n");
switch(bus_width)
{
case BUS_8_BIT:
@ -1193,12 +1199,15 @@ ahcintr(unit)
/* Negotiate 16_BITS */
bus_width = BUS_16_BIT;
case BUS_16_BIT:
if(bootverbose)
printf("ahc%d: target "
"%d using 16Bit "
"transfers\n",
unit, target);
scratch |= 0x80;
break;
scratch |= 0x80;
break;
default:
break;
}
outb(HA_RETURN_1 + iobase,
bus_width | SEND_WDTR);
@ -1745,7 +1754,7 @@ ahc_init(unit)
struct ahc_data *ahc = ahcdata[unit];
u_long iobase = ahc->baseport;
u_char scsi_conf, sblkctl, i, host_id;
int intdef, max_targ = 16, wait, have_seeprom = 0;
int intdef, max_targ = 15, wait, have_seeprom = 0;
int bios_disabled = 0;
struct seeprom_config sc;
/*
@ -1758,7 +1767,8 @@ ahc_init(unit)
printf("ahc%d: scb %d bytes; ahc_dma %d bytes\n",
unit, sizeof(struct scb), sizeof(struct ahc_dma_seg));
#endif /* AHC_DEBUG */
printf("ahc%d: reading board settings\n", unit);
if(bootverbose)
printf("ahc%d: reading board settings\n", unit);
/* Save the IRQ type before we do a chip reset */
@ -1809,17 +1819,19 @@ ahc_init(unit)
case AHC_394:
case AHC_294:
host_id = 0x07; /* default to SCSI ID 7 for 7850 */
if (ahc->type != AHC_AIC7850) {
if (ahc->type & AHC_AIC7870) {
unsigned short *scarray = (u_short *)&sc;
unsigned short checksum = 0;
printf("ahc%d: Reading SEEPROM...", unit);
if(bootverbose)
printf("ahc%d: Reading SEEPROM...", unit);
have_seeprom = enable_seeprom (iobase + SEECTL,
SEECS, SEECK, SEEDO, SEEDI, SEERDY, SEEMS);
if (have_seeprom) {
have_seeprom = read_seeprom (iobase + SEECTL,
(u_short *)&sc, sizeof(sc)/2, SEECS,
SEECK, SEEDO, SEEDI, SEERDY, SEEMS);
(u_short *)&sc, ahc->flags & AHC_CHNLB,
sizeof(sc)/2, SEECS, SEECK, SEEDO,
SEEDI, SEERDY, SEEMS);
release_seeprom (iobase + SEECTL, SEECS, SEECK,
SEEDO, SEEDI, SEERDY, SEEMS);
if (have_seeprom) {
@ -1831,7 +1843,8 @@ ahc_init(unit)
have_seeprom = 0;
}
else {
printf("done.\n");
if(bootverbose)
printf("done.\n");
host_id = (sc.brtime_id & CFSCSIID);
}
}
@ -1843,18 +1856,16 @@ ahc_init(unit)
}
}
ahc->maxscbs = 0x10;
if(ahc->type == AHC_AIC7850){
if(ahc->type == AHC_394)
printf("ahc%d: 3940 ", unit);
else if(ahc->type == AHC_294)
printf("ahc%d: 2940 ", unit);
else if(ahc->type == AHC_AIC7850){
printf("ahc%d: aic7850 ", unit);
ahc->maxscbs = 0x03;
}
else if(ahc->type == AHC_AIC7870)
printf("ahc%d: aic7870 ", unit);
else if(ahc->type == AHC_394){
printf("ahc%d: 3940 ", unit);
/* XXX Test this! ahc->maxscbs = 0xff; */
}
else
printf("ahc%d: 2940 ", unit);
printf("ahc%d: aic7870 ", unit);
outb(DSPCISTATUS + iobase, 0xc0 /* DFTHRSH == 100% */);
/*
* XXX Use SCSI ID from SEEPROM if we have it; otherwise
@ -1871,12 +1882,22 @@ ahc_init(unit)
switch ( (sblkctl = inb(SBLKCTL + iobase) & 0x0a) ) {
case 0:
ahc->our_id = (inb(HA_SCSICONF + iobase) & HSCSIID);
printf("Single Channel, SCSI Id=%d, ", ahc->our_id);
if(ahc->type == AHC_394)
printf("Channel %c, SCSI Id=%d, ",
ahc->flags & AHC_CHNLB ? 'B' : 'A',
ahc->our_id);
else
printf("Single Channel, SCSI Id=%d, ", ahc->our_id);
outb(HA_FLAGS + iobase, SINGLE_BUS);
break;
case 2:
ahc->our_id = (inb(HA_SCSICONF + 1 + iobase) & HWSCSIID);
printf("Wide Channel, SCSI Id=%d, ", ahc->our_id);
if(ahc->type == AHC_394)
printf("Wide Channel %c, SCSI Id=%d, ",
ahc->flags & AHC_CHNLB ? 'B' : 'A',
ahc->our_id);
else
printf("Wide Channel, SCSI Id=%d, ", ahc->our_id);
ahc->type |= AHC_WIDE;
outb(HA_FLAGS + iobase, WIDE_BUS);
break;
@ -1930,9 +1951,27 @@ ahc_init(unit)
printf("aic7850, ");
else
printf("aic7870, ");
if(ahc->flags & AHC_EXTSCB) {
/*
* This adapter has external SCB memory.
* Walk the SCBs to determine how many there are.
*/
for(i = 0; i < AHC_SCB_MAX; i++) {
outb(SCBPTR + iobase, i);
outb(SCBARRAY + iobase, 0xaa);
if(inb(SCBARRAY + iobase) == 0xaa){
outb(SCBARRAY + iobase, 0x55);
if(inb(SCBARRAY + iobase) == 0x55) {
continue;
}
}
break;
}
ahc->maxscbs = i;
}
printf("%d SCBs\n", ahc->maxscbs);
if(!(ahc->type & AHC_AIC78X0)) {
if(!(ahc->type & AHC_AIC78X0) && bootverbose) {
if(ahc->pause & IRQMS)
printf("ahc%d: Using Level Sensitive Interrupts\n",
unit);
@ -1942,7 +1981,7 @@ ahc_init(unit)
}
if(!(ahc->type & AHC_AIC78X0)){
/*
* The 294x cards are PCI, so we get their interrupt from the PCI
* The AIC78X0 cards are PCI, so we get their interrupt from the PCI
* BIOS.
*/
@ -1986,7 +2025,7 @@ ahc_init(unit)
/* Reset the bus */
outb(SCSISEQ + iobase, SCSIRSTO);
DELAY(10000);
DELAY(1000);
outb(SCSISEQ + iobase, 0);
/* Select Channel A */
@ -1999,7 +2038,7 @@ ahc_init(unit)
/* Reset the bus */
outb(SCSISEQ + iobase, SCSIRSTO);
DELAY(10000);
DELAY(1000);
outb(SCSISEQ + iobase, 0);
/*
@ -2026,9 +2065,9 @@ ahc_init(unit)
ahc->discenable = ~(inw(HA_DISC_DSB + iobase));
if(!(ahc->type & AHC_WIDE))
max_targ = 8;
max_targ = 7;
for(i = 0; i < max_targ; i++){
for(i = 0; i <= max_targ; i++){
u_char target_settings;
if (have_seeprom) {
target_settings = (sc.device_flags[i] & CFXFER) << 4;
@ -2113,9 +2152,11 @@ ahc_init(unit)
* difference when doing many small block transfers.
*/
printf("ahc%d: Downloading Sequencer Program...", unit);
if(bootverbose)
printf("ahc%d: Downloading Sequencer Program...", unit);
ahc_loadseq(iobase);
printf("Done\n");
if(bootverbose)
printf("Done\n");
outb(SEQCTL + iobase, FASTMODE);
if (!(ahc->type & AHC_AIC78X0))
@ -2668,37 +2709,57 @@ ahc_scb_timeout(unit, ahc, scb)
void
ahc_timeout(void *arg1)
{
struct scb *scb = (struct scb *)arg1;
int unit;
struct ahc_data *ahc;
int s = splbio();
struct scb *scb = (struct scb *)arg1;
int unit;
struct ahc_data *ahc;
int s, h;
s = splbio();
unit = scb->xs->sc_link->adapter_unit;
ahc = ahcdata[unit];
printf("ahc%d: target %d, lun %d (%s%d) timed out\n", unit
,scb->xs->sc_link->target
,scb->xs->sc_link->lun
,scb->xs->sc_link->device->name
,scb->xs->sc_link->dev_unit);
unit = scb->xs->sc_link->adapter_unit;
ahc = ahcdata[unit];
printf("ahc%d: target %d, lun %d (%s%d) timed out\n", unit
,scb->xs->sc_link->target
,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_done(unit, scb);
splx(s);
return;
}
/* abort the operation that has timed out */
ahc_scb_timeout( unit, ahc, scb );
/*
* 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);
}
ahc->in_timeout = 0;
splx(s);
}
@ -2743,7 +2804,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_done (unit, scbp);
ahc_timeout_done (unit, scbp);
outb(SCBPTR + iobase, scbp->position);
outb(SCBARRAY + iobase, SCB_NEEDDMA);
i--;
@ -2800,7 +2861,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_done (unit, scbp);
ahc_timeout_done (unit, scbp);
found++;
}
}
@ -2863,7 +2924,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_done (unit, scbp);
ahc_timeout_done (unit, scbp);
return next;
}
@ -2993,3 +3054,28 @@ ahc_match_scb (scb, target, channel)
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);
}

View File

@ -20,7 +20,7 @@
* 4. Modifications may be freely made to this file if the above conditions
* are met.
*
* $Id: aic7xxx.h,v 1.11 1995/07/04 21:14:45 gibbs Exp $
* $Id: aic7xxx.h,v 1.12 1995/08/05 17:32:55 gibbs Exp $
*/
#ifndef _AIC7XXX_H_
@ -30,13 +30,17 @@
#define AHC_NSEG 256 /* number of dma segments supported */
#define AHC_SCB_MAX 16 /*
* Up to 16 SCBs on some types of aic7xxx based
* boards. The aic7770 family only have 4
#define AHC_SCB_MAX 255 /*
* Up to 255 SCBs on some types of aic7xxx
* based boards. The aic7870 have 16 internal
* SCBs, but external SRAM bumps this to 255.
* The aic7770 family have only 4, and the
* aic7850 have only 3.
*/
/* #define AHCDEBUG */
extern int bootverbose;
typedef unsigned long int physaddr;
extern int ahc_unit;
@ -59,6 +63,18 @@ typedef enum {
AHC_394 = 0x840 /* Twin Channel PCI Controller */
}ahc_type;
typedef enum {
AHC_FNONE = 0x00,
AHC_INIT = 0x01,
AHC_RUNNING = 0x02,
AHC_EXTSCB = 0x10, /* External SCBs present */
AHC_CHNLB = 0x20, /*
* Second controller on 3940
* Also encodes the offset in the
* SEEPROM for CHNLB info (32)
*/
}ahc_flag;
/*
* The driver keeps up to MAX_SCB scb structures per card in memory. Only the
* first 26 bytes of the structure are valid for the hardware, the rest used
@ -127,12 +143,12 @@ struct scb {
struct ahc_data {
ahc_type type;
int flags;
#define AHC_INIT 0x01
#define AHC_RUNNING 0x02
ahc_flag flags;
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;
@ -156,7 +172,7 @@ struct ahc_data {
extern struct ahc_data *ahcdata[NAHC];
int ahcprobe __P((int unit, u_long io_base, ahc_type type));
int ahcprobe __P((int unit, u_long io_base, ahc_type type, ahc_flag flags));
int ahc_attach __P((int unit));
int ahcintr();