summaryrefslogtreecommitdiffstats
path: root/sys/dev/aic7xxx
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/aic7xxx')
-rw-r--r--sys/dev/aic7xxx/aic7770.c39
-rw-r--r--sys/dev/aic7xxx/aic7xxx.c716
-rw-r--r--sys/dev/aic7xxx/aic7xxx.h94
-rw-r--r--sys/dev/aic7xxx/aic7xxx.reg4
-rw-r--r--sys/dev/aic7xxx/aic7xxx_inline.h65
-rw-r--r--sys/dev/aic7xxx/aic7xxx_osm.c4
-rw-r--r--sys/dev/aic7xxx/aic7xxx_pci.c168
7 files changed, 614 insertions, 476 deletions
diff --git a/sys/dev/aic7xxx/aic7770.c b/sys/dev/aic7xxx/aic7770.c
index 5229eb2..6acfb0f 100644
--- a/sys/dev/aic7xxx/aic7770.c
+++ b/sys/dev/aic7xxx/aic7770.c
@@ -37,7 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
- * $Id: //depot/aic7xxx/aic7xxx/aic7770.c#27 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7770.c#30 $
*
* $FreeBSD$
*/
@@ -59,6 +59,9 @@
#define ID_OLV_274x 0x04907782 /* Olivetti OEM */
#define ID_OLV_274xD 0x04907783 /* Olivetti OEM (Differential) */
+static int aic7770_chip_init(struct ahc_softc *ahc);
+static int aic7770_suspend(struct ahc_softc *ahc);
+static int aic7770_resume(struct ahc_softc *ahc);
static int aha2840_load_seeprom(struct ahc_softc *ahc);
static ahc_device_setup_t ahc_aic7770_VL_setup;
static ahc_device_setup_t ahc_aic7770_EISA_setup;;
@@ -144,6 +147,12 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
ahc->description = entry->name;
error = ahc_softc_init(ahc);
+ if (error != 0)
+ return (error);
+
+ ahc->bus_chip_init = aic7770_chip_init;
+ ahc->bus_suspend = aic7770_suspend;
+ ahc->bus_resume = aic7770_resume;
error = ahc_reset(ahc);
if (error != 0)
@@ -226,6 +235,9 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH);
ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF);
+ ahc->bus_softc.aic7770_softc.busspd = hostconf & DFTHRSH;
+ ahc->bus_softc.aic7770_softc.bustime = (hostconf << 2) & BOFF;
+
/*
* Generic aic7xxx initialization.
*/
@@ -253,6 +265,28 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
return (0);
}
+static int
+aic7770_chip_init(struct ahc_softc *ahc)
+{
+ ahc_outb(ahc, BUSSPD, ahc->bus_softc.aic7770_softc.busspd);
+ ahc_outb(ahc, BUSTIME, ahc->bus_softc.aic7770_softc.bustime);
+ ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS);
+ ahc_outb(ahc, BCTL, ENABLE);
+ return (ahc_chip_init(ahc));
+}
+
+static int
+aic7770_suspend(struct ahc_softc *ahc)
+{
+ return (ahc_suspend(ahc));
+}
+
+static int
+aic7770_resume(struct ahc_softc *ahc)
+{
+ return (ahc_resume(ahc));
+}
+
/*
* Read the 284x SEEPROM.
*/
@@ -280,7 +314,7 @@ aha2840_load_seeprom(struct ahc_softc *ahc)
if (bootverbose)
printf("%s: Reading SEEPROM...", ahc_name(ahc));
have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc,
- /*start_addr*/0, sizeof(sc)/2);
+ /*start_addr*/0, sizeof(*sc)/2);
if (have_seeprom) {
@@ -371,5 +405,6 @@ ahc_aic7770_setup(struct ahc_softc *ahc)
ahc->features = AHC_AIC7770_FE;
ahc->bugs |= AHC_TMODE_WIDEODD_BUG;
ahc->flags |= AHC_PAGESCBS;
+ ahc->instruction_ram_size = 448;
return (0);
}
diff --git a/sys/dev/aic7xxx/aic7xxx.c b/sys/dev/aic7xxx/aic7xxx.c
index 3816f90..406d597 100644
--- a/sys/dev/aic7xxx/aic7xxx.c
+++ b/sys/dev/aic7xxx/aic7xxx.c
@@ -37,7 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#112 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#128 $
*
* $FreeBSD$
*/
@@ -144,7 +144,8 @@ static struct ahc_syncrate ahc_syncrates[] =
#include "aic7xxx_seq.h"
/**************************** Function Declarations ***************************/
-static void ahc_force_renegotiation(struct ahc_softc *ahc);
+static void ahc_force_renegotiation(struct ahc_softc *ahc,
+ struct ahc_devinfo *devinfo);
static struct ahc_tmode_tstate*
ahc_alloc_tstate(struct ahc_softc *ahc,
u_int scsi_id, char channel);
@@ -224,7 +225,7 @@ static void ahc_reset_current_bus(struct ahc_softc *ahc);
#ifdef AHC_DUMP_SEQ
static void ahc_dumpseq(struct ahc_softc *ahc);
#endif
-static void ahc_loadseq(struct ahc_softc *ahc);
+static int ahc_loadseq(struct ahc_softc *ahc);
static int ahc_check_patch(struct ahc_softc *ahc,
struct patch **start_patch,
u_int start_instr, u_int *skip_addr);
@@ -389,7 +390,7 @@ ahc_handle_brkadrint(struct ahc_softc *ahc)
ahc_dump_card_state(ahc);
- /* Tell everyone that this HBA is no longer availible */
+ /* Tell everyone that this HBA is no longer available */
ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, ALL_CHANNELS,
CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_UNKNOWN,
CAM_NO_HBA);
@@ -1032,14 +1033,15 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
* we should look at the last phase the sequencer recorded,
* or the current phase presented on the bus.
*/
- u_int mesg_out;
- u_int curphase;
- u_int errorphase;
- u_int lastphase;
- u_int scsirate;
- u_int i;
- u_int sstat2;
- int silent;
+ struct ahc_devinfo devinfo;
+ u_int mesg_out;
+ u_int curphase;
+ u_int errorphase;
+ u_int lastphase;
+ u_int scsirate;
+ u_int i;
+ u_int sstat2;
+ int silent;
lastphase = ahc_inb(ahc, LASTPHASE);
curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
@@ -1128,7 +1130,9 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
* case we are out of sync for some external reason
* unknown (or unreported) by the target.
*/
- ahc_force_renegotiation(ahc);
+ ahc_fetch_devinfo(ahc, &devinfo);
+ ahc_force_renegotiation(ahc, &devinfo);
+
ahc_outb(ahc, CLRINT, CLRSCSIINT);
ahc_unpause(ahc);
} else if ((status & SELTO) != 0) {
@@ -1165,6 +1169,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
ahc_name(ahc), scbptr, scb_index);
ahc_dump_card_state(ahc);
} else {
+ struct ahc_devinfo devinfo;
#ifdef AHC_DEBUG
if ((ahc_debug & AHC_SHOW_SELTO) != 0) {
ahc_print_path(ahc, scb);
@@ -1181,7 +1186,8 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
* a unit attention in this case, so we must always
* renegotiate.
*/
- ahc_force_renegotiation(ahc);
+ ahc_scb_devinfo(ahc, &devinfo, scb);
+ ahc_force_renegotiation(ahc, &devinfo);
ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT);
ahc_freeze_devq(ahc, scb);
}
@@ -1189,13 +1195,14 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
ahc_restart(ahc);
} else if ((status & BUSFREE) != 0
&& (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) {
- u_int lastphase;
- u_int saved_scsiid;
- u_int saved_lun;
- u_int target;
- u_int initiator_role_id;
- char channel;
- int printerror;
+ struct ahc_devinfo devinfo;
+ u_int lastphase;
+ u_int saved_scsiid;
+ u_int saved_lun;
+ u_int target;
+ u_int initiator_role_id;
+ char channel;
+ int printerror;
/*
* Clear our selection hardware as soon as possible.
@@ -1227,13 +1234,13 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
target = SCSIID_TARGET(ahc, saved_scsiid);
initiator_role_id = SCSIID_OUR_ID(saved_scsiid);
channel = SCSIID_CHANNEL(ahc, saved_scsiid);
+ ahc_compile_devinfo(&devinfo, initiator_role_id,
+ target, saved_lun, channel, ROLE_INITIATOR);
printerror = 1;
if (lastphase == P_MESGOUT) {
- struct ahc_devinfo devinfo;
u_int tag;
- ahc_fetch_devinfo(ahc, &devinfo);
tag = SCB_LIST_NULL;
if (ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT_TAG, TRUE)
|| ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT, TRUE)) {
@@ -1344,13 +1351,15 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
if (lastphase == ahc_phase_table[i].phase)
break;
}
- /*
- * Renegotiate with this device at the
- * next oportunity just in case this busfree
- * is due to a negotiation mismatch with the
- * device.
- */
- ahc_force_renegotiation(ahc);
+ if (lastphase != P_BUSFREE) {
+ /*
+ * Renegotiate with this device at the
+ * next oportunity just in case this busfree
+ * is due to a negotiation mismatch with the
+ * device.
+ */
+ ahc_force_renegotiation(ahc, &devinfo);
+ }
printf("Unexpected busfree %s\n"
"SEQADDR == 0x%x\n",
ahc_phase_table[i].phasemsg,
@@ -1371,19 +1380,17 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
* a command to the current device.
*/
static void
-ahc_force_renegotiation(struct ahc_softc *ahc)
+ahc_force_renegotiation(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
{
- struct ahc_devinfo devinfo;
struct ahc_initiator_tinfo *targ_info;
struct ahc_tmode_tstate *tstate;
- ahc_fetch_devinfo(ahc, &devinfo);
targ_info = ahc_fetch_transinfo(ahc,
- devinfo.channel,
- devinfo.our_scsiid,
- devinfo.target,
+ devinfo->channel,
+ devinfo->our_scsiid,
+ devinfo->target,
&tstate);
- ahc_update_neg_request(ahc, &devinfo, tstate,
+ ahc_update_neg_request(ahc, devinfo, tstate,
targ_info, AHC_NEG_IF_NON_ASYNC);
}
@@ -2988,9 +2995,9 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
targ_scsirate = tinfo->scsirate;
/*
- * Parse as much of the message as is availible,
+ * Parse as much of the message as is available,
* rejecting it if we don't support it. When
- * the entire message is availible and has been
+ * the entire message is available and has been
* handled, return MSGLOOP_MSGCOMPLETE, indicating
* that we have parsed an entire message.
*
@@ -3898,7 +3905,7 @@ ahc_softc_insert(struct ahc_softc *ahc)
*/
list_ahc = TAILQ_FIRST(&ahc_tailq);
while (list_ahc != NULL
- && ahc_softc_comp(list_ahc, ahc) <= 0)
+ && ahc_softc_comp(ahc, list_ahc) <= 0)
list_ahc = TAILQ_NEXT(list_ahc, links);
if (list_ahc != NULL)
TAILQ_INSERT_BEFORE(list_ahc, ahc, links);
@@ -3942,7 +3949,6 @@ ahc_free(struct ahc_softc *ahc)
{
int i;
- ahc_fini_scbdata(ahc);
switch (ahc->init_level) {
default:
case 5:
@@ -3974,6 +3980,7 @@ ahc_free(struct ahc_softc *ahc)
ahc_dma_tag_destroy(ahc, ahc->parent_dmat);
#endif
ahc_platform_free(ahc);
+ ahc_fini_scbdata(ahc);
for (i = 0; i < AHC_NUM_TARGETS; i++) {
struct ahc_tmode_tstate *tstate;
@@ -4038,6 +4045,7 @@ ahc_reset(struct ahc_softc *ahc)
{
u_int sblkctl;
u_int sxfrctl1_a, sxfrctl1_b;
+ int error;
int wait;
/*
@@ -4128,12 +4136,19 @@ ahc_reset(struct ahc_softc *ahc)
}
ahc_outb(ahc, SXFRCTL1, sxfrctl1_a);
+ error = 0;
+ if (ahc->init_level > 0)
+ /*
+ * If a recovery action has forced a chip reset,
+ * re-initialize the chip to our liking.
+ */
+ error = ahc->bus_chip_init(ahc);
#ifdef AHC_DUMP_SEQ
- if (ahc->init_level == 0)
+ else
ahc_dumpseq(ahc);
#endif
- return (0);
+ return (error);
}
/*
@@ -4203,6 +4218,14 @@ ahc_build_free_scb_list(struct ahc_softc *ahc)
ahc_outb(ahc, SCB_LUN, 0xFF);
}
+ if ((ahc->flags & AHC_PAGESCBS) != 0) {
+ /* SCB 0 heads the free list. */
+ ahc_outb(ahc, FREE_SCBH, 0);
+ } else {
+ /* No free list. */
+ ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL);
+ }
+
/* Make sure that the last SCB terminates the free list */
ahc_outb(ahc, SCBPTR, i-1);
ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL);
@@ -4228,20 +4251,11 @@ ahc_init_scbdata(struct ahc_softc *ahc)
/* Determine the number of hardware SCBs and initialize them */
scb_data->maxhscbs = ahc_probe_scbs(ahc);
- if ((ahc->flags & AHC_PAGESCBS) != 0) {
- /* SCB 0 heads the free list */
- ahc_outb(ahc, FREE_SCBH, 0);
- } else {
- ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL);
- }
-
if (ahc->scb_data->maxhscbs == 0) {
printf("%s: No SCB space found\n", ahc_name(ahc));
return (ENXIO);
}
- ahc_build_free_scb_list(ahc);
-
/*
* Create our DMA tags. These tags define the kinds of device
* accessible memory allocations and memory mappings we will
@@ -4343,10 +4357,9 @@ ahc_init_scbdata(struct ahc_softc *ahc)
}
/*
- * Tell the sequencer which SCB will be the next one it receives.
+ * Reserve the next queued SCB.
*/
ahc->next_queued_scb = ahc_get_scb(ahc);
- ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag);
/*
* Note that we were successfull
@@ -4531,6 +4544,192 @@ ahc_controller_info(struct ahc_softc *ahc, char *buf)
sprintf(buf, "%d SCBs", ahc->scb_data->maxhscbs);
}
+int
+ahc_chip_init(struct ahc_softc *ahc)
+{
+ int term;
+ int error;
+ u_int i;
+ u_int scsi_conf;
+ u_int scsiseq_template;
+ uint32_t physaddr;
+
+ ahc_outb(ahc, SEQ_FLAGS, 0);
+ ahc_outb(ahc, SEQ_FLAGS2, 0);
+
+ /* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels*/
+ if (ahc->features & AHC_TWIN) {
+
+ /*
+ * Setup Channel B first.
+ */
+ ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB);
+ term = (ahc->flags & AHC_TERM_ENB_B) != 0 ? STPWEN : 0;
+ ahc_outb(ahc, SCSIID, ahc->our_id_b);
+ scsi_conf = ahc_inb(ahc, SCSICONF + 1);
+ ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL))
+ |term|ahc->seltime_b|ENSTIMER|ACTNEGEN);
+ if ((ahc->features & AHC_ULTRA2) != 0)
+ ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR);
+ ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
+ ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN);
+
+ /* Select Channel A */
+ ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB);
+ }
+ term = (ahc->flags & AHC_TERM_ENB_A) != 0 ? STPWEN : 0;
+ if ((ahc->features & AHC_ULTRA2) != 0)
+ ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id);
+ else
+ ahc_outb(ahc, SCSIID, ahc->our_id);
+ scsi_conf = ahc_inb(ahc, SCSICONF);
+ ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL))
+ |term|ahc->seltime
+ |ENSTIMER|ACTNEGEN);
+ if ((ahc->features & AHC_ULTRA2) != 0)
+ ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR);
+ ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
+ ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN);
+
+ /* There are no untagged SCBs active yet. */
+ for (i = 0; i < 16; i++) {
+ ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, 0));
+ if ((ahc->flags & AHC_SCB_BTT) != 0) {
+ int lun;
+
+ /*
+ * The SCB based BTT allows an entry per
+ * target and lun pair.
+ */
+ for (lun = 1; lun < AHC_NUM_LUNS; lun++)
+ ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, lun));
+ }
+ }
+
+ /* All of our queues are empty */
+ for (i = 0; i < 256; i++)
+ ahc->qoutfifo[i] = SCB_LIST_NULL;
+ ahc_sync_qoutfifo(ahc, BUS_DMASYNC_PREREAD);
+
+ for (i = 0; i < 256; i++)
+ ahc->qinfifo[i] = SCB_LIST_NULL;
+
+ if ((ahc->features & AHC_MULTI_TID) != 0) {
+ ahc_outb(ahc, TARGID, 0);
+ ahc_outb(ahc, TARGID + 1, 0);
+ }
+
+ /*
+ * Tell the sequencer where it can find our arrays in memory.
+ */
+ physaddr = ahc->scb_data->hscb_busaddr;
+ ahc_outb(ahc, HSCB_ADDR, physaddr & 0xFF);
+ ahc_outb(ahc, HSCB_ADDR + 1, (physaddr >> 8) & 0xFF);
+ ahc_outb(ahc, HSCB_ADDR + 2, (physaddr >> 16) & 0xFF);
+ ahc_outb(ahc, HSCB_ADDR + 3, (physaddr >> 24) & 0xFF);
+
+ physaddr = ahc->shared_data_busaddr;
+ ahc_outb(ahc, SHARED_DATA_ADDR, physaddr & 0xFF);
+ ahc_outb(ahc, SHARED_DATA_ADDR + 1, (physaddr >> 8) & 0xFF);
+ ahc_outb(ahc, SHARED_DATA_ADDR + 2, (physaddr >> 16) & 0xFF);
+ ahc_outb(ahc, SHARED_DATA_ADDR + 3, (physaddr >> 24) & 0xFF);
+
+ /*
+ * Initialize the group code to command length table.
+ * This overrides the values in TARG_SCSIRATE, so only
+ * setup the table after we have processed that information.
+ */
+ ahc_outb(ahc, CMDSIZE_TABLE, 5);
+ ahc_outb(ahc, CMDSIZE_TABLE + 1, 9);
+ ahc_outb(ahc, CMDSIZE_TABLE + 2, 9);
+ ahc_outb(ahc, CMDSIZE_TABLE + 3, 0);
+ ahc_outb(ahc, CMDSIZE_TABLE + 4, 15);
+ ahc_outb(ahc, CMDSIZE_TABLE + 5, 11);
+ ahc_outb(ahc, CMDSIZE_TABLE + 6, 0);
+ ahc_outb(ahc, CMDSIZE_TABLE + 7, 0);
+
+ if ((ahc->features & AHC_HS_MAILBOX) != 0)
+ ahc_outb(ahc, HS_MAILBOX, 0);
+
+ /* Tell the sequencer of our initial queue positions */
+ if ((ahc->features & AHC_TARGETMODE) != 0) {
+ ahc->tqinfifonext = 1;
+ ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1);
+ ahc_outb(ahc, TQINPOS, ahc->tqinfifonext);
+ }
+ ahc->qinfifonext = 0;
+ ahc->qoutfifonext = 0;
+ if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+ ahc_outb(ahc, QOFF_CTLSTA, SCB_QSIZE_256);
+ ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
+ ahc_outb(ahc, SNSCB_QOFF, ahc->qinfifonext);
+ ahc_outb(ahc, SDSCB_QOFF, 0);
+ } else {
+ ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
+ ahc_outb(ahc, QINPOS, ahc->qinfifonext);
+ ahc_outb(ahc, QOUTPOS, ahc->qoutfifonext);
+ }
+
+ /* We don't have any waiting selections */
+ ahc_outb(ahc, WAITING_SCBH, SCB_LIST_NULL);
+
+ /* Our disconnection list is empty too */
+ ahc_outb(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL);
+
+ /* Message out buffer starts empty */
+ ahc_outb(ahc, MSG_OUT, MSG_NOOP);
+
+ /*
+ * Setup the allowed SCSI Sequences based on operational mode.
+ * If we are a target, we'll enalbe select in operations once
+ * we've had a lun enabled.
+ */
+ scsiseq_template = ENSELO|ENAUTOATNO|ENAUTOATNP;
+ if ((ahc->flags & AHC_INITIATORROLE) != 0)
+ scsiseq_template |= ENRSELI;
+ ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq_template);
+
+ /* Initialize our list of free SCBs. */
+ ahc_build_free_scb_list(ahc);
+
+ /*
+ * Tell the sequencer which SCB will be the next one it receives.
+ */
+ ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag);
+
+ /*
+ * Load the Sequencer program and Enable the adapter
+ * in "fast" mode.
+ */
+ if (bootverbose)
+ printf("%s: Downloading Sequencer Program...",
+ ahc_name(ahc));
+
+ error = ahc_loadseq(ahc);
+ if (error != 0)
+ return (error);
+
+ if ((ahc->features & AHC_ULTRA2) != 0) {
+ int wait;
+
+ /*
+ * Wait for up to 500ms for our transceivers
+ * to settle. If the adapter does not have
+ * a cable attached, the transceivers may
+ * never settle, so don't complain if we
+ * fail here.
+ */
+ ahc_pause(ahc);
+ for (wait = 5000;
+ (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait;
+ wait--)
+ ahc_delay(100);
+ ahc_unpause(ahc);
+ }
+
+ return (0);
+}
+
/*
* Start the board, ready for normal operation
*/
@@ -4538,15 +4737,12 @@ int
ahc_init(struct ahc_softc *ahc)
{
int max_targ;
- int i;
- int term;
+ u_int i;
u_int scsi_conf;
- u_int scsiseq_template;
u_int ultraenb;
u_int discenable;
u_int tagenable;
size_t driver_data_size;
- uint32_t physaddr;
#ifdef AHC_DEBUG
if ((ahc_debug & AHC_DEBUG_SEQUENCER) != 0)
@@ -4600,7 +4796,9 @@ ahc_init(struct ahc_softc *ahc)
/* DMA tag for mapping buffers into device visible space. */
if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
/*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
- /*lowaddr*/BUS_SPACE_MAXADDR,
+ /*lowaddr*/ahc->flags & AHC_39BIT_ADDRESSING
+ ? (bus_addr_t)0x7FFFFFFFFFULL
+ : BUS_SPACE_MAXADDR_32BIT,
/*highaddr*/BUS_SPACE_MAXADDR,
/*filter*/NULL, /*filterarg*/NULL,
/*maxsize*/(AHC_NSEG - 1) * PAGE_SIZE,
@@ -4664,9 +4862,6 @@ ahc_init(struct ahc_softc *ahc)
for (i = 0; i < AHC_TMODE_CMDS; i++)
ahc->targetcmds[i].cmd_valid = 0;
ahc_sync_tqinfifo(ahc, BUS_DMASYNC_PREREAD);
- ahc->tqinfifonext = 1;
- ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1);
- ahc_outb(ahc, TQINPOS, ahc->tqinfifonext);
ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[256];
}
ahc->qinfifo = &ahc->qoutfifo[256];
@@ -4697,9 +4892,6 @@ ahc_init(struct ahc_softc *ahc)
}
}
- ahc_outb(ahc, SEQ_FLAGS, 0);
- ahc_outb(ahc, SEQ_FLAGS2, 0);
-
if (ahc->scb_data->maxhscbs < AHC_SCB_MAX_ALLOC) {
ahc->flags |= AHC_PAGESCBS;
} else {
@@ -4708,62 +4900,31 @@ ahc_init(struct ahc_softc *ahc)
#ifdef AHC_DEBUG
if (ahc_debug & AHC_SHOW_MISC) {
- printf("%s: hardware scb %d bytes; kernel scb %d bytes; "
- "ahc_dma %d bytes\n",
+ printf("%s: hardware scb %u bytes; kernel scb %u bytes; "
+ "ahc_dma %u bytes\n",
ahc_name(ahc),
- sizeof(struct hardware_scb),
- sizeof(struct scb),
- sizeof(struct ahc_dma_seg));
+ (u_int)sizeof(struct hardware_scb),
+ (u_int)sizeof(struct scb),
+ (u_int)sizeof(struct ahc_dma_seg));
}
#endif /* AHC_DEBUG */
- /* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels*/
+ /*
+ * Look at the information that board initialization or
+ * the board bios has left us.
+ */
if (ahc->features & AHC_TWIN) {
-
- /*
- * The device is gated to channel B after a chip reset,
- * so set those values first
- */
- ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB);
- term = (ahc->flags & AHC_TERM_ENB_B) != 0 ? STPWEN : 0;
- ahc_outb(ahc, SCSIID, ahc->our_id_b);
scsi_conf = ahc_inb(ahc, SCSICONF + 1);
- ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL))
- |term|ahc->seltime_b|ENSTIMER|ACTNEGEN);
- if ((ahc->features & AHC_ULTRA2) != 0)
- ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR);
- ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
- ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN);
-
if ((scsi_conf & RESET_SCSI) != 0
&& (ahc->flags & AHC_INITIATORROLE) != 0)
ahc->flags |= AHC_RESET_BUS_B;
-
- /* Select Channel A */
- ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB);
}
- term = (ahc->flags & AHC_TERM_ENB_A) != 0 ? STPWEN : 0;
- if ((ahc->features & AHC_ULTRA2) != 0)
- ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id);
- else
- ahc_outb(ahc, SCSIID, ahc->our_id);
- scsi_conf = ahc_inb(ahc, SCSICONF);
- ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL))
- |term|ahc->seltime
- |ENSTIMER|ACTNEGEN);
- if ((ahc->features & AHC_ULTRA2) != 0)
- ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR);
- ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
- ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN);
+ scsi_conf = ahc_inb(ahc, SCSICONF);
if ((scsi_conf & RESET_SCSI) != 0
&& (ahc->flags & AHC_INITIATORROLE) != 0)
ahc->flags |= AHC_RESET_BUS_A;
- /*
- * Look at the information that board initialization or
- * the board bios has left us.
- */
ultraenb = 0;
tagenable = ALL_TARGETS_MASK;
@@ -4815,7 +4976,7 @@ ahc_init(struct ahc_softc *ahc)
* connection type we have with the target.
*/
tinfo->user.period = ahc_syncrates->period;
- tinfo->user.offset = ~0;
+ tinfo->user.offset = MAX_OFFSET;
} else {
u_int scsirate;
uint16_t mask;
@@ -4850,7 +5011,7 @@ ahc_init(struct ahc_softc *ahc)
if (offset == 0)
tinfo->user.period = 0;
else
- tinfo->user.offset = ~0;
+ tinfo->user.offset = MAX_OFFSET;
if ((scsirate & SXFR_ULTRA2) <= 8/*10MHz*/
&& (ahc->features & AHC_DT) != 0)
tinfo->user.ppr_options =
@@ -4868,7 +5029,7 @@ ahc_init(struct ahc_softc *ahc)
? AHC_SYNCRATE_ULTRA
: AHC_SYNCRATE_FAST);
if (tinfo->user.period != 0)
- tinfo->user.offset = ~0;
+ tinfo->user.offset = MAX_OFFSET;
}
if (tinfo->user.period == 0)
tinfo->user.offset = 0;
@@ -4890,127 +5051,7 @@ ahc_init(struct ahc_softc *ahc)
ahc->user_discenable = discenable;
ahc->user_tagenable = tagenable;
- /* There are no untagged SCBs active yet. */
- for (i = 0; i < 16; i++) {
- ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, 0));
- if ((ahc->flags & AHC_SCB_BTT) != 0) {
- int lun;
-
- /*
- * The SCB based BTT allows an entry per
- * target and lun pair.
- */
- for (lun = 1; lun < AHC_NUM_LUNS; lun++)
- ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, lun));
- }
- }
-
- /* All of our queues are empty */
- for (i = 0; i < 256; i++)
- ahc->qoutfifo[i] = SCB_LIST_NULL;
- ahc_sync_qoutfifo(ahc, BUS_DMASYNC_PREREAD);
-
- for (i = 0; i < 256; i++)
- ahc->qinfifo[i] = SCB_LIST_NULL;
-
- if ((ahc->features & AHC_MULTI_TID) != 0) {
- ahc_outb(ahc, TARGID, 0);
- ahc_outb(ahc, TARGID + 1, 0);
- }
-
- /*
- * Tell the sequencer where it can find our arrays in memory.
- */
- physaddr = ahc->scb_data->hscb_busaddr;
- ahc_outb(ahc, HSCB_ADDR, physaddr & 0xFF);
- ahc_outb(ahc, HSCB_ADDR + 1, (physaddr >> 8) & 0xFF);
- ahc_outb(ahc, HSCB_ADDR + 2, (physaddr >> 16) & 0xFF);
- ahc_outb(ahc, HSCB_ADDR + 3, (physaddr >> 24) & 0xFF);
-
- physaddr = ahc->shared_data_busaddr;
- ahc_outb(ahc, SHARED_DATA_ADDR, physaddr & 0xFF);
- ahc_outb(ahc, SHARED_DATA_ADDR + 1, (physaddr >> 8) & 0xFF);
- ahc_outb(ahc, SHARED_DATA_ADDR + 2, (physaddr >> 16) & 0xFF);
- ahc_outb(ahc, SHARED_DATA_ADDR + 3, (physaddr >> 24) & 0xFF);
-
- /*
- * Initialize the group code to command length table.
- * This overrides the values in TARG_SCSIRATE, so only
- * setup the table after we have processed that information.
- */
- ahc_outb(ahc, CMDSIZE_TABLE, 5);
- ahc_outb(ahc, CMDSIZE_TABLE + 1, 9);
- ahc_outb(ahc, CMDSIZE_TABLE + 2, 9);
- ahc_outb(ahc, CMDSIZE_TABLE + 3, 0);
- ahc_outb(ahc, CMDSIZE_TABLE + 4, 15);
- ahc_outb(ahc, CMDSIZE_TABLE + 5, 11);
- ahc_outb(ahc, CMDSIZE_TABLE + 6, 0);
- ahc_outb(ahc, CMDSIZE_TABLE + 7, 0);
-
- /* Tell the sequencer of our initial queue positions */
- ahc_outb(ahc, KERNEL_QINPOS, 0);
- ahc_outb(ahc, QINPOS, 0);
- ahc_outb(ahc, QOUTPOS, 0);
-
- /*
- * Use the built in queue management registers
- * if they are available.
- */
- if ((ahc->features & AHC_QUEUE_REGS) != 0) {
- ahc_outb(ahc, QOFF_CTLSTA, SCB_QSIZE_256);
- ahc_outb(ahc, SDSCB_QOFF, 0);
- ahc_outb(ahc, SNSCB_QOFF, 0);
- ahc_outb(ahc, HNSCB_QOFF, 0);
- }
-
-
- /* We don't have any waiting selections */
- ahc_outb(ahc, WAITING_SCBH, SCB_LIST_NULL);
-
- /* Our disconnection list is empty too */
- ahc_outb(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL);
-
- /* Message out buffer starts empty */
- ahc_outb(ahc, MSG_OUT, MSG_NOOP);
-
- /*
- * Setup the allowed SCSI Sequences based on operational mode.
- * If we are a target, we'll enalbe select in operations once
- * we've had a lun enabled.
- */
- scsiseq_template = ENSELO|ENAUTOATNO|ENAUTOATNP;
- if ((ahc->flags & AHC_INITIATORROLE) != 0)
- scsiseq_template |= ENRSELI;
- ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq_template);
-
- /*
- * Load the Sequencer program and Enable the adapter
- * in "fast" mode.
- */
- if (bootverbose)
- printf("%s: Downloading Sequencer Program...",
- ahc_name(ahc));
-
- ahc_loadseq(ahc);
-
- if ((ahc->features & AHC_ULTRA2) != 0) {
- int wait;
-
- /*
- * Wait for up to 500ms for our transceivers
- * to settle. If the adapter does not have
- * a cable attached, the tranceivers may
- * never settle, so don't complain if we
- * fail here.
- */
- ahc_pause(ahc);
- for (wait = 5000;
- (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait;
- wait--)
- ahc_delay(100);
- ahc_unpause(ahc);
- }
- return (0);
+ return (ahc->bus_chip_init(ahc));
}
void
@@ -5046,7 +5087,6 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc)
maxloops = 1000;
ahc->flags |= AHC_ALL_INTERRUPTS;
- intstat = 0;
paused = FALSE;
do {
if (paused)
@@ -5056,11 +5096,11 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc)
paused = TRUE;
ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & ~ENSELO);
ahc_clear_critical_section(ahc);
- if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0)
- break;
+ intstat = ahc_inb(ahc, INTSTAT);
} while (--maxloops
- && (((intstat = ahc_inb(ahc, INTSTAT)) & INT_PEND) != 0
- || (ahc_inb(ahc, SSTAT0) & (SELDO|SELINGO))));
+ && (intstat != 0xFF || (ahc->features & AHC_REMOVABLE) == 0)
+ && ((intstat & INT_PEND) != 0
+ || (ahc_inb(ahc, SSTAT0) & (SELDO|SELINGO)) != 0));
if (maxloops == 0) {
printf("Infinite interrupt loop, INTSTAT = %x",
ahc_inb(ahc, INTSTAT));
@@ -5072,13 +5112,13 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc)
int
ahc_suspend(struct ahc_softc *ahc)
{
- uint8_t *ptr;
- int i;
ahc_pause_and_flushwork(ahc);
- if (LIST_FIRST(&ahc->pending_scbs) != NULL)
+ if (LIST_FIRST(&ahc->pending_scbs) != NULL) {
+ ahc_unpause(ahc);
return (EBUSY);
+ }
#if AHC_TARGET_MODE
/*
@@ -5086,73 +5126,11 @@ ahc_suspend(struct ahc_softc *ahc)
* Perhaps we should just refuse to be suspended if we
* are acting in a target role.
*/
- if (ahc->pending_device != NULL)
+ if (ahc->pending_device != NULL) {
+ ahc_unpause(ahc);
return (EBUSY);
-#endif
-
- /* Save volatile registers */
- if ((ahc->features & AHC_TWIN) != 0) {
- ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB);
- ahc->suspend_state.channel[1].scsiseq = ahc_inb(ahc, SCSISEQ);
- ahc->suspend_state.channel[1].sxfrctl0 = ahc_inb(ahc, SXFRCTL0);
- ahc->suspend_state.channel[1].sxfrctl1 = ahc_inb(ahc, SXFRCTL1);
- ahc->suspend_state.channel[1].simode0 = ahc_inb(ahc, SIMODE0);
- ahc->suspend_state.channel[1].simode1 = ahc_inb(ahc, SIMODE1);
- ahc->suspend_state.channel[1].seltimer = ahc_inb(ahc, SELTIMER);
- ahc->suspend_state.channel[1].seqctl = ahc_inb(ahc, SEQCTL);
- ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB);
- }
- ahc->suspend_state.channel[0].scsiseq = ahc_inb(ahc, SCSISEQ);
- ahc->suspend_state.channel[0].sxfrctl0 = ahc_inb(ahc, SXFRCTL0);
- ahc->suspend_state.channel[0].sxfrctl1 = ahc_inb(ahc, SXFRCTL1);
- ahc->suspend_state.channel[0].simode0 = ahc_inb(ahc, SIMODE0);
- ahc->suspend_state.channel[0].simode1 = ahc_inb(ahc, SIMODE1);
- ahc->suspend_state.channel[0].seltimer = ahc_inb(ahc, SELTIMER);
- ahc->suspend_state.channel[0].seqctl = ahc_inb(ahc, SEQCTL);
-
- if ((ahc->chip & AHC_PCI) != 0) {
- ahc->suspend_state.dscommand0 = ahc_inb(ahc, DSCOMMAND0);
- ahc->suspend_state.dspcistatus = ahc_inb(ahc, DSPCISTATUS);
- }
-
- if ((ahc->features & AHC_DT) != 0) {
- u_int sfunct;
-
- sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
- ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
- ahc->suspend_state.optionmode = ahc_inb(ahc, OPTIONMODE);
- ahc_outb(ahc, SFUNCT, sfunct);
- ahc->suspend_state.crccontrol1 = ahc_inb(ahc, CRCCONTROL1);
- }
-
- if ((ahc->features & AHC_MULTI_FUNC) != 0)
- ahc->suspend_state.scbbaddr = ahc_inb(ahc, SCBBADDR);
-
- if ((ahc->features & AHC_ULTRA2) != 0)
- ahc->suspend_state.dff_thrsh = ahc_inb(ahc, DFF_THRSH);
-
- ptr = ahc->suspend_state.scratch_ram;
- for (i = 0; i < 64; i++)
- *ptr++ = ahc_inb(ahc, SRAM_BASE + i);
-
- if ((ahc->features & AHC_MORE_SRAM) != 0) {
- for (i = 0; i < 16; i++)
- *ptr++ = ahc_inb(ahc, TARG_OFFSET + i);
- }
-
- ptr = ahc->suspend_state.btt;
- if ((ahc->flags & AHC_SCB_BTT) != 0) {
- for (i = 0;i < AHC_NUM_TARGETS; i++) {
- int j;
-
- for (j = 0;j < AHC_NUM_LUNS; j++) {
- u_int tcl;
-
- tcl = BUILD_TCL(i << 4, j);
- *ptr = ahc_index_busy_tcl(ahc, tcl);
- }
- }
}
+#endif
ahc_shutdown(ahc);
return (0);
}
@@ -5160,81 +5138,8 @@ ahc_suspend(struct ahc_softc *ahc)
int
ahc_resume(struct ahc_softc *ahc)
{
- uint8_t *ptr;
- int i;
ahc_reset(ahc);
-
- ahc_build_free_scb_list(ahc);
-
- /* Restore volatile registers */
- if ((ahc->features & AHC_TWIN) != 0) {
- ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB);
- ahc_outb(ahc, SCSIID, ahc->our_id);
- ahc_outb(ahc, SCSISEQ, ahc->suspend_state.channel[1].scsiseq);
- ahc_outb(ahc, SXFRCTL0, ahc->suspend_state.channel[1].sxfrctl0);
- ahc_outb(ahc, SXFRCTL1, ahc->suspend_state.channel[1].sxfrctl1);
- ahc_outb(ahc, SIMODE0, ahc->suspend_state.channel[1].simode0);
- ahc_outb(ahc, SIMODE1, ahc->suspend_state.channel[1].simode1);
- ahc_outb(ahc, SELTIMER, ahc->suspend_state.channel[1].seltimer);
- ahc_outb(ahc, SEQCTL, ahc->suspend_state.channel[1].seqctl);
- ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB);
- }
- ahc_outb(ahc, SCSISEQ, ahc->suspend_state.channel[0].scsiseq);
- ahc_outb(ahc, SXFRCTL0, ahc->suspend_state.channel[0].sxfrctl0);
- ahc_outb(ahc, SXFRCTL1, ahc->suspend_state.channel[0].sxfrctl1);
- ahc_outb(ahc, SIMODE0, ahc->suspend_state.channel[0].simode0);
- ahc_outb(ahc, SIMODE1, ahc->suspend_state.channel[0].simode1);
- ahc_outb(ahc, SELTIMER, ahc->suspend_state.channel[0].seltimer);
- ahc_outb(ahc, SEQCTL, ahc->suspend_state.channel[0].seqctl);
- if ((ahc->features & AHC_ULTRA2) != 0)
- ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id);
- else
- ahc_outb(ahc, SCSIID, ahc->our_id);
-
- if ((ahc->chip & AHC_PCI) != 0) {
- ahc_outb(ahc, DSCOMMAND0, ahc->suspend_state.dscommand0);
- ahc_outb(ahc, DSPCISTATUS, ahc->suspend_state.dspcistatus);
- }
-
- if ((ahc->features & AHC_DT) != 0) {
- u_int sfunct;
-
- sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
- ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
- ahc_outb(ahc, OPTIONMODE, ahc->suspend_state.optionmode);
- ahc_outb(ahc, SFUNCT, sfunct);
- ahc_outb(ahc, CRCCONTROL1, ahc->suspend_state.crccontrol1);
- }
-
- if ((ahc->features & AHC_MULTI_FUNC) != 0)
- ahc_outb(ahc, SCBBADDR, ahc->suspend_state.scbbaddr);
-
- if ((ahc->features & AHC_ULTRA2) != 0)
- ahc_outb(ahc, DFF_THRSH, ahc->suspend_state.dff_thrsh);
-
- ptr = ahc->suspend_state.scratch_ram;
- for (i = 0; i < 64; i++)
- ahc_outb(ahc, SRAM_BASE + i, *ptr++);
-
- if ((ahc->features & AHC_MORE_SRAM) != 0) {
- for (i = 0; i < 16; i++)
- ahc_outb(ahc, TARG_OFFSET + i, *ptr++);
- }
-
- ptr = ahc->suspend_state.btt;
- if ((ahc->flags & AHC_SCB_BTT) != 0) {
- for (i = 0;i < AHC_NUM_TARGETS; i++) {
- int j;
-
- for (j = 0;j < AHC_NUM_LUNS; j++) {
- u_int tcl;
-
- tcl = BUILD_TCL(i << 4, j);
- ahc_busy_tcl(ahc, tcl, *ptr);
- }
- }
- }
return (0);
}
@@ -6379,19 +6284,11 @@ void
ahc_dumpseq(struct ahc_softc* ahc)
{
int i;
- int max_prog;
-
- if ((ahc->chip & AHC_BUS_MASK) < AHC_PCI)
- max_prog = 448;
- else if ((ahc->features & AHC_ULTRA2) != 0)
- max_prog = 768;
- else
- max_prog = 512;
ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM);
ahc_outb(ahc, SEQADDR0, 0);
ahc_outb(ahc, SEQADDR1, 0);
- for (i = 0; i < max_prog; i++) {
+ for (i = 0; i < ahc->instruction_ram_size; i++) {
uint8_t ins_bytes[4];
ahc_insb(ahc, SEQRAM, ins_bytes, 4);
@@ -6403,7 +6300,7 @@ ahc_dumpseq(struct ahc_softc* ahc)
}
#endif
-static void
+static int
ahc_loadseq(struct ahc_softc *ahc)
{
struct cs cs_table[num_critical_sections];
@@ -6413,9 +6310,9 @@ ahc_loadseq(struct ahc_softc *ahc)
u_int cs_count;
u_int cur_cs;
u_int i;
- int downloaded;
u_int skip_addr;
u_int sg_prefetch_cnt;
+ int downloaded;
uint8_t download_consts[7];
/*
@@ -6456,6 +6353,19 @@ ahc_loadseq(struct ahc_softc *ahc)
*/
continue;
}
+
+ if (downloaded == ahc->instruction_ram_size) {
+ /*
+ * We're about to exceed the instruction
+ * storage capacity for this chip. Fail
+ * the load.
+ */
+ printf("\n%s: Program too large for instruction memory "
+ "size of %d!\n", ahc_name(ahc),
+ ahc->instruction_ram_size);
+ return (ENOMEM);
+ }
+
/*
* Move through the CS table until we find a CS
* that might apply to this instruction.
@@ -6498,6 +6408,7 @@ ahc_loadseq(struct ahc_softc *ahc)
printf("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n",
ahc_name(ahc), ahc->features, ahc->bugs, ahc->flags);
}
+ return (0);
}
static int
@@ -6942,11 +6853,12 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
struct ahc_tmode_lstate *lstate;
struct ccb_en_lun *cel;
cam_status status;
+ u_long s;
u_int target;
u_int lun;
u_int target_mask;
u_int our_id;
- u_long s;
+ int error;
char channel;
status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate, &lstate,
@@ -7023,7 +6935,8 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
*/
if ((ahc->flags & AHC_TARGETROLE) == 0
&& ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
- u_long s;
+ u_long s;
+ ahc_flag saved_flags;
printf("Configuring Target Mode\n");
ahc_lock(ahc, &s);
@@ -7032,11 +6945,28 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
ahc_unlock(ahc, &s);
return;
}
+ saved_flags = ahc->flags;
ahc->flags |= AHC_TARGETROLE;
if ((ahc->features & AHC_MULTIROLE) == 0)
ahc->flags &= ~AHC_INITIATORROLE;
ahc_pause(ahc);
- ahc_loadseq(ahc);
+ error = ahc_loadseq(ahc);
+ if (error != 0) {
+ /*
+ * Restore original configuration and notify
+ * the caller that we cannot support target mode.
+ * Since the adapter started out in this
+ * configuration, the firmware load will succeed,
+ * so there is no point in checking ahc_loadseq's
+ * return value.
+ */
+ ahc->flags = saved_flags;
+ (void)ahc_loadseq(ahc);
+ ahc_unpause(ahc);
+ ahc_unlock(ahc, &s);
+ ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
+ return;
+ }
ahc_unlock(ahc, &s);
}
cel = &ccb->cel;
@@ -7272,7 +7202,11 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
ahc->flags &= ~AHC_TARGETROLE;
ahc->flags |= AHC_INITIATORROLE;
ahc_pause(ahc);
- ahc_loadseq(ahc);
+ /*
+ * Returning to a configuration that
+ * fit previously will always succeed.
+ */
+ (void)ahc_loadseq(ahc);
}
}
ahc_unpause(ahc);
diff --git a/sys/dev/aic7xxx/aic7xxx.h b/sys/dev/aic7xxx/aic7xxx.h
index a30deb3..de1a221 100644
--- a/sys/dev/aic7xxx/aic7xxx.h
+++ b/sys/dev/aic7xxx/aic7xxx.h
@@ -37,7 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#70 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#75 $
*
* $FreeBSD$
*/
@@ -365,14 +365,15 @@ typedef enum {
AHC_LSCBS_ENABLED = 0x2000000, /* 64Byte SCBs enabled */
AHC_SCB_CONFIG_USED = 0x4000000, /* No SEEPROM but SCB2 had info. */
AHC_NO_BIOS_INIT = 0x8000000, /* No BIOS left over settings. */
- AHC_DISABLE_PCI_PERR = 0x10000000
+ AHC_DISABLE_PCI_PERR = 0x10000000,
+ AHC_HAS_TERM_LOGIC = 0x20000000
} ahc_flag;
/************************* Hardware SCB Definition ***************************/
/*
* The driver keeps up to MAX_SCB scb structures per card in memory. The SCB
- * consists of a "hardware SCB" mirroring the fields availible on the card
+ * consists of a "hardware SCB" mirroring the fields available on the card
* and additional information the kernel stores for each transaction.
*
* To minimize space utilization, a portion of the hardware scb stores
@@ -691,7 +692,7 @@ struct ahc_tmode_lstate;
#define AHC_WIDTH_UNKNOWN 0xFF
#define AHC_PERIOD_UNKNOWN 0xFF
-#define AHC_OFFSET_UNKNOWN 0x0
+#define AHC_OFFSET_UNKNOWN 0xFF
#define AHC_PPR_OPTS_UNKNOWN 0xFF
/*
@@ -877,31 +878,39 @@ typedef enum {
/*********************** Software Configuration Structure *********************/
TAILQ_HEAD(scb_tailq, scb);
-struct ahc_suspend_channel_state {
- uint8_t scsiseq;
- uint8_t sxfrctl0;
- uint8_t sxfrctl1;
- uint8_t simode0;
- uint8_t simode1;
- uint8_t seltimer;
- uint8_t seqctl;
+struct ahc_aic7770_softc {
+ /*
+ * Saved register state used for chip_init().
+ */
+ uint8_t busspd;
+ uint8_t bustime;
+};
+
+struct ahc_pci_softc {
+ /*
+ * Saved register state used for chip_init().
+ */
+ uint32_t devconfig;
+ uint16_t targcrccnt;
+ uint8_t command;
+ uint8_t csize_lattime;
+ uint8_t optionmode;
+ uint8_t crccontrol1;
+ uint8_t dscommand0;
+ uint8_t dspcistatus;
+ uint8_t scbbaddr;
+ uint8_t dff_thrsh;
};
-struct ahc_suspend_state {
- struct ahc_suspend_channel_state channel[2];
- uint8_t optionmode;
- uint8_t dscommand0;
- uint8_t dspcistatus;
- /* hsmailbox */
- uint8_t crccontrol1;
- uint8_t scbbaddr;
- /* Host and sequencer SCB counts */
- uint8_t dff_thrsh;
- uint8_t *scratch_ram;
- uint8_t *btt;
+union ahc_bus_softc {
+ struct ahc_aic7770_softc aic7770_softc;
+ struct ahc_pci_softc pci_softc;
};
typedef void (*ahc_bus_intr_t)(struct ahc_softc *);
+typedef int (*ahc_bus_chip_init_t)(struct ahc_softc *);
+typedef int (*ahc_bus_suspend_t)(struct ahc_softc *);
+typedef int (*ahc_bus_resume_t)(struct ahc_softc *);
typedef void ahc_callback_t (void *);
struct ahc_softc {
@@ -937,6 +946,11 @@ struct ahc_softc {
struct scb_tailq untagged_queues[AHC_NUM_TARGETS];
/*
+ * Bus attachment specific data.
+ */
+ union ahc_bus_softc bus_softc;
+
+ /*
* Platform specific data.
*/
struct ahc_platform_data *platform_data;
@@ -952,6 +966,22 @@ struct ahc_softc {
ahc_bus_intr_t bus_intr;
/*
+ * Bus specific initialization required
+ * after a chip reset.
+ */
+ ahc_bus_chip_init_t bus_chip_init;
+
+ /*
+ * Bus specific suspend routine.
+ */
+ ahc_bus_suspend_t bus_suspend;
+
+ /*
+ * Bus specific resume routine.
+ */
+ ahc_bus_resume_t bus_resume;
+
+ /*
* Target mode related state kept on a per enabled lun basis.
* Targets that are not enabled will have null entries.
* As an initiator, we keep one target entry for our initiator
@@ -1043,9 +1073,6 @@ struct ahc_softc {
*/
bus_addr_t dma_bug_buf;
- /* Information saved through suspend/resume cycles */
- struct ahc_suspend_state suspend_state;
-
/* Number of enabled target mode device on this card */
u_int enabled_luns;
@@ -1055,7 +1082,16 @@ struct ahc_softc {
/* PCI cacheline size. */
u_int pci_cachesize;
- u_int stack_size;
+ /*
+ * Count of parity errors we have seen as a target.
+ * We auto-disable parity error checking after seeing
+ * AHC_PCI_TARGET_PERR_THRESH number of errors.
+ */
+ u_int pci_target_perr_count;
+#define AHC_PCI_TARGET_PERR_THRESH 10
+
+ /* Maximum number of sequencer instructions supported. */
+ u_int instruction_ram_size;
/* Per-Unit descriptive information */
const char *description;
@@ -1152,6 +1188,7 @@ int ahc_match_scb(struct ahc_softc *ahc, struct scb *scb,
struct ahc_softc *ahc_alloc(void *platform_arg, char *name);
int ahc_softc_init(struct ahc_softc *);
void ahc_controller_info(struct ahc_softc *ahc, char *buf);
+int ahc_chip_init(struct ahc_softc *ahc);
int ahc_init(struct ahc_softc *ahc);
void ahc_intr_enable(struct ahc_softc *ahc, int enable);
void ahc_pause_and_flushwork(struct ahc_softc *ahc);
@@ -1167,7 +1204,6 @@ int ahc_reset(struct ahc_softc *ahc);
void ahc_shutdown(void *arg);
/*************************** Interrupt Services *******************************/
-void ahc_pci_intr(struct ahc_softc *ahc);
void ahc_clear_intstat(struct ahc_softc *ahc);
void ahc_run_qoutfifo(struct ahc_softc *ahc);
#ifdef AHC_TARGET_MODE
diff --git a/sys/dev/aic7xxx/aic7xxx.reg b/sys/dev/aic7xxx/aic7xxx.reg
index 7dc8f6d..49bc1f2 100644
--- a/sys/dev/aic7xxx/aic7xxx.reg
+++ b/sys/dev/aic7xxx/aic7xxx.reg
@@ -39,7 +39,7 @@
*
* $FreeBSD$
*/
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#37 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $"
/*
* This file is processed by the aic7xxx_asm utility for use in assembling
@@ -1580,7 +1580,7 @@ const BUS_32_BIT 0x02
const MAX_OFFSET_8BIT 0x0f
const MAX_OFFSET_16BIT 0x08
const MAX_OFFSET_ULTRA2 0x7f
-const MAX_OFFSET 0xff
+const MAX_OFFSET 0x7f
const HOST_MSG 0xff
/* Target mode command processing constants */
diff --git a/sys/dev/aic7xxx/aic7xxx_inline.h b/sys/dev/aic7xxx/aic7xxx_inline.h
index 53de390..f066b8f 100644
--- a/sys/dev/aic7xxx/aic7xxx_inline.h
+++ b/sys/dev/aic7xxx/aic7xxx_inline.h
@@ -37,7 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#39 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#42 $
*
* $FreeBSD$
*/
@@ -460,7 +460,7 @@ ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
/*
- * Make sure our data is consistant from the
+ * Make sure our data is consistent from the
* perspective of the adapter.
*/
ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
@@ -500,7 +500,7 @@ ahc_get_sense_bufaddr(struct ahc_softc *ahc, struct scb *scb)
static __inline void ahc_sync_qoutfifo(struct ahc_softc *ahc, int op);
static __inline void ahc_sync_tqinfifo(struct ahc_softc *ahc, int op);
static __inline u_int ahc_check_cmdcmpltqueues(struct ahc_softc *ahc);
-static __inline void ahc_intr(struct ahc_softc *ahc);
+static __inline int ahc_intr(struct ahc_softc *ahc);
static __inline void
ahc_sync_qoutfifo(struct ahc_softc *ahc, int op)
@@ -558,7 +558,7 @@ ahc_check_cmdcmpltqueues(struct ahc_softc *ahc)
/*
* Catch an interrupt from the adapter
*/
-static __inline void
+static __inline int
ahc_intr(struct ahc_softc *ahc)
{
u_int intstat;
@@ -570,7 +570,7 @@ ahc_intr(struct ahc_softc *ahc)
* so just return. This is likely just a shared
* interrupt.
*/
- return;
+ return (0);
}
/*
* Instead of directly reading the interrupt status register,
@@ -585,6 +585,20 @@ ahc_intr(struct ahc_softc *ahc)
intstat = ahc_inb(ahc, INTSTAT);
}
+ if ((intstat & INT_PEND) == 0) {
+#if AHC_PCI_CONFIG > 0
+ if (ahc->unsolicited_ints > 500) {
+ ahc->unsolicited_ints = 0;
+ if ((ahc->chip & AHC_PCI) != 0
+ && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
+ ahc->bus_intr(ahc);
+ }
+#endif
+ ahc->unsolicited_ints++;
+ return (0);
+ }
+ ahc->unsolicited_ints = 0;
+
if (intstat & CMDCMPLT) {
ahc_outb(ahc, CLRINT, CLRCMDINT);
@@ -604,38 +618,25 @@ ahc_intr(struct ahc_softc *ahc)
#endif
}
- if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0)
- /* Hot eject */
- return;
-
- if ((intstat & INT_PEND) == 0) {
-#if AHC_PCI_CONFIG > 0
- if (ahc->unsolicited_ints > 500) {
- ahc->unsolicited_ints = 0;
- if ((ahc->chip & AHC_PCI) != 0
- && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
- ahc->bus_intr(ahc);
- }
-#endif
- ahc->unsolicited_ints++;
- return;
- }
- ahc->unsolicited_ints = 0;
-
- if (intstat & BRKADRINT) {
+ /*
+ * Handle statuses that may invalidate our cached
+ * copy of INTSTAT separately.
+ */
+ if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) {
+ /* Hot eject. Do nothing */
+ } else if (intstat & BRKADRINT) {
ahc_handle_brkadrint(ahc);
- /* Fatal error, no more interrupts to handle. */
- return;
- }
+ } else if ((intstat & (SEQINT|SCSIINT)) != 0) {
- if ((intstat & (SEQINT|SCSIINT)) != 0)
ahc_pause_bug_fix(ahc);
- if ((intstat & SEQINT) != 0)
- ahc_handle_seqint(ahc, intstat);
+ if ((intstat & SEQINT) != 0)
+ ahc_handle_seqint(ahc, intstat);
- if ((intstat & SCSIINT) != 0)
- ahc_handle_scsiint(ahc, intstat);
+ if ((intstat & SCSIINT) != 0)
+ ahc_handle_scsiint(ahc, intstat);
+ }
+ return (1);
}
#endif /* _AIC7XXX_INLINE_H_ */
diff --git a/sys/dev/aic7xxx/aic7xxx_osm.c b/sys/dev/aic7xxx/aic7xxx_osm.c
index 8ce01a6..2cdeb34 100644
--- a/sys/dev/aic7xxx/aic7xxx_osm.c
+++ b/sys/dev/aic7xxx/aic7xxx_osm.c
@@ -284,7 +284,7 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
untimeout(ahc_timeout, (caddr_t)scb, ccb->ccb_h.timeout_ch);
if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
- int op;
+ /*XXX bus_dmasync_op_t*/int op;
if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
op = BUS_DMASYNC_POSTREAD;
@@ -1107,7 +1107,7 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
if (nsegments != 0) {
struct ahc_dma_seg *sg;
bus_dma_segment_t *end_seg;
- int op;
+ /*XXX bus_dmasync_op_t*/int op;
end_seg = dm_segs + nsegments;
diff --git a/sys/dev/aic7xxx/aic7xxx_pci.c b/sys/dev/aic7xxx/aic7xxx_pci.c
index ed1e641..1c6e8e9 100644
--- a/sys/dev/aic7xxx/aic7xxx_pci.c
+++ b/sys/dev/aic7xxx/aic7xxx_pci.c
@@ -39,7 +39,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#57 $
+ * $Id$
*
* $FreeBSD$
*/
@@ -696,8 +696,12 @@ static void aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
static void aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
int *externalcable_present,
int *eeprom_present);
-static void write_brdctl(struct ahc_softc *ahc, uint8_t value);
+static void write_brdctl(struct ahc_softc *ahc, uint8_t value);
static uint8_t read_brdctl(struct ahc_softc *ahc);
+static void ahc_pci_intr(struct ahc_softc *ahc);
+static int ahc_pci_chip_init(struct ahc_softc *ahc);
+static int ahc_pci_suspend(struct ahc_softc *ahc);
+static int ahc_pci_resume(struct ahc_softc *ahc);
static int
ahc_9005_subdevinfo_valid(uint16_t device, uint16_t vendor,
@@ -748,10 +752,7 @@ ahc_find_pci_device(ahc_dev_softc_t pci)
device = ahc_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2);
subvendor = ahc_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2);
subdevice = ahc_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2);
- full_id = ahc_compose_id(device,
- vendor,
- subdevice,
- subvendor);
+ full_id = ahc_compose_id(device, vendor, subdevice, subvendor);
/*
* If the second function is not hooked up, ignore it.
@@ -833,18 +834,10 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4);
/* Ensure busmastering is enabled */
- command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1);
+ command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2);
command |= PCIM_CMD_BUSMASTEREN;
- /*
- * Disable PCI parity error reporting. Users typically
- * do this to work around broken PCI chipsets that get
- * the parity timing wrong and thus generate lots of spurious
- * errors.
- */
- if ((ahc->flags & AHC_DISABLE_PCI_PERR) != 0)
- command &= ~PCIM_CMD_PERRESPEN;
- ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/1);
+ ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/2);
/* On all PCI adapters, we allow SCB paging */
ahc->flags |= AHC_PAGESCBS;
@@ -853,7 +846,23 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
if (error != 0)
return (error);
+ /*
+ * Disable PCI parity error checking. Users typically
+ * do this to work around broken PCI chipsets that get
+ * the parity timing wrong and thus generate lots of spurious
+ * errors. The chip only allows us to disable *all* parity
+ * error reporting when doing this, so CIO bus, scb ram, and
+ * scratch ram parity errors will be ignored too.
+ */
+ if ((ahc->flags & AHC_DISABLE_PCI_PERR) != 0) {
+ ahc->pause |= FAILDIS;
+ ahc->unpause |= FAILDIS;
+ }
+
ahc->bus_intr = ahc_pci_intr;
+ ahc->bus_chip_init = ahc_pci_chip_init;
+ ahc->bus_suspend = ahc_pci_suspend;
+ ahc->bus_resume = ahc_pci_resume;
/* Remeber how the card was setup in case there is no SEEPROM */
if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) {
@@ -993,6 +1002,35 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
if ((sxfrctl1 & STPWEN) != 0)
ahc->flags |= AHC_TERM_ENB_A;
+ /*
+ * Save chip register configuration data for chip resets
+ * that occur during runtime and resume events.
+ */
+ ahc->bus_softc.pci_softc.devconfig =
+ ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4);
+ ahc->bus_softc.pci_softc.command =
+ ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1);
+ ahc->bus_softc.pci_softc.csize_lattime =
+ ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1);
+ ahc->bus_softc.pci_softc.dscommand0 = ahc_inb(ahc, DSCOMMAND0);
+ ahc->bus_softc.pci_softc.dspcistatus = ahc_inb(ahc, DSPCISTATUS);
+ if ((ahc->features & AHC_DT) != 0) {
+ u_int sfunct;
+
+ sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
+ ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
+ ahc->bus_softc.pci_softc.optionmode = ahc_inb(ahc, OPTIONMODE);
+ ahc->bus_softc.pci_softc.targcrccnt = ahc_inw(ahc, TARGCRCCNT);
+ ahc_outb(ahc, SFUNCT, sfunct);
+ ahc->bus_softc.pci_softc.crccontrol1 =
+ ahc_inb(ahc, CRCCONTROL1);
+ }
+ if ((ahc->features & AHC_MULTI_FUNC) != 0)
+ ahc->bus_softc.pci_softc.scbbaddr = ahc_inb(ahc, SCBBADDR);
+
+ if ((ahc->features & AHC_ULTRA2) != 0)
+ ahc->bus_softc.pci_softc.dff_thrsh = ahc_inb(ahc, DFF_THRSH);
+
/* Core initialization */
error = ahc_init(ahc);
if (error != 0)
@@ -1412,6 +1450,7 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
}
if (have_autoterm) {
+ ahc->flags |= AHC_HAS_TERM_LOGIC;
ahc_acquire_seeprom(ahc, &sd);
configure_termination(ahc, &sd, sc->adapter_control, sxfrctl1);
ahc_release_seeprom(&sd);
@@ -1845,11 +1884,14 @@ aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
spiocap |= EXT_BRDCTL;
ahc_outb(ahc, SPIOCAP, spiocap);
ahc_outb(ahc, BRDCTL, BRDRW|BRDCS);
+ ahc_flush_device_writes(ahc);
+ ahc_delay(500);
ahc_outb(ahc, BRDCTL, 0);
+ ahc_flush_device_writes(ahc);
+ ahc_delay(500);
brdctl = ahc_inb(ahc, BRDCTL);
*internal50_present = (brdctl & BRDDAT5) ? 0 : 1;
*externalcable_present = (brdctl & BRDDAT6) ? 0 : 1;
-
*eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0;
}
@@ -1943,7 +1985,7 @@ read_brdctl(ahc)
return (value);
}
-void
+static void
ahc_pci_intr(struct ahc_softc *ahc)
{
u_int error;
@@ -1961,6 +2003,7 @@ ahc_pci_intr(struct ahc_softc *ahc)
ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
if (status1 & DPE) {
+ ahc->pci_target_perr_count++;
printf("%s: Data Parity Error Detected during address "
"or write data phase\n", ahc_name(ahc));
}
@@ -1992,10 +2035,90 @@ ahc_pci_intr(struct ahc_softc *ahc)
ahc_outb(ahc, CLRINT, CLRPARERR);
}
+ if (ahc->pci_target_perr_count > AHC_PCI_TARGET_PERR_THRESH) {
+ printf(
+"%s: WARNING WARNING WARNING WARNING\n"
+"%s: Too many PCI parity errors observed as a target.\n"
+"%s: Some device on this bus is generating bad parity.\n"
+"%s: This is an error *observed by*, not *generated by*, this controller.\n"
+"%s: PCI parity error checking has been disabled.\n"
+"%s: WARNING WARNING WARNING WARNING\n",
+ ahc_name(ahc), ahc_name(ahc), ahc_name(ahc),
+ ahc_name(ahc), ahc_name(ahc), ahc_name(ahc));
+ ahc->pause |= FAILDIS;
+ ahc->unpause |= FAILDIS;
+ }
ahc_unpause(ahc);
}
static int
+ahc_pci_chip_init(struct ahc_softc *ahc)
+{
+ ahc_outb(ahc, DSCOMMAND0, ahc->bus_softc.pci_softc.dscommand0);
+ ahc_outb(ahc, DSPCISTATUS, ahc->bus_softc.pci_softc.dspcistatus);
+ if ((ahc->features & AHC_DT) != 0) {
+ u_int sfunct;
+
+ sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
+ ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
+ ahc_outb(ahc, OPTIONMODE, ahc->bus_softc.pci_softc.optionmode);
+ ahc_outw(ahc, TARGCRCCNT, ahc->bus_softc.pci_softc.targcrccnt);
+ ahc_outb(ahc, SFUNCT, sfunct);
+ ahc_outb(ahc, CRCCONTROL1,
+ ahc->bus_softc.pci_softc.crccontrol1);
+ }
+ if ((ahc->features & AHC_MULTI_FUNC) != 0)
+ ahc_outb(ahc, SCBBADDR, ahc->bus_softc.pci_softc.scbbaddr);
+
+ if ((ahc->features & AHC_ULTRA2) != 0)
+ ahc_outb(ahc, DFF_THRSH, ahc->bus_softc.pci_softc.dff_thrsh);
+
+ return (ahc_chip_init(ahc));
+}
+
+static int
+ahc_pci_suspend(struct ahc_softc *ahc)
+{
+ return (ahc_suspend(ahc));
+}
+
+static int
+ahc_pci_resume(struct ahc_softc *ahc)
+{
+
+ ahc_power_state_change(ahc, AHC_POWER_STATE_D0);
+
+ /*
+ * We assume that the OS has restored our register
+ * mappings, etc. Just update the config space registers
+ * that the OS doesn't know about and rely on our chip
+ * reset handler to handle the rest.
+ */
+ ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4,
+ ahc->bus_softc.pci_softc.devconfig);
+ ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1,
+ ahc->bus_softc.pci_softc.command);
+ ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1,
+ ahc->bus_softc.pci_softc.csize_lattime);
+ if ((ahc->flags & AHC_HAS_TERM_LOGIC) != 0) {
+ struct seeprom_descriptor sd;
+ u_int sxfrctl1;
+
+ sd.sd_ahc = ahc;
+ sd.sd_control_offset = SEECTL;
+ sd.sd_status_offset = SEECTL;
+ sd.sd_dataout_offset = SEECTL;
+
+ ahc_acquire_seeprom(ahc, &sd);
+ configure_termination(ahc, &sd,
+ ahc->seep_config->adapter_control,
+ &sxfrctl1);
+ ahc_release_seeprom(&sd);
+ }
+ return (ahc_resume(ahc));
+}
+
+static int
ahc_aic785X_setup(struct ahc_softc *ahc)
{
ahc_dev_softc_t pci;
@@ -2009,6 +2132,7 @@ ahc_aic785X_setup(struct ahc_softc *ahc)
rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
if (rev >= 1)
ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
+ ahc->instruction_ram_size = 512;
return (0);
}
@@ -2026,6 +2150,7 @@ ahc_aic7860_setup(struct ahc_softc *ahc)
rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
if (rev >= 1)
ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
+ ahc->instruction_ram_size = 512;
return (0);
}
@@ -2049,6 +2174,7 @@ ahc_aic7870_setup(struct ahc_softc *ahc)
ahc->chip = AHC_AIC7870;
ahc->features = AHC_AIC7870_FE;
ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
+ ahc->instruction_ram_size = 512;
return (0);
}
@@ -2102,6 +2228,7 @@ ahc_aic7880_setup(struct ahc_softc *ahc)
} else {
ahc->bugs |= AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
}
+ ahc->instruction_ram_size = 512;
return (0);
}
@@ -2149,6 +2276,7 @@ ahc_aic7890_setup(struct ahc_softc *ahc)
rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
if (rev == 0)
ahc->bugs |= AHC_AUTOFLUSH_BUG|AHC_CACHETHEN_BUG;
+ ahc->instruction_ram_size = 768;
return (0);
}
@@ -2161,6 +2289,7 @@ ahc_aic7892_setup(struct ahc_softc *ahc)
ahc->features = AHC_AIC7892_FE;
ahc->flags |= AHC_NEWEEPROM_FMT;
ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
+ ahc->instruction_ram_size = 1024;
return (0);
}
@@ -2216,6 +2345,7 @@ ahc_aic7895_setup(struct ahc_softc *ahc)
ahc_pci_write_config(pci, DEVCONFIG, devconfig, /*bytes*/1);
#endif
ahc->flags |= AHC_NEWEEPROM_FMT;
+ ahc->instruction_ram_size = 512;
return (0);
}
@@ -2230,6 +2360,7 @@ ahc_aic7896_setup(struct ahc_softc *ahc)
ahc->features = AHC_AIC7896_FE;
ahc->flags |= AHC_NEWEEPROM_FMT;
ahc->bugs |= AHC_CACHETHEN_DIS_BUG;
+ ahc->instruction_ram_size = 768;
return (0);
}
@@ -2244,6 +2375,7 @@ ahc_aic7899_setup(struct ahc_softc *ahc)
ahc->features = AHC_AIC7899_FE;
ahc->flags |= AHC_NEWEEPROM_FMT;
ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
+ ahc->instruction_ram_size = 1024;
return (0);
}
OpenPOWER on IntegriCloud