Add basic support for the 398X cards as multi-channel SCSI host adapters.

This involves expanding the support of the SEEPROM routines to deal with
the larger SEEPROMs on these cards and providing a mechanism to share
SCB arrays between multiple controllers.

Most of the 398X support came from Dan Eischer.

ahc_data -> ahc_softc

Clean up some more type bogons I missed from the last pass.

Be more clear when handing the NO_MATCH condition.  NO_MATCH can also
happen when the sequencer encounters an SCB we've asked to be aborted.
This commit is contained in:
gibbs 1996-10-28 06:10:02 +00:00
parent a30df8e223
commit 82270a2c1b
4 changed files with 292 additions and 184 deletions

View File

@ -1,7 +1,7 @@
/*
* Interface for the 93C46/26/06 serial eeprom parts.
* Interface for the 93C66/56/46/26/06 serial eeprom parts.
*
* Copyright (c) 1995 Daniel M. Eischen
* Copyright (c) 1995, 1996 Daniel M. Eischen
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -18,14 +18,14 @@
* 4. Modifications may be freely made to this file if the above conditions
* are met.
*
* $Id: 93cx6.c,v 1.5 1996/05/30 07:19:54 gibbs Exp $
* $Id: 93cx6.c,v 1.6 1996/10/25 06:42:49 gibbs Exp $
*/
/*
* The instruction set of the 93C46/26/06 chips are as follows:
* The instruction set of the 93C66/56/46/26/06 chips are as follows:
*
* Start OP
* Function Bit Code Address Data Description
* Start OP *
* Function Bit Code Address** Data Description
* -------------------------------------------------------------------
* READ 1 10 A5 - A0 Reads data stored in memory,
* starting at specified address
@ -38,12 +38,14 @@
* EWDS 1 00 00XXXX Disables all programming
* instructions
* *Note: A value of X for address is a don't care condition.
* **Note: There are 8 address bits for the 93C56/66 chips unlike
* the 93C46/26/06 chips which have 6 address bits.
*
* The 93C46 has a four wire interface: clock, chip select, data in, and
* data out. In order to perform one of the above functions, you need
* to enable the chip select for a clock period (typically a minimum of
* 1 usec, with the clock high and low a minimum of 750 and 250 nsec
* respectively. While the chip select remains high, you can clock in
* respectively). While the chip select remains high, you can clock in
* the instructions (above) starting with the start bit, followed by the
* OP code, Address, and Data (if needed). For the READ instruction, the
* requested 16-bit register contents is read from the data out line but
@ -125,8 +127,8 @@ read_seeprom(sd, buf, start_addr, count)
if (seeprom_read.bits[i] != 0)
temp ^= sd->sd_DO;
}
/* Send the 6 bit address (MSB first, LSB last). */
for (i = 5; i >= 0; i--) {
/* Send the 6 or 8 bit address (MSB first, LSB last). */
for (i = (sd->sd_chip - 1); i >= 0; i--) {
if ((k & (1 << i)) != 0)
temp ^= sd->sd_DO;
SEEPROM_OUTB(sd, temp);

View File

@ -20,7 +20,7 @@
* 4. Modifications may be freely made to this file if the above conditions
* are met.
*
* $Id: 93cx6.h,v 1.1.2.3 1996/06/08 07:10:44 gibbs Exp $
* $Id: 93cx6.h,v 1.4 1996/10/25 06:42:50 gibbs Exp $
*/
#include <sys/param.h>
@ -28,6 +28,11 @@
#include <sys/systm.h>
#endif
typedef enum {
C46 = 6,
C56_66 = 8
} seeprom_chip_t;
struct seeprom_descriptor {
#if defined(__FreeBSD__)
u_int32_t sd_iobase;
@ -37,6 +42,7 @@ struct seeprom_descriptor {
bus_io_handle_t sd_ioh;
bus_io_size_t sd_offset;
#endif
seeprom_chip_t sd_chip;
u_int16_t sd_MS;
u_int16_t sd_RDY;
u_int16_t sd_CS;

View File

@ -32,7 +32,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aic7xxx.c,v 1.75.2.5 1996/10/06 22:48:12 gibbs Exp $
* $Id: aic7xxx.c,v 1.80 1996/10/25 06:42:51 gibbs Exp $
*/
/*
* TODO:
@ -163,16 +163,16 @@ int ahc_broken_cache = 1;
static void ahcminphys __P((struct buf *bp));
static int32_t ahc_scsi_cmd __P((struct scsi_xfer *xs));
static void ahc_run_waiting_queue __P((struct ahc_data *ahc));
static void ahc_run_waiting_queue __P((struct ahc_softc *ahc));
static struct scb *
ahc_get_scb __P((struct ahc_data *ahc, u_int32_t flags));
static void ahc_free_scb __P((struct ahc_data *ahc, struct scb *scb));
ahc_get_scb __P((struct ahc_softc *ahc, u_int32_t flags));
static void ahc_free_scb __P((struct ahc_softc *ahc, struct scb *scb));
static struct scb *
ahc_alloc_scb __P((struct ahc_data *ahc));
static inline void pause_sequencer __P((struct ahc_data *ahc));
static inline void unpause_sequencer __P((struct ahc_data *ahc,
ahc_alloc_scb __P((struct ahc_softc *ahc));
static inline void pause_sequencer __P((struct ahc_softc *ahc));
static inline void unpause_sequencer __P((struct ahc_softc *ahc,
int unpause_always));
static inline void restart_sequencer __P((struct ahc_data *ahc));
static inline void restart_sequencer __P((struct ahc_softc *ahc));
static struct scsi_adapter ahc_switch =
{
@ -202,7 +202,7 @@ static struct scsi_device ahc_dev =
static inline void
pause_sequencer(ahc)
struct ahc_data *ahc;
struct ahc_softc *ahc;
{
AHC_OUTB(ahc, HCNTRL, ahc->pause);
@ -216,7 +216,7 @@ pause_sequencer(ahc)
static inline void
unpause_sequencer(ahc, unpause_always)
struct ahc_data *ahc;
struct ahc_softc *ahc;
int unpause_always;
{
if (unpause_always
@ -229,7 +229,7 @@ unpause_sequencer(ahc, unpause_always)
*/
static inline void
restart_sequencer(ahc)
struct ahc_data *ahc;
struct ahc_softc *ahc;
{
do {
AHC_OUTB(ahc, SEQCTL, SEQRESET|FASTMODE);
@ -247,31 +247,31 @@ restart_sequencer(ahc)
((sc_link)->scsibus == (ahc)->sc_link_b.scsibus)
#endif
static u_int8_t ahc_abort_wscb __P((struct ahc_data *ahc, struct scb *scbp,
static u_int8_t ahc_abort_wscb __P((struct ahc_softc *ahc, struct scb *scbp,
u_int8_t scbpos, u_int8_t prev,
struct scb *timedout_scb,
u_int32_t xs_error));
static void ahc_done __P((struct ahc_data *ahc, struct scb *scbp));
static void ahc_handle_seqint __P((struct ahc_data *ahc, u_int8_t intstat));
static void ahc_handle_scsiint __P((struct ahc_data *ahc,
static void ahc_done __P((struct ahc_softc *ahc, struct scb *scbp));
static void ahc_handle_seqint __P((struct ahc_softc *ahc, u_int8_t intstat));
static void ahc_handle_scsiint __P((struct ahc_softc *ahc,
u_int8_t intstat));
static void ahc_loadseq __P((struct ahc_data *ahc));
static void ahc_loadseq __P((struct ahc_softc *ahc));
static int ahc_match_scb __P((struct scb *scb, int target, char channel));
static int ahc_poll __P((struct ahc_data *ahc, int wait));
static int ahc_poll __P((struct ahc_softc *ahc, int wait));
#ifdef AHC_DEBUG
static void ahc_print_scb __P((struct scb *scb));
#endif
static u_int8_t find_scb __P((struct ahc_data *ahc, struct scb *scb));
static int ahc_reset_channel __P((struct ahc_data *ahc, char channel,
static u_int8_t find_scb __P((struct ahc_softc *ahc, struct scb *scb));
static int ahc_reset_channel __P((struct ahc_softc *ahc, char channel,
struct scb *timedout_scb,
u_int32_t xs_error,
int initiate_reset));
static int ahc_reset_device __P((struct ahc_data *ahc, int target,
static int ahc_reset_device __P((struct ahc_softc *ahc, int target,
char channel, struct scb *timedout_scb,
u_int32_t xs_error));
static void ahc_reset_current_bus __P((struct ahc_data *ahc));
static void ahc_run_done_queue __P((struct ahc_data *ahc));
static void ahc_scsirate __P((struct ahc_data* ahc, u_int8_t *scsirate,
static void ahc_reset_current_bus __P((struct ahc_softc *ahc));
static void ahc_run_done_queue __P((struct ahc_softc *ahc));
static void ahc_scsirate __P((struct ahc_softc* ahc, u_int8_t *scsirate,
u_int8_t *period, u_int8_t *offset,
char channel, int target));
#if defined(__FreeBSD__)
@ -281,13 +281,13 @@ static timeout_t
static void ahc_timeout __P((void *));
#endif
static void ahc_unbusy_target __P((struct ahc_data *ahc,
static u_int8_t ahc_unbusy_target __P((struct ahc_softc *ahc,
int target, char channel));
static void ahc_construct_sdtr __P((struct ahc_data *ahc, int start_byte,
static void ahc_construct_sdtr __P((struct ahc_softc *ahc, int start_byte,
u_int8_t period, u_int8_t offset));
static void ahc_construct_wdtr __P((struct ahc_data *ahc, int start_byte,
static void ahc_construct_wdtr __P((struct ahc_softc *ahc, int start_byte,
u_int8_t bus_width));
static void ahc_calc_residual __P((struct scb *scb));
@ -295,7 +295,7 @@ static void ahc_calc_residual __P((struct scb *scb));
#if defined(__FreeBSD__)
char *ahc_name(ahc)
struct ahc_data *ahc;
struct ahc_softc *ahc;
{
static char name[10];
@ -377,41 +377,53 @@ static int ahc_num_syncrates =
* is paused.
*/
#if defined(__FreeBSD__)
struct ahc_data *
ahc_alloc(unit, iobase, maddr, type, flags)
struct ahc_softc *
ahc_alloc(unit, iobase, maddr, type, flags, scb_data)
int unit;
u_int32_t iobase;
#elif defined(__NetBSD__)
void
ahc_construct(ahc, bc, ioh, maddr, type, flags)
struct ahc_data *ahc;
struct ahc_softc *ahc;
bus_chipset_tag_t bc;
bus_io_handle_t ioh;
#endif
vm_offset_t maddr;
ahc_type type;
ahc_flag flags;
struct scb_data *scb_data;
{
/*
* find unit and check we have that many defined
*/
#if defined(__FreeBSD__)
struct ahc_data *ahc;
struct ahc_softc *ahc;
size_t alloc_size;
/*
* Allocate a storage area for us
*/
ahc = malloc(sizeof(struct ahc_data), M_TEMP, M_NOWAIT);
if (scb_data == NULL)
/*
* We are not sharing SCB space with another controller
* so allocate our own SCB data space.
*/
alloc_size = sizeof(struct full_ahc_softc);
else
alloc_size = sizeof(struct ahc_softc);
ahc = malloc(alloc_size, M_DEVBUF, M_NOWAIT);
if (!ahc) {
printf("ahc%d: cannot malloc!\n", unit);
return NULL;
}
bzero(ahc, sizeof(struct ahc_data));
bzero(ahc, alloc_size);
#endif
STAILQ_INIT(&ahc->free_scbs);
if (scb_data == NULL) {
struct full_ahc_softc* full_softc = (struct full_ahc_softc*)ahc;
ahc->scb_data = &full_softc->scb_data_storage;
STAILQ_INIT(&ahc->scb_data->free_scbs);
} else
ahc->scb_data = scb_data;
STAILQ_INIT(&ahc->waiting_scbs);
#if defined(__FreeBSD__)
ahc->unit = unit;
@ -435,7 +447,7 @@ ahc_construct(ahc, bc, ioh, maddr, type, flags)
void
ahc_free(ahc)
struct ahc_data *ahc;
struct ahc_softc *ahc;
{
#if defined(__FreeBSD__)
free(ahc, M_DEVBUF);
@ -498,7 +510,7 @@ ahc_reset(devname, bc, ioh)
*/
static void
ahc_scsirate(ahc, scsirate, period, offset, channel, target )
struct ahc_data *ahc;
struct ahc_softc *ahc;
u_int8_t *scsirate;
u_int8_t *period;
u_int8_t *offset;
@ -592,7 +604,7 @@ ahcprint(aux, name)
*/
int
ahc_attach(ahc)
struct ahc_data *ahc;
struct ahc_softc *ahc;
{
struct scsibus_data *scbus;
@ -715,10 +727,10 @@ int
ahc_intr(arg)
void *arg;
{
struct ahc_data *ahc;
struct ahc_softc *ahc;
u_int8_t intstat;
ahc = (struct ahc_data *)arg;
ahc = (struct ahc_softc *)arg;
intstat = AHC_INB(ahc, INTSTAT);
/*
* Is this interrupt for me? or for
@ -764,7 +776,7 @@ ahc_intr(arg)
for (; qoutcnt > 0; qoutcnt--) {
scb_index = AHC_INB(ahc, QOUTFIFO);
scb = ahc->scbarray[scb_index];
scb = ahc->scb_data->scbarray[scb_index];
if (!scb || !(scb->flags & SCB_ACTIVE)) {
printf("%s: WARNING "
"no command for scb %d "
@ -798,7 +810,7 @@ ahc_intr(arg)
static void
ahc_handle_seqint(ahc, intstat)
struct ahc_data *ahc;
struct ahc_softc *ahc;
u_int8_t intstat;
{
struct scb *scb;
@ -813,16 +825,75 @@ ahc_handle_seqint(ahc, intstat)
switch (intstat & SEQINT_MASK) {
case NO_MATCH:
{
/*
* This could be for a normal abort request.
* Figure out the SCB that we were trying to find
* and only give an error if we didn't ask for this
* to happen.
*/
u_int8_t scb_index;
u_int8_t busy_scbid;
busy_scbid = ahc_unbusy_target(ahc, target, channel);
scb_index = AHC_INB(ahc, ARG_1);
if (scb_index == SCB_LIST_NULL)
/* Untagged Request */
scb_index = busy_scbid;
if (scb_index < ahc->scb_data->numscbs) {
scb = ahc->scb_data->scbarray[busy_scbid];
if (scb->hscb->control & ABORT_SCB) {
sc_print_addr(scb->xs->sc_link);
printf(" - SCB abort successfull\n");
break;
}
}
printf("%s:%c:%d: no active SCB for reconnecting "
"target - issuing ABORT\n",
ahc_name(ahc), channel, target);
printf("SAVED_TCL == 0x%x\n",
AHC_INB(ahc, SAVED_TCL));
ahc_unbusy_target(ahc, target, channel);
AHC_OUTB(ahc, SCB_CONTROL, 0);
AHC_OUTB(ahc, CLRSINT1, CLRSELTIMEO);
AHC_OUTB(ahc, RETURN_1, 0);
break;
}
case NO_MATCH_BUSY:
{
/* The SCB that wanted to link in is in CUR_SCBID */
u_int8_t scb_index;
u_int8_t busy_scbindex;
struct scb *busy_scb = NULL;
scb_index = AHC_INB(ahc, CUR_SCBID);
scb = ahc->scb_data->scbarray[scb_index];
/* Find the busy SCB and unbusy this target */
busy_scbindex = ahc_unbusy_target(ahc, scb->xs->sc_link->target,
channel);
if (busy_scbindex == SCB_LIST_NULL)
panic("%s:%c:%d: Target busy link failure, but "
"the target is not busy!\n",
ahc_name(ahc), channel, target);
busy_scb = ahc->scb_data->scbarray[busy_scbindex];
/* Busy SCB should be aborted */
if ((busy_scb != NULL)
&& (busy_scb->hscb->control & ABORT_SCB) == 0
&& (busy_scb->hscb->control & SCB_ACTIVE) != 0) {
panic("%s:%c:%d: Target busy link failure, but "
"busy SCB exists!\n",
ahc_name(ahc), channel, target);
}
if ((scb->hscb->control & ABORT_SCB) == 0) {
/* We didn't want to abort this one too */
AHC_OUTB(ahc, QINFIFO, scb_index);
} else
/* It's been aborted */
ahc_done(ahc, scb);
restart_sequencer(ahc);
}
case SEND_REJECT:
{
u_int8_t rejbyte = AHC_INB(ahc, REJBYTE);
@ -1070,7 +1141,7 @@ ahc_handle_seqint(ahc, intstat)
*/
scb_index = AHC_INB(ahc, SCB_TAG);
scb = ahc->scbarray[scb_index];
scb = ahc->scb_data->scbarray[scb_index];
hscb = scb->hscb;
/*
@ -1168,6 +1239,7 @@ ahc_handle_seqint(ahc, intstat)
* The upper level SCSI code will someday
* handle this properly.
*/
printf("Queue Full\n");
xs->error = XS_BUSY;
break;
default:
@ -1184,7 +1256,7 @@ ahc_handle_seqint(ahc, intstat)
struct scsi_xfer *xs;
scb_index = AHC_INB(ahc, SCB_TAG);
scb = ahc->scbarray[scb_index];
scb = ahc->scb_data->scbarray[scb_index];
xs = scb->xs;
/*
* We didn't recieve a valid tag back from
@ -1202,7 +1274,7 @@ ahc_handle_seqint(ahc, intstat)
int scb_index;
scb_index = AHC_INB(ahc, SCB_TAG);
scb = ahc->scbarray[scb_index];
scb = ahc->scb_data->scbarray[scb_index];
/*
* This SCB had MK_MESSAGE set in its control byte,
* informing the sequencer that we wanted to send a
@ -1256,7 +1328,7 @@ ahc_handle_seqint(ahc, intstat)
*/
u_int8_t scbindex = AHC_INB(ahc, SCB_TAG);
scb = ahc->scbarray[scbindex];
scb = ahc->scb_data->scbarray[scbindex];
if (scb->flags & SCB_DEVICE_RESET) {
u_int8_t targ_scratch;
int found;
@ -1297,7 +1369,7 @@ ahc_handle_seqint(ahc, intstat)
*/
u_int8_t scbindex = AHC_INB(ahc, SCB_TAG);
u_int32_t overrun;
scb = ahc->scbarray[scbindex];
scb = ahc->scb_data->scbarray[scbindex];
overrun = AHC_INB(ahc, STCNT0)
| (AHC_INB(ahc, STCNT1) << 8)
| (AHC_INB(ahc, STCNT2) << 16);
@ -1343,7 +1415,7 @@ ahc_handle_seqint(ahc, intstat)
static void
ahc_handle_scsiint(ahc, intstat)
struct ahc_data *ahc;
struct ahc_softc *ahc;
u_int8_t intstat;
{
u_int8_t scb_index;
@ -1352,7 +1424,7 @@ ahc_handle_scsiint(ahc, intstat)
scb_index = AHC_INB(ahc, SCB_TAG);
status = AHC_INB(ahc, SSTAT1);
scb = ahc->scbarray[scb_index];
scb = ahc->scb_data->scbarray[scb_index];
if (status & SCSIRSTI) {
char channel;
@ -1489,7 +1561,7 @@ ahc_handle_scsiint(ahc, intstat)
*/
static void
ahc_done(ahc, scb)
struct ahc_data *ahc;
struct ahc_softc *ahc;
struct scb *scb;
{
struct scsi_xfer *xs = scb->xs;
@ -1542,7 +1614,8 @@ ahc_done(ahc, scb)
printf("%s: target %d Tagged Queuing Device\n",
ahc_name(ahc), xs->sc_link->target);
ahc->tagenable |= mask;
if (ahc->maxhscbs >= 16 || (ahc->flags&AHC_PAGESCBS)) {
if (ahc->scb_data->maxhscbs >= 16
|| (ahc->flags & AHC_PAGESCBS)) {
/* Default to 8 tags */
xs->sc_link->opennings += 6;
} else {
@ -1568,7 +1641,7 @@ ahc_done(ahc, scb)
*/
int
ahc_init(ahc)
struct ahc_data *ahc;
struct ahc_softc *ahc;
{
u_int8_t scsi_conf, sblkctl, i;
u_int16_t ultraenable = 0;
@ -1587,22 +1660,28 @@ ahc_init(ahc)
case 0:
ahc->our_id = (AHC_INB(ahc, SCSICONF) & HSCSIID);
ahc->flags &= ~AHC_CHANNEL_B_PRIMARY;
if (ahc->type == AHC_394)
printf("Channel %c, SCSI Id=%d, ",
ahc->flags & AHC_CHNLB ? 'B' : 'A',
if ((ahc->type & AHC_39X) != 0) {
char channel = 'A';
if ((ahc->flags & (AHC_CHNLB|AHC_CHNLC)) != 0)
channel = ahc->flags & AHC_CHNLB ? 'B' : 'C';
printf("Channel %c, SCSI Id=%d, ", channel,
ahc->our_id);
else
} else
printf("Single Channel, SCSI Id=%d, ", ahc->our_id);
AHC_OUTB(ahc, FLAGS, SINGLE_BUS | (ahc->flags & AHC_PAGESCBS));
break;
case 2:
ahc->our_id = (AHC_INB(ahc, SCSICONF + 1) & 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',
if ((ahc->type & AHC_39X) != 0) {
char channel = 'A';
if ((ahc->flags & (AHC_CHNLB|AHC_CHNLC)) != 0)
channel = ahc->flags & AHC_CHNLB ? 'B' : 'C';
printf("Wide Channel %c, SCSI Id=%d, ", channel,
ahc->our_id);
else
} else
printf("Wide Channel, SCSI Id=%d, ", ahc->our_id);
ahc->type |= AHC_WIDE;
AHC_OUTB(ahc, FLAGS, WIDE_BUS | (ahc->flags & AHC_PAGESCBS));
@ -1622,7 +1701,7 @@ ahc_init(ahc)
/* Determine the number of SCBs and initialize them */
{
if (ahc->scb_data->maxhscbs == 0) {
/* SCB 0 heads the free list */
AHC_OUTB(ahc, FREE_SCBH, 0);
for (i = 0; i < AHC_SCB_MAX; i++) {
@ -1656,16 +1735,18 @@ ahc_init(ahc)
AHC_OUTB(ahc, SCBPTR, 0);
AHC_OUTB(ahc, SCB_CONTROL, 0);
ahc->maxhscbs = i;
ahc->scb_data->maxhscbs = i;
}
if ((ahc->maxhscbs < AHC_SCB_MAX) && (ahc->flags & AHC_PAGESCBS)) {
ahc->maxscbs = AHC_SCB_MAX;
printf("%d/%d SCBs\n", ahc->maxhscbs, ahc->maxscbs);
if ((ahc->scb_data->maxhscbs < AHC_SCB_MAX)
&& (ahc->flags & AHC_PAGESCBS)) {
ahc->scb_data->maxscbs = AHC_SCB_MAX;
printf("%d/%d SCBs\n", ahc->scb_data->maxhscbs,
ahc->scb_data->maxscbs);
} else {
ahc->maxscbs = ahc->maxhscbs;
ahc->scb_data->maxscbs = ahc->scb_data->maxhscbs;
ahc->flags &= ~AHC_PAGESCBS;
printf("%d SCBs\n", ahc->maxhscbs);
printf("%d SCBs\n", ahc->scb_data->maxhscbs);
}
@ -1832,12 +1913,12 @@ ahc_init(ahc)
/*
* Set the number of availible hardware SCBs
*/
AHC_OUTB(ahc, SCBCOUNT, ahc->maxhscbs);
AHC_OUTB(ahc, SCBCOUNT, ahc->scb_data->maxhscbs);
/*
* 2's compliment of maximum tag value
*/
i = ahc->maxscbs;
i = ahc->scb_data->maxscbs;
AHC_OUTB(ahc, COMP_SCBCOUNT, -i & 0xff);
/*
@ -1848,29 +1929,29 @@ ahc_init(ahc)
* sequencer depends on this array being physically
* contiguous.
*/
{
if (ahc->scb_data->hscbs == NULL) {
size_t array_size;
u_int32_t hscb_physaddr;
array_size = ahc->maxscbs * sizeof(struct hardware_scb);
array_size = ahc->scb_data->maxscbs*sizeof(struct hardware_scb);
if (array_size > PAGE_SIZE) {
ahc->hscbs = (struct hardware_scb *)
ahc->scb_data->hscbs = (struct hardware_scb *)
contigmalloc(array_size, M_DEVBUF,
M_NOWAIT, 0ul, 0xffffffff, PAGE_SIZE,
0x10000);
} else {
ahc->hscbs = (struct hardware_scb *)
ahc->scb_data->hscbs = (struct hardware_scb *)
malloc(array_size, M_DEVBUF, M_NOWAIT);
}
if (ahc->hscbs == NULL) {
if (ahc->scb_data->hscbs == NULL) {
printf("%s: unable to allocate hardware SCB array. "
"Failing attach\n");
return (-1);
}
/* Tell the sequencer where it can find the hscb array. */
hscb_physaddr = vtophys(ahc->hscbs);
hscb_physaddr = vtophys(ahc->scb_data->hscbs);
AHC_OUTB(ahc, HSCB_ADDR0, hscb_physaddr & 0xFF);
AHC_OUTB(ahc, HSCB_ADDR1, (hscb_physaddr >> 8)& 0xFF);
AHC_OUTB(ahc, HSCB_ADDR2, (hscb_physaddr >> 16)& 0xFF);
@ -1887,7 +1968,7 @@ ahc_init(ahc)
} else if (ahc->type & AHC_AIC7850) {
ahc->qfullcount = 8;
ahc->qcntmask = 0x0f;
} else if (ahc->maxhscbs == 255) {
} else if (ahc->scb_data->maxhscbs == 255) {
/* 7870/7880 with external SRAM */
ahc->qfullcount = 255;
ahc->qcntmask = 0xff;
@ -1972,12 +2053,12 @@ ahc_scsi_cmd(xs)
{
struct scb *scb;
struct hardware_scb *hscb;
struct ahc_data *ahc;
struct ahc_softc *ahc;
u_int16_t mask;
int flags;
int s;
ahc = (struct ahc_data *)xs->sc_link->adapter_softc;
ahc = (struct ahc_softc *)xs->sc_link->adapter_softc;
mask = (0x01 << (xs->sc_link->target
| (IS_SCSIBUS_B(ahc, xs->sc_link) ? SELBUSB : 0)));
SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahc_scsi_cmd\n"));
@ -2148,7 +2229,7 @@ ahc_scsi_cmd(xs)
*/
static void
ahc_run_waiting_queue(ahc)
struct ahc_data *ahc;
struct ahc_softc *ahc;
{
struct scb *scb;
@ -2188,7 +2269,7 @@ ahc_run_waiting_queue(ahc)
*/
static void
ahc_free_scb(ahc, scb)
struct ahc_data *ahc;
struct ahc_softc *ahc;
struct scb *scb;
{
struct hardware_scb *hscb;
@ -2203,13 +2284,13 @@ ahc_free_scb(ahc, scb)
hscb->control = 0;
hscb->status = 0;
STAILQ_INSERT_HEAD(&ahc->free_scbs, scb, links);
STAILQ_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links);
if (scb->links.stqe_next == NULL) {
/*
* If there were no SCBs availible, wake anybody waiting
* for one to come free.
*/
wakeup((caddr_t)&ahc->free_scbs);
wakeup((caddr_t)&ahc->scb_data->free_scbs);
}
#ifdef AHC_DEBUG
ahc->activescbs--;
@ -2225,7 +2306,7 @@ ahc_free_scb(ahc, scb)
*/
static struct scb *
ahc_get_scb(ahc, flags)
struct ahc_data *ahc;
struct ahc_softc *ahc;
u_int32_t flags;
{
struct scb *scbp;
@ -2237,15 +2318,14 @@ ahc_get_scb(ahc, flags)
* but only if we can't allocate a new one.
*/
while (1) {
if ((scbp = ahc->free_scbs.stqh_first)) {
STAILQ_REMOVE_HEAD(&ahc->free_scbs, links);
} else if(ahc->numscbs < ahc->maxscbs) {
if ((scbp = ahc->scb_data->free_scbs.stqh_first)) {
STAILQ_REMOVE_HEAD(&ahc->scb_data->free_scbs, links);
} else if(ahc->scb_data->numscbs < ahc->scb_data->maxscbs) {
scbp = ahc_alloc_scb(ahc);
if (scbp == NULL)
printf("%s: Can't malloc SCB\n", ahc_name(ahc));
}
else if ((flags & SCSI_NOSLEEP) == 0) {
tsleep((caddr_t)&ahc->free_scbs, PRIBIO,
} else if ((flags & SCSI_NOSLEEP) == 0) {
tsleep((caddr_t)&ahc->scb_data->free_scbs, PRIBIO,
"ahcscb", 0);
continue;
}
@ -2256,7 +2336,7 @@ ahc_get_scb(ahc, flags)
if (scbp) {
ahc->activescbs++;
if((ahc_debug & AHC_SHOWSCBCNT)
&& (ahc->activescbs == ahc->maxhscbs))
&& (ahc->activescbs == ahc->scb_data->maxhscbs))
printf("%s: Max SCBs active\n", ahc_name(ahc));
}
#endif
@ -2269,10 +2349,10 @@ ahc_get_scb(ahc, flags)
static struct scb *
ahc_alloc_scb(ahc)
struct ahc_data *ahc;
struct ahc_softc *ahc;
{
static struct ahc_dma_seg *next_sg_array = NULL;
static int sg_arrays_free;
static int sg_arrays_free = 0;
struct scb *newscb;
newscb = (struct scb *) malloc(sizeof(struct scb), M_DEVBUF, M_NOWAIT);
@ -2282,9 +2362,6 @@ ahc_alloc_scb(ahc)
size_t alloc_size = sizeof(struct ahc_dma_seg)
* AHC_NSEG;
sg_arrays_free = PAGE_SIZE / alloc_size;
/* Don't ever allocate more than we may need */
sg_arrays_free = MIN(ahc->maxscbs - ahc->numscbs,
sg_arrays_free);
alloc_size *= sg_arrays_free;
if (alloc_size == 0)
panic("%s: SG list doesn't fit in a page",
@ -2301,21 +2378,21 @@ ahc_alloc_scb(ahc)
next_sg_array = NULL;
else
next_sg_array = &next_sg_array[AHC_NSEG];
hscb = &ahc->hscbs[ahc->numscbs];
hscb = &ahc->scb_data->hscbs[ahc->scb_data->numscbs];
newscb->hscb = hscb;
hscb->control = 0;
hscb->status = 0;
hscb->tag = ahc->numscbs;
hscb->tag = ahc->scb_data->numscbs;
hscb->residual_data_count[2] = 0;
hscb->residual_data_count[1] = 0;
hscb->residual_data_count[0] = 0;
hscb->residual_SG_segment_count = 0;
ahc->numscbs++;
ahc->scb_data->numscbs++;
/*
* Place in the scbarray
* Never is removed.
*/
ahc->scbarray[hscb->tag] = newscb;
ahc->scb_data->scbarray[hscb->tag] = newscb;
} else {
free(newscb, M_DEVBUF);
newscb = NULL;
@ -2325,7 +2402,7 @@ ahc_alloc_scb(ahc)
}
static void ahc_loadseq(ahc)
struct ahc_data *ahc;
struct ahc_softc *ahc;
{
static u_char seqprog[] = {
# include "aic7xxx_seq.h"
@ -2347,7 +2424,7 @@ static void ahc_loadseq(ahc)
*/
static int
ahc_poll(ahc, wait)
struct ahc_data *ahc;
struct ahc_softc *ahc;
int wait; /* in msec */
{
while (--wait) {
@ -2367,7 +2444,7 @@ ahc_timeout(arg)
void *arg;
{
struct scb *scb = (struct scb *)arg;
struct ahc_data *ahc;
struct ahc_softc *ahc;
int s, found;
u_char bus_state;
@ -2379,7 +2456,7 @@ ahc_timeout(arg)
return;
}
ahc = (struct ahc_data *)scb->xs->sc_link->adapter_softc;
ahc = (struct ahc_softc *)scb->xs->sc_link->adapter_softc;
if (ahc->in_timeout) {
/*
@ -2505,7 +2582,7 @@ ahc_timeout(arg)
saved_scbptr = AHC_INB(ahc, SCBPTR);
active_scb_index = AHC_INB(ahc, SCB_TAG);
active_scb = ahc->scbarray[active_scb_index];
active_scb = ahc->scb_data->scbarray[active_scb_index];
if (bus_state != 0) {
/* Send the abort to the active SCB */
@ -2566,7 +2643,7 @@ ahc_timeout(arg)
*/
static u_int8_t
find_scb(ahc, scb)
struct ahc_data *ahc;
struct ahc_softc *ahc;
struct scb *scb;
{
u_int8_t saved_scbptr;
@ -2574,13 +2651,13 @@ find_scb(ahc, scb)
saved_scbptr = AHC_INB(ahc, SCBPTR);
curindex = 0;
for (curindex = 0; curindex < ahc->maxhscbs; curindex++) {
for (curindex = 0; curindex < ahc->scb_data->maxhscbs; curindex++) {
AHC_OUTB(ahc, SCBPTR, curindex);
if (AHC_INB(ahc, SCB_TAG) == scb->hscb->tag)
break;
}
AHC_OUTB(ahc, SCBPTR, saved_scbptr);
if (curindex > ahc->maxhscbs)
if (curindex > ahc->scb_data->maxhscbs)
curindex = SCB_LIST_NULL;
return curindex;
@ -2592,7 +2669,7 @@ find_scb(ahc, scb)
*/
static int
ahc_reset_device(ahc, target, channel, timedout_scb, xs_error)
struct ahc_data *ahc;
struct ahc_softc *ahc;
int target;
char channel;
struct scb *timedout_scb;
@ -2615,7 +2692,7 @@ ahc_reset_device(ahc, target, channel, timedout_scb, xs_error)
for (i = 0; i < (queued - found); i++) {
saved_queue[i] = AHC_INB(ahc, QINFIFO);
scbp = ahc->scbarray[saved_queue[i]];
scbp = ahc->scb_data->scbarray[saved_queue[i]];
if (ahc_match_scb (scbp, target, channel)) {
/*
* We found an scb that needs to be aborted.
@ -2645,7 +2722,7 @@ ahc_reset_device(ahc, target, channel, timedout_scb, xs_error)
while (next != SCB_LIST_NULL) {
AHC_OUTB(ahc, SCBPTR, next);
scbp = ahc->scbarray[AHC_INB(ahc, SCB_TAG)];
scbp = ahc->scb_data->scbarray[AHC_INB(ahc, SCB_TAG)];
if (ahc_match_scb(scbp, target, channel)) {
next = ahc_abort_wscb(ahc, scbp, next, prev,
timedout_scb, xs_error);
@ -2662,8 +2739,8 @@ ahc_reset_device(ahc, target, channel, timedout_scb, xs_error)
* are other (most likely tagged) commands that
* were disconnected when the reset occured.
*/
for (i = 0; i < ahc->numscbs; i++) {
scbp = ahc->scbarray[i];
for (i = 0; i < ahc->scb_data->numscbs; i++) {
scbp = ahc->scb_data->scbarray[i];
if ((scbp->flags & SCB_ACTIVE)
&& ahc_match_scb(scbp, target, channel)) {
/* Ensure the target is "free" */
@ -2685,8 +2762,8 @@ ahc_reset_device(ahc, target, channel, timedout_scb, xs_error)
*/
static u_char
ahc_abort_wscb (ahc, scbp, scbpos, prev, timedout_scb, xs_error)
struct ahc_data *ahc;
struct scb *scbp;
struct ahc_softc *ahc;
struct scb *scbp;
u_int8_t scbpos;
u_int8_t prev;
struct scb *timedout_scb;
@ -2733,14 +2810,15 @@ ahc_abort_wscb (ahc, scbp, scbpos, prev, timedout_scb, xs_error)
return next;
}
static void
static u_int8_t
ahc_unbusy_target(ahc, target, channel)
struct ahc_data *ahc;
struct ahc_softc *ahc;
int target;
char channel;
{
u_int8_t active_scb;
u_int8_t info_scb;
u_int8_t busy_scbid;
u_int32_t scb_offset;
info_scb = target / 4;
@ -2749,13 +2827,15 @@ ahc_unbusy_target(ahc, target, channel)
active_scb = AHC_INB(ahc, SCBPTR);
AHC_OUTB(ahc, SCBPTR, info_scb);
scb_offset = SCB_ACTIVE0 + (target & 0x03);
busy_scbid = AHC_INB(ahc, scb_offset);
AHC_OUTB(ahc, scb_offset, SCB_LIST_NULL);
AHC_OUTB(ahc, SCBPTR, active_scb);
return busy_scbid;
}
static void
ahc_reset_current_bus(ahc)
struct ahc_data *ahc;
struct ahc_softc *ahc;
{
AHC_OUTB(ahc, SCSISEQ, SCSIRSTO);
DELAY(1000);
@ -2764,7 +2844,7 @@ ahc_reset_current_bus(ahc)
static int
ahc_reset_channel(ahc, channel, timedout_scb, xs_error, initiate_reset)
struct ahc_data *ahc;
struct ahc_softc *ahc;
char channel;
struct scb *timedout_scb;
u_int32_t xs_error;
@ -2851,13 +2931,13 @@ ahc_reset_channel(ahc, channel, timedout_scb, xs_error, initiate_reset)
void
ahc_run_done_queue(ahc)
struct ahc_data *ahc;
struct ahc_softc *ahc;
{
int i;
struct scb *scbp;
for (i = 0; i < ahc->numscbs; i++) {
scbp = ahc->scbarray[i];
for (i = 0; i < ahc->scb_data->numscbs; i++) {
scbp = ahc->scb_data->scbarray[i];
if (scbp->flags & SCB_QUEUED_FOR_DONE)
ahc_done(ahc, scbp);
}
@ -2880,7 +2960,7 @@ ahc_match_scb (scb, target, channel)
static void
ahc_construct_sdtr(ahc, start_byte, period, offset)
struct ahc_data *ahc;
struct ahc_softc *ahc;
int start_byte;
u_int8_t period;
u_int8_t offset;
@ -2895,7 +2975,7 @@ ahc_construct_sdtr(ahc, start_byte, period, offset)
static void
ahc_construct_wdtr(ahc, start_byte, bus_width)
struct ahc_data *ahc;
struct ahc_softc *ahc;
int start_byte;
u_int8_t bus_width;
{

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.28.2.2 1996/10/06 01:31:25 gibbs Exp $
* $Id: aic7xxx.h,v 1.30 1996/10/25 06:42:53 gibbs Exp $
*/
#ifndef _AIC7XXX_H_
@ -97,23 +97,28 @@ 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_AIC7860 = 0x021, /* ULTRA version of the aic7850 */
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_294AU = 0x421, /* aic7860 based '2940' */
AHC_294 = 0x440, /* PCI Based Controller */
AHC_294U = 0x441, /* ULTRA PCI Based Controller */
AHC_394 = 0x840, /* Twin Channel PCI Controller */
AHC_394U = 0x841, /* Twin, ULTRA Channel PCI Controller */
AHC_NONE = 0x0000,
AHC_ULTRA = 0x0001, /* Supports 20MHz Transfers */
AHC_WIDE = 0x0002, /* Wide Channel */
AHC_TWIN = 0x0008, /* Twin Channel */
AHC_AIC7770 = 0x0010,
AHC_AIC7850 = 0x0020,
AHC_AIC7860 = 0x0021, /* ULTRA version of the aic7850 */
AHC_AIC7870 = 0x0040,
AHC_AIC7880 = 0x0041,
AHC_AIC78X0 = 0x0060, /* PCI Based Controller */
AHC_274 = 0x0110, /* EISA Based Controller */
AHC_284 = 0x0210, /* VL/ISA Based Controller */
AHC_294AU = 0x0421, /* aic7860 based '2940' */
AHC_294 = 0x0440, /* PCI Based Controller */
AHC_294U = 0x0441, /* ULTRA PCI Based Controller */
AHC_394 = 0x0840, /* Twin Channel PCI Controller */
AHC_394U = 0x0841, /* ULTRA, Twin Channel PCI Controller */
AHC_398 = 0x1040, /* Multi Channel PCI RAID Controller */
AHC_398U = 0x1041, /* ULTRA, Multi Channel PCI
* RAID Controller
*/
AHC_39X = 0x1800 /* Multi Channel PCI Adapter */
}ahc_type;
typedef enum {
@ -133,11 +138,16 @@ typedef enum {
* settings.
*/
AHC_CHNLB = 0x20, /*
* Second controller on 3940
* Second controller on 3940/398X
* Also encodes the offset in the
* SEEPROM for CHNLB info (32)
*/
}ahc_flag;
AHC_CHNLC = 0x40 /*
* Third controller on 3985
* Also encodes the offset in the
* SEEPROM for CHNLC info (64)
*/
} ahc_flag;
typedef enum {
SCB_FREE = 0x0000,
@ -154,7 +164,7 @@ typedef enum {
SCB_SENTORDEREDTAG = 0x0400,
SCB_MSGOUT_SDTR = 0x0800,
SCB_MSGOUT_WDTR = 0x1000
}scb_flag;
} scb_flag;
/*
* The driver keeps up to MAX_SCB scb structures per card in memory. The SCB
@ -198,8 +208,7 @@ struct hardware_scb {
*/
};
struct scb
{
struct scb {
struct hardware_scb *hscb;
STAILQ_ENTRY(scb) links; /* for chaining */
struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
@ -209,7 +218,22 @@ struct scb
u_int8_t position;/* Position in card's scbarray */
};
struct ahc_data {
struct scb_data {
struct hardware_scb *hscbs; /* Array of hardware SCBs */
struct scb *scbarray[AHC_SCB_MAX]; /* Array of kernel SCBs */
STAILQ_HEAD(, scb) free_scbs; /*
* Pool of SCBs ready to be assigned
* commands to execute.
*/
u_int8_t numscbs;
u_int8_t maxhscbs; /* Number of SCBs on the card */
u_int8_t maxscbs; /*
* Max SCBs we allocate total including
* any that will force us to page SCBs
*/
};
struct ahc_softc {
#if defined(__FreeBSD__)
int unit;
#elif defined(__NetBSD__)
@ -224,18 +248,14 @@ struct ahc_data {
u_int32_t baseport;
#endif
volatile u_int8_t *maddr;
struct hardware_scb *hscbs; /* Array of hardware SCBs */
struct scb *scbarray[AHC_SCB_MAX]; /* Array of kernel SCBs */
STAILQ_HEAD(, scb) free_scbs; /*
* Pool of SCBs ready to be assigned
* commands to execute.
*/
struct scb_data *scb_data;
struct scsi_link sc_link;
struct scsi_link sc_link_b; /* Second bus for Twin channel cards */
STAILQ_HEAD(, scb) waiting_scbs;/*
* SCBs waiting ready to go but
* waiting for space in the QINFIFO.
*/
struct scsi_link sc_link;
struct scsi_link sc_link_b; /* Second bus for Twin channel cards */
u_int8_t activescbs;
u_int16_t needsdtr_orig; /* Targets we initiate sync neg with */
u_int16_t needwdtr_orig; /* Targets we initiate wide neg with */
u_int16_t needsdtr; /* Current list of negotiated targets */
@ -247,13 +267,6 @@ struct ahc_data {
u_int16_t discenable; /* Targets allowed to disconnect */
u_int8_t our_id; /* our scsi id */
u_int8_t our_id_b; /* B channel scsi id */
u_int8_t numscbs;
u_int8_t activescbs;
u_int8_t maxhscbs; /* Number of SCBs on the card */
u_int8_t maxscbs; /*
* Max SCBs we allocate total including
* any that will force us to page SCBs
*/
u_int8_t qcntmask; /*
* Mask of valid registers in the
* Q*CNT registers.
@ -276,6 +289,11 @@ struct ahc_data {
u_int8_t in_timeout;
};
struct full_ahc_softc {
struct ahc_softc softc;
struct scb_data scb_data_storage;
};
/* #define AHC_DEBUG */
#ifdef AHC_DEBUG
/* Different debugging levels used when AHC_DEBUG is defined */
@ -291,20 +309,22 @@ extern int ahc_debug; /* Initialized in i386/scsi/aic7xxx.c */
#if defined(__FreeBSD__)
char *ahc_name __P((struct ahc_data *ahc));
char *ahc_name __P((struct ahc_softc *ahc));
void ahc_reset __P((u_int32_t iobase));
struct ahc_data *ahc_alloc __P((int unit, u_int32_t io_base, vm_offset_t maddr, ahc_type type, ahc_flag flags));
struct ahc_softc *ahc_alloc __P((int unit, u_int32_t io_base,
vm_offset_t maddr, ahc_type type,
ahc_flag flags, struct scb_data *scb_data));
#elif defined(__NetBSD__)
#define ahc_name(ahc) (ahc)->sc_dev.dv_xname
void ahc_reset __P((char *devname, bus_chipset_tag_t bc, bus_io_handle_t ioh));
void ahc_construct __P((struct ahc_data *ahc, bus_chipset_tag_t bc, bus_io_handle_t ioh, ahc_type type, ahc_flag flags));
void ahc_construct __P((struct ahc_softc *ahc, bus_chipset_tag_t bc, bus_io_handle_t ioh, ahc_type type, ahc_flag flags));
#endif
void ahc_free __P((struct ahc_data *));
int ahc_init __P((struct ahc_data *));
int ahc_attach __P((struct ahc_data *));
void ahc_free __P((struct ahc_softc *));
int ahc_init __P((struct ahc_softc *));
int ahc_attach __P((struct ahc_softc *));
#if defined(__FreeBSD__)
void ahc_intr __P((void *arg));
#elif defined(__NetBSD__)