diff options
Diffstat (limited to 'sys/dev/aic7xxx')
-rw-r--r-- | sys/dev/aic7xxx/aic7770.c | 39 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx.c | 716 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx.h | 94 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx.reg | 4 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_inline.h | 65 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_osm.c | 4 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_pci.c | 168 |
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); } |