Honor the CHANNEL_B_PRIMARY bit of the BIOSCTRL register and probe

channel B first as approriate.

Only reset the SCSI bus if the RESET_SCSI bit of SCSICONF is set.  This
makes the aic7xxx driver honor all of the configuration settings availible
in SCSI-Select or the ECU.

Fix a benign bug in the reset code that caused us to always wait a full
second after the chip reset.  This should shave some time off the probe.
Bug found by pedrosal@nce.ufrj.br (Pedro Salenbauch)

It seems that only the top three sync rates are doubled when in ultra mode,
so update the syncrates table as appropriate.
Found by "Dan Willis" <dan@plutotech.com> and his SCSI bus analyzer
This commit is contained in:
Justin T. Gibbs 1996-05-10 16:21:05 +00:00
parent 2f17ee3208
commit efaafa27d3
2 changed files with 154 additions and 88 deletions

View File

@ -31,7 +31,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aic7xxx.c,v 1.64 1996/04/23 04:47:02 gibbs Exp $
* $Id: aic7xxx.c,v 1.65 1996/04/28 19:21:19 gibbs Exp $
*/
/*
* TODO:
@ -288,11 +288,11 @@ static struct {
{ 0x100, 50, "20.0" },
{ 0x110, 62, "16.0" },
{ 0x120, 75, "13.4" },
{ 0x130, 87, "11.4" },
{ 0x140, 100, "10.0" },
{ 0x150, 112, "8.8" },
{ 0x160, 125, "8.0" },
{ 0x170, 137, "7.2" },
{ 0x130, 175, "5.7" },
{ 0x140, 200, "5.0" },
{ 0x150, 225, "4.4" },
{ 0x160, 250, "4.0" },
{ 0x170, 275, "3.6" },
{ 0x000, 100, "10.0" },
{ 0x010, 125, "8.0" },
{ 0x020, 150, "6.67" },
@ -367,16 +367,14 @@ ahc_reset(iobase)
/* Retain the IRQ type accross the chip reset */
hcntrl = (inb(HCNTRL + iobase) & IRQMS) | INTEN;
outb(HCNTRL + iobase, CHIPRST | PAUSE);
/*
* Ensure that the reset has finished
*/
wait = 1000;
while (wait--) {
while (--wait && !(inb(HCNTRL + iobase) & CHIPRSTACK))
DELAY(1000);
if(!(inb(HCNTRL + iobase) & CHIPRST))
break;
}
if(wait == 0) {
printf("ahc at 0x%lx: WARNING - Failed chip reset! "
"Trying to initialize anyway.\n", iobase);
@ -405,14 +403,8 @@ ahc_scsirate(ahc, scsirate, period, offset, target )
* enabled and vice-versa.
*/
if (ahc->type & AHC_ULTRA) {
if (!(ahc_syncrates[i].sxfr & ULTRA_SXFR)) {
printf("ahc%d: target %d requests "
"%sMHz transfers, but adapter "
"in Ultra mode can only sync at "
"7.2MHz or above\n", ahc->unit,
target, ahc_syncrates[i].rate);
if (!(ahc_syncrates[i].sxfr & ULTRA_SXFR))
break; /* Use Async */
}
}
else {
if (ahc_syncrates[i].sxfr & ULTRA_SXFR) {
@ -454,7 +446,7 @@ ahc_attach(ahc)
struct scsibus_data *scbus;
/*
* fill in the prototype scsi_link.
* fill in the prototype scsi_links.
*/
ahc->sc_link.adapter_unit = ahc->unit;
ahc->sc_link.adapter_targ = ahc->our_id;
@ -465,6 +457,14 @@ ahc_attach(ahc)
ahc->sc_link.flags = DEBUGLEVEL;
ahc->sc_link.fordriver = 0;
if(ahc->type & AHC_TWIN) {
/* Configure the second scsi bus */
ahc->sc_link_b = ahc->sc_link;
ahc->sc_link_b.adapter_targ = ahc->our_id_b;
ahc->sc_link_b.adapter_bus = 1;
ahc->sc_link_b.fordriver = (void *)SELBUSB;
}
/*
* Prepare the scsibus_data area for the upperlevel
* scsi code.
@ -472,7 +472,8 @@ ahc_attach(ahc)
scbus = scsi_alloc_bus();
if(!scbus)
return 0;
scbus->adapter_link = &ahc->sc_link;
scbus->adapter_link = (ahc->flags & AHC_CHANNEL_B_PRIMARY) ?
&ahc->sc_link_b : &ahc->sc_link;
if(ahc->type & AHC_WIDE)
scbus->maxtarg = 15;
@ -480,23 +481,22 @@ ahc_attach(ahc)
* ask the adapter what subunits are present
*/
if(bootverbose)
printf("ahc%d: Probing channel A\n", ahc->unit);
printf("ahc%d: Probing channel %c\n", ahc->unit,
(ahc->flags & AHC_CHANNEL_B_PRIMARY) ? 'B' : 'A');
scsi_attachdevs(scbus);
scbus = NULL; /* Upper-level SCSI code owns this now */
if(ahc->type & AHC_TWIN) {
/* Configure the second scsi bus */
ahc->sc_link_b = ahc->sc_link;
ahc->sc_link_b.adapter_targ = ahc->our_id_b;
ahc->sc_link_b.adapter_bus = 1;
ahc->sc_link_b.fordriver = (void *)SELBUSB;
scbus = scsi_alloc_bus();
if(!scbus)
return 0;
scbus->adapter_link = &ahc->sc_link_b;
scbus->adapter_link = (ahc->flags & AHC_CHANNEL_B_PRIMARY) ?
&ahc->sc_link : &ahc->sc_link_b;
if(ahc->type & AHC_WIDE)
scbus->maxtarg = 15;
if(bootverbose)
printf("ahc%d: Probing Channel B\n", ahc->unit);
printf("ahc%d: Probing Channel %c\n", ahc->unit,
(ahc->flags & AHC_CHANNEL_B_PRIMARY) ? 'A': 'B');
scsi_attachdevs(scbus);
scbus = NULL; /* Upper-level SCSI code owns this now */
}
@ -798,6 +798,9 @@ ahc_intr(arg)
case NO_MATCH:
if(ahc->flags & AHC_PAGESCBS) {
/* SCB Page-in request */
u_char tag;
u_char next;
u_char disc_scb;
struct scb *outscb;
u_char arg_1 = inb(ARG_1 + iobase);
if(arg_1 == SCB_LIST_NULL) {
@ -812,8 +815,9 @@ ahc_intr(arg)
/*
* Now to pick the SCB to page out.
* Either take a free SCB, an assigned SCB,
* an SCB that just completed or the first
* one on the disconnected SCB list.
* an SCB that just completed, the first
* one on the disconnected SCB list, or
* as a last resort a queued SCB.
*/
if(ahc->free_scbs.stqh_first) {
outscb = ahc->free_scbs.stqh_first;
@ -826,8 +830,9 @@ ahc_intr(arg)
outb(SCBPTR + iobase, scb->position);
ahc_send_scb(ahc, scb);
scb->flags &= ~SCB_PAGED_OUT;
goto pagein_done;
}
else if(ahc->assigned_scbs.stqh_first) {
if(ahc->assigned_scbs.stqh_first) {
outscb = ahc->assigned_scbs.stqh_first;
STAILQ_REMOVE_HEAD(&ahc->assigned_scbs,
links);
@ -839,8 +844,9 @@ ahc_intr(arg)
outb(SCBPTR + iobase, scb->position);
ahc_send_scb(ahc, scb);
scb->flags &= ~SCB_PAGED_OUT;
goto pagein_done;
}
else if(intstat & CMDCMPLT) {
if(intstat & CMDCMPLT) {
int scb_index;
printf("PIC\n");
@ -854,7 +860,7 @@ ahc_intr(arg)
printf("ahc%d: WARNING "
"no command for scb %d (cmdcmplt)\n",
ahc->unit, scb_index );
goto use_disconnected_scb;
/* Fall through in hopes of finding another SCB */
}
else {
scb->position = outscb->position;
@ -864,18 +870,11 @@ ahc_intr(arg)
scb->flags &= ~SCB_PAGED_OUT;
untimeout(ahc_timeout, (caddr_t)outscb);
ahc_done(ahc, outscb);
goto pagein_done;
}
}
else {
u_char tag;
u_char next;
u_char disc_scb;
use_disconnected_scb:
disc_scb =
inb(DISCONNECTED_SCBH + iobase);
if(disc_scb == SCB_LIST_NULL)
panic("Page-in request with no "
"candidates");
disc_scb = inb(DISCONNECTED_SCBH + iobase);
if(disc_scb != SCB_LIST_NULL) {
outb(SCBPTR + iobase, disc_scb);
tag = inb(SCB_TAG + iobase);
outscb = ahc->scbarray[tag];
@ -889,6 +888,52 @@ ahc_intr(arg)
outb(DISCONNECTED_SCBH + iobase, next);
ahc_page_scb(ahc, outscb, scb);
}
else if(inb(QINCNT + iobase) & ahc->qcntmask) {
/* Pull one of our queued commands as a last resort */
disc_scb = inb(QINFIFO + iobase);
outb(SCBPTR + iobase, disc_scb);
tag = inb(SCB_TAG + iobase);
outscb = ahc->scbarray[tag];
if((outscb->control & 0x23) != TAG_ENB) {
/*
* This is not a simple tagged command
* so its position in the queue
* matters. Take the command at the
* end of the queue instead.
*/
int i;
int saved_queue[AHC_SCB_MAX];
int queued = inb(QINCNT + iobase) & ahc->qcntmask;
/* Count the command we removed already */
saved_queue[0] = disc_scb;
queued++;
/* Empty the input queue */
for (i = 1; i < queued; i++)
saved_queue[i] = inb(QINFIFO + iobase);
/* Put everyone back put the last entry */
queued--;
for (i = 0; i < queued; i++)
outb (QINFIFO + iobase, saved_queue[i]);
outb(SCBPTR + iobase, saved_queue[queued]);
tag = inb(SCB_TAG + iobase);
outscb = ahc->scbarray[tag];
}
untimeout(ahc_timeout, (caddr_t)outscb);
scb->position = outscb->position;
outscb->position = SCB_LIST_NULL;
STAILQ_INSERT_HEAD(&ahc->waiting_scbs,
outscb, links);
outscb->flags = SCB_WAITINGQ;
ahc_send_scb(ahc, scb);
scb->flags &= ~SCB_PAGED_OUT;
}
else
panic("Page-in request with no candidates");
pagein_done:
outb(RETURN_1 + iobase, SCB_PAGEDIN);
}
else {
@ -1645,6 +1690,7 @@ ahc_init(ahc)
switch ( (sblkctl = inb(SBLKCTL + iobase) & 0x0a) ) {
case 0:
ahc->our_id = (inb(SCSICONF + iobase) & HSCSIID);
ahc->flags &= ~AHC_CHANNEL_B_PRIMARY;
if(ahc->type == AHC_394)
printf("Channel %c, SCSI Id=%d, ",
ahc->flags & AHC_CHNLB ? 'B' : 'A',
@ -1655,6 +1701,7 @@ ahc_init(ahc)
break;
case 2:
ahc->our_id = (inb(SCSICONF + 1 + iobase) & HWSCSIID);
ahc->flags &= ~AHC_CHANNEL_B_PRIMARY;
if(ahc->type == AHC_394)
printf("Wide Channel %c, SCSI Id=%d, ",
ahc->flags & AHC_CHNLB ? 'B' : 'A',
@ -1733,15 +1780,46 @@ ahc_init(ahc)
* so set those values first
*/
outb(SCSIID + iobase, ahc->our_id_b);
scsi_conf = inb(SCSICONF + 1 + iobase) & (ENSPCHK|STIMESEL);
outb(SXFRCTL1 + iobase, scsi_conf|ENSTIMER|ACTNEGEN|STPWEN);
scsi_conf = inb(SCSICONF + 1 + iobase);
outb(SXFRCTL1 + iobase, (scsi_conf & (ENSPCHK|STIMESEL))
| ENSTIMER|ACTNEGEN|STPWEN);
outb(SIMODE1 + iobase, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
if(ahc->type & AHC_ULTRA)
outb(SXFRCTL0 + iobase, DFON|SPIOEN|ULTRAEN);
else
outb(SXFRCTL0 + iobase, DFON|SPIOEN);
if(scsi_conf & RESET_SCSI) {
/* Reset the bus */
if(bootverbose)
printf("Reseting Channel B\n");
outb(SCSISEQ + iobase, SCSIRSTO);
DELAY(1000);
outb(SCSISEQ + iobase, 0);
/* Ensure we don't get a RSTI interrupt from this */
outb(CLRSINT1 + iobase, CLRSCSIRSTI);
outb(CLRINT + iobase, CLRSCSIINT);
}
/* Select Channel A */
outb(SBLKCTL + iobase, 0);
}
outb(SCSIID + iobase, ahc->our_id);
scsi_conf = inb(SCSICONF + iobase);
outb(SXFRCTL1 + iobase, (scsi_conf & (ENSPCHK|STIMESEL))
| ENSTIMER|ACTNEGEN|STPWEN);
outb(SIMODE1 + iobase, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
if(ahc->type & AHC_ULTRA)
outb(SXFRCTL0 + iobase, DFON|SPIOEN|ULTRAEN);
else
outb(SXFRCTL0 + iobase, DFON|SPIOEN);
if(scsi_conf & RESET_SCSI) {
/* Reset the bus */
if(bootverbose)
printf("Reseting Channel A\n");
outb(SCSISEQ + iobase, SCSIRSTO);
DELAY(1000);
outb(SCSISEQ + iobase, 0);
@ -1749,27 +1827,7 @@ ahc_init(ahc)
/* Ensure we don't get a RSTI interrupt from this */
outb(CLRSINT1 + iobase, CLRSCSIRSTI);
outb(CLRINT + iobase, CLRSCSIINT);
/* Select Channel A */
outb(SBLKCTL + iobase, 0);
}
outb(SCSIID + iobase, ahc->our_id);
scsi_conf = inb(SCSICONF + iobase) & (ENSPCHK|STIMESEL);
outb(SXFRCTL1 + iobase, scsi_conf|ENSTIMER|ACTNEGEN|STPWEN);
outb(SIMODE1 + iobase, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
if(ahc->type & AHC_ULTRA)
outb(SXFRCTL0 + iobase, DFON|SPIOEN|ULTRAEN);
else
outb(SXFRCTL0 + iobase, DFON|SPIOEN);
/* Reset the bus */
outb(SCSISEQ + iobase, SCSIRSTO);
DELAY(1000);
outb(SCSISEQ + iobase, 0);
/* Ensure we don't get a RSTI interrupt from this */
outb(CLRSINT1 + iobase, CLRSCSIRSTI);
outb(CLRINT + iobase, CLRSCSIINT);
/*
* Look at the information that board initialization or

View File

@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aic7xxx.h,v 1.25 1996/04/20 21:29:27 gibbs Exp $
* $Id: aic7xxx.h,v 1.26 1996/04/28 19:21:20 gibbs Exp $
*/
#ifndef _AIC7XXX_H_
@ -77,27 +77,47 @@ typedef enum {
}ahc_type;
typedef enum {
AHC_FNONE = 0x00,
AHC_INIT = 0x01,
AHC_RUNNING = 0x02,
AHC_PAGESCBS = 0x04, /* Enable SCB paging */
AHC_USEDEFAULTS = 0x10, /*
AHC_FNONE = 0x00,
AHC_INIT = 0x01,
AHC_RUNNING = 0x02,
AHC_PAGESCBS = 0x04, /* Enable SCB paging */
AHC_CHANNEL_B_PRIMARY = 0x08, /*
* On twin channel adapters, probe
* channel B first since it is the
* primary bus.
*/
AHC_USEDEFAULTS = 0x10, /*
* For cards without an seeprom
* or a BIOS to initialize the chip's
* SRAM, we use the default chip and
* target settings.
* SRAM, we use the default target
* settings.
*/
AHC_CHNLB = 0x20, /*
AHC_CHNLB = 0x20, /*
* Second controller on 3940
* Also encodes the offset in the
* SEEPROM for CHNLB info (32)
*/
}ahc_flag;
typedef enum {
SCB_FREE = 0x000,
SCB_ACTIVE = 0x001,
SCB_ABORTED = 0x002,
SCB_DEVICE_RESET = 0x004,
SCB_IMMED = 0x008,
SCB_SENSE = 0x010,
SCB_TIMEDOUT = 0x020,
SCB_QUEUED_FOR_DONE = 0x040,
SCB_PAGED_OUT = 0x080,
SCB_WAITINGQ = 0x100,
SCB_ASSIGNEDQ = 0x200,
SCB_SENTORDEREDTAG = 0x400
}scb_flag;
/*
* The driver keeps up to MAX_SCB scb structures per card in memory. Only the
* first 26 bytes of the structure need to be transfered to the card during
* normal operation. The fields starting at byte 32 are used for kernel level
* first 28 bytes of the structure need to be transfered to the card during
* normal operation. The fields starting at byte 28 are used for kernel level
* bookkeeping.
*/
struct scb {
@ -131,19 +151,7 @@ struct scb {
/*-----------------end of hardware supported fields----------------*/
STAILQ_ENTRY(scb) links; /* for chaining */
struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
int flags;
#define SCB_FREE 0x000
#define SCB_ACTIVE 0x001
#define SCB_ABORTED 0x002
#define SCB_DEVICE_RESET 0x004
#define SCB_IMMED 0x008
#define SCB_SENSE 0x010
#define SCB_TIMEDOUT 0x020
#define SCB_QUEUED_FOR_DONE 0x040
#define SCB_PAGED_OUT 0x080
#define SCB_WAITINGQ 0x100
#define SCB_ASSIGNEDQ 0x200
#define SCB_SENTORDEREDTAG 0x400
scb_flag flags;
u_char position; /* Position in card's scbarray */
struct ahc_dma_seg ahc_dma[AHC_NSEG] __attribute__ ((packed));
struct scsi_sense sense_cmd; /* SCSI command block */