diff options
Diffstat (limited to 'sys/dev/aic7xxx/aic7xxx.c')
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx.c | 323 |
1 files changed, 231 insertions, 92 deletions
diff --git a/sys/dev/aic7xxx/aic7xxx.c b/sys/dev/aic7xxx/aic7xxx.c index 8b6c634..654c4f9 100644 --- a/sys/dev/aic7xxx/aic7xxx.c +++ b/sys/dev/aic7xxx/aic7xxx.c @@ -2,6 +2,7 @@ * Core routines and tables shareable across OS platforms. * * Copyright (c) 1994-2001 Justin T. Gibbs. + * Copyright (c) 2000-2001 Adaptec Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -10,32 +11,46 @@ * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the - * GNU Public License ("GPL"). + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/src/aic7xxx/aic7xxx.c#43 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#59 $ * * $FreeBSD$ */ -#include <dev/aic7xxx/aic7xxx_freebsd.h> +#ifdef __linux__ +#include "aic7xxx_osm.h" +#include "aic7xxx_inline.h" +#include "aicasm/aicasm_insformat.h" +#else +#include <dev/aic7xxx/aic7xxx_osm.h> #include <dev/aic7xxx/aic7xxx_inline.h> #include <dev/aic7xxx/aicasm/aicasm_insformat.h> +#endif /****************************** Softc Data ************************************/ struct ahc_softc_tailq ahc_tailq = TAILQ_HEAD_INITIALIZER(ahc_tailq); @@ -129,6 +144,7 @@ static struct ahc_syncrate ahc_syncrates[] = #include "aic7xxx_seq.h" /**************************** Function Declarations ***************************/ +static void ahc_force_renegotiation(struct ahc_softc *ahc); static struct ahc_tmode_tstate* ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel); @@ -203,9 +219,6 @@ static u_int ahc_rem_scb_from_disc_list(struct ahc_softc *ahc, static void ahc_add_curscb_to_free_list(struct ahc_softc *ahc); static u_int ahc_rem_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev); -static int ahc_abort_scbs(struct ahc_softc *ahc, int target, - char channel, int lun, u_int tag, - role_t role, uint32_t status); static void ahc_reset_current_bus(struct ahc_softc *ahc); #ifdef AHC_DUMP_SEQ static void ahc_dumpseq(struct ahc_softc *ahc); @@ -237,9 +250,15 @@ ahc_restart(struct ahc_softc *ahc) ahc_pause(ahc); + /* No more pending messages. */ + ahc_clear_msg_state(ahc); + ahc_outb(ahc, SCSISIGO, 0); /* De-assert BSY */ ahc_outb(ahc, MSG_OUT, MSG_NOOP); /* No message to send */ ahc_outb(ahc, SXFRCTL1, ahc_inb(ahc, SXFRCTL1) & ~BITBUCKET); + ahc_outb(ahc, LASTPHASE, P_BUSFREE); + ahc_outb(ahc, SAVED_SCSIID, 0xFF); + ahc_outb(ahc, SAVED_LUN, 0xFF); /* * Ensure that the sequencer's idea of TQINPOS @@ -319,7 +338,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc) * Save off the residual * if there is one. */ - ahc_update_residual(scb); + ahc_update_residual(ahc, scb); ahc_done(ahc, scb); } } @@ -480,7 +499,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) /* * Save off the residual if there is one. */ - ahc_update_residual(scb); + ahc_update_residual(ahc, scb); #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOWSENSE) { ahc_print_path(ahc, scb); @@ -705,19 +724,20 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) MSG_TYPE_INITIATOR_MSGIN; ahc->msgin_index = 0; } - } else { + } +#if AHC_TARGET_MODE + else { if (bus_phase == P_MESGOUT) { ahc->msg_type = MSG_TYPE_TARGET_MSGOUT; ahc->msgin_index = 0; } -#if AHC_TARGET_MODE else ahc_setup_target_msgin(ahc, &devinfo, scb); -#endif } +#endif } ahc_handle_message_phase(ahc); @@ -801,7 +821,12 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) * target does a command complete. */ ahc_freeze_devq(ahc, scb); - ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); + if ((scb->flags & SCB_SENSE) == 0) { + ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); + } else { + scb->flags &= ~SCB_SENSE; + ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); + } ahc_freeze_scb(scb); if ((ahc->features & AHC_ULTRA2) != 0) { @@ -1063,10 +1088,16 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) else ahc_outb(ahc, MSG_OUT, mesg_out); } + /* + * Force a renegotiation with this target just in + * case we are out of sync for some external reason + * unknown (or unreported) by the target. + */ + ahc_force_renegotiation(ahc); ahc_outb(ahc, CLRINT, CLRSCSIINT); ahc_unpause(ahc); } else if ((status & SELTO) != 0) { - u_int scbptr; + u_int scbptr; /* Stop the selection */ ahc_outb(ahc, SCSISEQ, 0); @@ -1102,6 +1133,16 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) ahc_freeze_devq(ahc, scb); } ahc_outb(ahc, CLRINT, CLRSCSIINT); + /* + * Force a renegotiation with this target just in + * case the cable was pulled and will later be + * re-attached. The target may forget its negotiation + * settings with us should it attempt to reselect + * during the interruption. The target will not issue + * a unit attention in this case, so we must always + * renegotiate. + */ + ahc_force_renegotiation(ahc); ahc_restart(ahc); } else if ((status & BUSFREE) != 0 && (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) { @@ -1167,7 +1208,6 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) printerror = 0; } else if (ahc_sent_msg(ahc, AHCMSG_1B, MSG_BUS_DEV_RESET, TRUE)) { - struct ahc_devinfo devinfo; #ifdef __FreeBSD__ /* * Don't mark the user's request for this BDR @@ -1267,7 +1307,6 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); } - ahc_clear_msg_state(ahc); ahc_outb(ahc, CLRINT, CLRSCSIINT); ahc_restart(ahc); } else { @@ -1277,6 +1316,27 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) } } +/* + * Force renegotiation to occur the next time we initiate + * a command to the current device. + */ +static void +ahc_force_renegotiation(struct ahc_softc *ahc) +{ + 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, + &tstate); + ahc_update_neg_request(ahc, &devinfo, tstate, + targ_info, /*force*/TRUE); +} + #define AHC_MAX_STEPS 2000 void ahc_clear_critical_section(struct ahc_softc *ahc) @@ -1343,9 +1403,8 @@ ahc_clear_critical_section(struct ahc_softc *ahc) stepping = TRUE; } ahc_outb(ahc, HCNTRL, ahc->unpause); - do { + while (!ahc_is_paused(ahc)) ahc_delay(200); - } while (!ahc_is_paused(ahc)); } if (stepping) { ahc_outb(ahc, SIMODE0, simode0); @@ -1364,11 +1423,18 @@ ahc_clear_intstat(struct ahc_softc *ahc) ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI |CLRBUSFREE|CLRSCSIPERR|CLRPHASECHG| CLRREQINIT); + ahc_flush_device_writes(ahc); ahc_outb(ahc, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO); + ahc_flush_device_writes(ahc); ahc_outb(ahc, CLRINT, CLRSCSIINT); + ahc_flush_device_writes(ahc); } /**************************** Debugging Routines ******************************/ +#ifdef AHC_DEBUG +int ahc_debug = AHC_DEBUG; +#endif + void ahc_print_scb(struct scb *scb) { @@ -1437,7 +1503,7 @@ ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel) memcpy(tstate, master_tstate, sizeof(*tstate)); memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns)); tstate->ultraenb = 0; - for (i = 0; i < 16; i++) { + for (i = 0; i < AHC_NUM_TARGETS; i++) { memset(&tstate->transinfo[i].curr, 0, sizeof(tstate->transinfo[i].curr)); memset(&tstate->transinfo[i].goal, 0, @@ -1486,7 +1552,8 @@ ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force) struct ahc_syncrate * ahc_devlimited_syncrate(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo, - u_int *period, u_int *ppr_options, role_t role) { + u_int *period, u_int *ppr_options, role_t role) +{ struct ahc_transinfo *transinfo; u_int maxsync; @@ -2284,7 +2351,7 @@ ahc_construct_sdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, } /* - * Build a wide negotiateion message in our message + * Build a wide negotiation message in our message * buffer based on the input parameters. */ static void @@ -2346,6 +2413,8 @@ ahc_clear_msg_state(struct ahc_softc *ahc) ahc_outb(ahc, CLRSINT1, CLRATNO); } ahc_outb(ahc, MSG_OUT, MSG_NOOP); + ahc_outb(ahc, SEQ_FLAGS2, + ahc_inb(ahc, SEQ_FLAGS2) & ~TARGET_MSG_PENDING); } /* @@ -2537,7 +2606,7 @@ reswitch: /* * Read the latched byte, but turn off SPIOEN first - * so that we don't inadvertantly cause a REQ for the + * so that we don't inadvertently cause a REQ for the * next byte. */ ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) & ~SPIOEN); @@ -2982,6 +3051,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) } break; } +#ifdef AHC_TARGET_MODE case MSG_BUS_DEV_RESET: ahc_handle_devreset(ahc, devinfo, CAM_BDR_SENT, @@ -2993,18 +3063,20 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) case MSG_ABORT_TAG: case MSG_ABORT: case MSG_CLEAR_QUEUE: -#ifdef AHC_TARGET_MODE + { + int tag; + /* Target mode messages */ if (devinfo->role != ROLE_TARGET) { reject = TRUE; break; } + tag = SCB_LIST_NULL; + if (ahc->msgin_buf[0] == MSG_ABORT_TAG) + tag = ahc_inb(ahc, INITIATOR_TAG); ahc_abort_scbs(ahc, devinfo->target, devinfo->channel, - devinfo->lun, - ahc->msgin_buf[0] == MSG_ABORT_TAG - ? SCB_LIST_NULL - : ahc_inb(ahc, INITIATOR_TAG), - ROLE_TARGET, CAM_REQ_ABORTED); + devinfo->lun, tag, ROLE_TARGET, + CAM_REQ_ABORTED); tstate = ahc->enabled_targets[devinfo->our_scsiid]; if (tstate != NULL) { @@ -3015,12 +3087,14 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) ahc_queue_lstate_event(ahc, lstate, devinfo->our_scsiid, ahc->msgin_buf[0], - /*arg*/0); + /*arg*/tag); ahc_send_lstate_events(ahc, lstate); } } - done = MSGLOOP_MSGCOMPLETE; + ahc_restart(ahc); + done = MSGLOOP_TERMINATED; break; + } #endif case MSG_TERM_IO_PROC: default: @@ -3475,7 +3549,7 @@ ahc_alloc(void *platform_arg, char *name) ahc->bugs = AHC_BUGNONE; ahc->flags = AHC_FNONE; - for (i = 0; i < 16; i++) + for (i = 0; i < AHC_NUM_TARGETS; i++) TAILQ_INIT(&ahc->untagged_queues[i]); if (ahc_platform_alloc(ahc, platform_arg) != 0) { ahc_free(ahc); @@ -3562,6 +3636,22 @@ ahc_softc_insert(struct ahc_softc *ahc) ahc->init_level++; } +/* + * Verify that the passed in softc pointer is for a + * controller that is still configured. + */ +struct ahc_softc * +ahc_find_softc(struct ahc_softc *ahc) +{ + struct ahc_softc *list_ahc; + + TAILQ_FOREACH(list_ahc, &ahc_tailq, links) { + if (list_ahc == ahc) + return (ahc); + } + return (NULL); +} + void ahc_set_unit(struct ahc_softc *ahc, int unit) { @@ -3662,7 +3752,7 @@ ahc_shutdown(void *arg) ahc_outb(ahc, SXFRCTL0, 0); ahc_outb(ahc, DSPCISTATUS, 0); - for (i = TARG_SCSIRATE; i < HA_274_BIOSCTRL; i++) + for (i = TARG_SCSIRATE; i < SCSICONF; i++) ahc_outb(ahc, i, 0); } @@ -3701,7 +3791,10 @@ ahc_reset(struct ahc_softc *ahc) ahc_outb(ahc, HCNTRL, CHIPRST | ahc->pause); /* - * Ensure that the reset has finished + * Ensure that the reset has finished. We delay 1000us + * prior to reading the register to make sure the chip + * has sufficiently completed its reset to handle register + * accesses. */ wait = 1000; do { @@ -3815,10 +3908,6 @@ ahc_build_free_scb_list(struct ahc_softc *ahc) /* Make sure that the last SCB terminates the free list */ ahc_outb(ahc, SCBPTR, i-1); ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL); - - /* Ensure we clear the 0 SCB's control byte. */ - ahc_outb(ahc, SCBPTR, 0); - ahc_outb(ahc, SCB_CONTROL, 0); } static int @@ -3832,11 +3921,11 @@ ahc_init_scbdata(struct ahc_softc *ahc) /* Allocate SCB resources */ scb_data->scbarray = - (struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX, + (struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX_ALLOC, M_DEVBUF, M_NOWAIT); if (scb_data->scbarray == NULL) return (ENOMEM); - memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX); + memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX_ALLOC); /* Determine the number of hardware SCBs and initialize them */ @@ -3871,7 +3960,7 @@ ahc_init_scbdata(struct ahc_softc *ahc) /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, - AHC_SCB_MAX * sizeof(struct hardware_scb), + AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb), /*nsegments*/1, /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, /*flags*/0, &scb_data->hscb_dmat) != 0) { @@ -3892,7 +3981,7 @@ ahc_init_scbdata(struct ahc_softc *ahc) /* And permanently map them */ ahc_dmamap_load(ahc, scb_data->hscb_dmat, scb_data->hscb_dmamap, scb_data->hscbs, - AHC_SCB_MAX * sizeof(struct hardware_scb), + AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb), ahc_dmamap_cb, &scb_data->hscb_busaddr, /*flags*/0); scb_data->init_level++; @@ -3903,7 +3992,7 @@ ahc_init_scbdata(struct ahc_softc *ahc) /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, - AHC_SCB_MAX * sizeof(struct scsi_sense_data), + AHC_SCB_MAX_ALLOC * sizeof(struct scsi_sense_data), /*nsegments*/1, /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, /*flags*/0, &scb_data->sense_dmat) != 0) { @@ -3924,7 +4013,7 @@ ahc_init_scbdata(struct ahc_softc *ahc) /* And permanently map them */ ahc_dmamap_load(ahc, scb_data->sense_dmat, scb_data->sense_dmamap, scb_data->sense, - AHC_SCB_MAX * sizeof(struct scsi_sense_data), + AHC_SCB_MAX_ALLOC * sizeof(struct scsi_sense_data), ahc_dmamap_cb, &scb_data->sense_busaddr, /*flags*/0); scb_data->init_level++; @@ -3944,7 +4033,8 @@ ahc_init_scbdata(struct ahc_softc *ahc) scb_data->init_level++; /* Perform initial CCB allocation */ - memset(scb_data->hscbs, 0, AHC_SCB_MAX * sizeof(struct hardware_scb)); + memset(scb_data->hscbs, 0, + AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb)); ahc_alloc_scbs(ahc); if (scb_data->numscbs == 0) { @@ -4036,7 +4126,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc) int i; scb_data = ahc->scb_data; - if (scb_data->numscbs >= AHC_SCB_MAX) + if (scb_data->numscbs >= AHC_SCB_MAX_ALLOC) /* Can't allocate any more */ return; @@ -4065,7 +4155,8 @@ ahc_alloc_scbs(struct ahc_softc *ahc) physaddr = sg_map->sg_physaddr; newcount = (PAGE_SIZE / (AHC_NSEG * sizeof(struct ahc_dma_seg))); - for (i = 0; scb_data->numscbs < AHC_SCB_MAX && i < newcount; i++) { + newcount = MIN(newcount, (AHC_SCB_MAX_ALLOC - scb_data->numscbs)); + for (i = 0; i < newcount; i++) { struct scb_platform_data *pdata; #ifndef __linux__ int error; @@ -4137,7 +4228,7 @@ ahc_controller_info(struct ahc_softc *ahc, char *buf) if ((ahc->flags & AHC_PAGESCBS) != 0) sprintf(buf, "%d/%d SCBs", - ahc->scb_data->maxhscbs, AHC_SCB_MAX); + ahc->scb_data->maxhscbs, AHC_MAX_QUEUE); else sprintf(buf, "%d SCBs", ahc->scb_data->maxhscbs); } @@ -4180,6 +4271,12 @@ ahc_init(struct ahc_softc *ahc) } } printf ("\n"); + /* + * Reading uninitialized scratch ram may + * generate parity errors. + */ + ahc_outb(ahc, CLRINT, CLRPARERR); + ahc_outb(ahc, CLRINT, CLRBRKADRINT); #endif max_targ = 15; @@ -4303,7 +4400,7 @@ 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) { + if (ahc->scb_data->maxhscbs < AHC_SCB_MAX_ALLOC) { ahc->flags |= AHC_PAGESCBS; } else { ahc->flags &= ~AHC_PAGESCBS; @@ -4371,7 +4468,7 @@ ahc_init(struct ahc_softc *ahc) tagenable = ALL_TARGETS_MASK; /* Grab the disconnection disable table and invert it for our needs */ - if (ahc->flags & AHC_USEDEFAULTS) { + if ((ahc->flags & AHC_USEDEFAULTS) != 0) { printf("%s: Host Adapter Bios disabled. Using default SCSI " "device parameters\n", ahc_name(ahc)); ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B| @@ -5014,7 +5111,8 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, uint8_t qinstart; uint8_t qinpos; uint8_t qintail; - uint8_t next, prev; + uint8_t next; + uint8_t prev; uint8_t curscbptr; int found; int maxtarget; @@ -5029,7 +5127,6 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, } else qinstart = ahc_inb(ahc, QINPOS); qinpos = qinstart; - next = ahc_inb(ahc, NEXT_QUEUED_SCB); found = 0; prev_scb = NULL; @@ -5079,9 +5176,9 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, ahc_done(ahc, scb); /* FALLTHROUGH */ + } case SEARCH_REMOVE: break; - } case SEARCH_COUNT: ahc_qinfifo_requeue(ahc, prev_scb, scb); prev_scb = scb; @@ -5507,24 +5604,40 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, maxlun = lun + 1; } - for (;i < maxtarget; i++) { - for (j = minlun;j < maxlun; j++) - ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, j)); - } + if (role != ROLE_TARGET) { + for (;i < maxtarget; i++) { + for (j = minlun;j < maxlun; j++) { + u_int scbid; + u_int tcl; - /* - * Go through the disconnected list and remove any entries we - * have queued for completion, 0'ing their control byte too. - * We save the active SCB and restore it ourselves, so there - * is no reason for this search to restore it too. - */ - ahc_search_disc_list(ahc, target, channel, lun, tag, - /*stop_on_first*/FALSE, /*remove*/TRUE, - /*save_state*/FALSE); + tcl = BUILD_TCL(i << 4, j); + scbid = ahc_index_busy_tcl(ahc, tcl); + scbp = ahc_lookup_scb(ahc, scbid); + if (scbp == NULL + || ahc_match_scb(ahc, scbp, target, channel, + lun, tag, role) == 0) + continue; + ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, j)); + } + } + + /* + * Go through the disconnected list and remove any entries we + * have queued for completion, 0'ing their control byte too. + * We save the active SCB and restore it ourselves, so there + * is no reason for this search to restore it too. + */ + ahc_search_disc_list(ahc, target, channel, lun, tag, + /*stop_on_first*/FALSE, /*remove*/TRUE, + /*save_state*/FALSE); + } /* * Go through the hardware SCB array looking for commands that - * were active but not on any list. + * were active but not on any list. In some cases, these remnants + * might not still have mappings in the scbindex array (e.g. unexpected + * bus free with the same scb queued for an abort). Don't hold this + * against them. */ for (i = 0; i < ahc->scb_data->maxhscbs; i++) { u_int scbid; @@ -5532,8 +5645,9 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, ahc_outb(ahc, SCBPTR, i); scbid = ahc_inb(ahc, SCB_TAG); scbp = ahc_lookup_scb(ahc, scbid); - if (scbp != NULL - && ahc_match_scb(ahc, scbp, target, channel, lun, tag, role)) + if ((scbp == NULL && scbid != SCB_LIST_NULL) + || (scbp != NULL + && ahc_match_scb(ahc, scbp, target, channel, lun, tag, role))) ahc_add_curscb_to_free_list(ahc); } @@ -5575,6 +5689,7 @@ ahc_reset_current_bus(struct ahc_softc *ahc) ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENSCSIRST); scsiseq = ahc_inb(ahc, SCSISEQ); ahc_outb(ahc, SCSISEQ, scsiseq | SCSIRSTO); + ahc_flush_device_writes(ahc); ahc_delay(AHC_BUSRESET_DELAY); /* Turn off the bus reset */ ahc_outb(ahc, SCSISEQ, scsiseq & ~SCSIRSTO); @@ -5616,6 +5731,16 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) */ ahc_run_qoutfifo(ahc); #if AHC_TARGET_MODE + /* + * XXX - In Twin mode, the tqinfifo may have commands + * for an unaffected channel in it. However, if + * we have run out of ATIO resources to drain that + * queue, we may not get them all out here. Further, + * the blocked transactions for the reset channel + * should just be killed off, irrespecitve of whether + * we are blocked on ATIO resources. Write a routine + * to compact the tqinfifo appropriately. + */ if ((ahc->flags & AHC_TARGETROLE) != 0) { ahc_run_tqinfifo(ahc, /*paused*/TRUE); } @@ -5637,10 +5762,6 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) */ ahc_outb(ahc, SBLKCTL, sblkctl ^ SELBUSB); simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST); - ahc_outb(ahc, SIMODE1, simode1); - if (initiate_reset) - ahc_reset_current_bus(ahc); - ahc_clear_intstat(ahc); #if AHC_TARGET_MODE /* * Bus resets clear ENSELI, so we cannot @@ -5648,19 +5769,18 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) * if we are in target mode. */ if ((ahc->flags & AHC_TARGETROLE) != 0) - ahc_outb(ahc, SIMODE1, simode1 | ENSCSIRST); + simode1 |= ENSCSIRST; #endif + ahc_outb(ahc, SIMODE1, simode1); + if (initiate_reset) + ahc_reset_current_bus(ahc); + ahc_clear_intstat(ahc); ahc_outb(ahc, SCSISEQ, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP)); ahc_outb(ahc, SBLKCTL, sblkctl); restart_needed = FALSE; } else { /* Case 2: A command from this bus is active or we're idle */ - ahc_clear_msg_state(ahc); simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST); - ahc_outb(ahc, SIMODE1, simode1); - if (initiate_reset) - ahc_reset_current_bus(ahc); - ahc_clear_intstat(ahc); #if AHC_TARGET_MODE /* * Bus resets clear ENSELI, so we cannot @@ -5668,8 +5788,12 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) * if we are in target mode. */ if ((ahc->flags & AHC_TARGETROLE) != 0) - ahc_outb(ahc, SIMODE1, simode1 | ENSCSIRST); + simode1 |= ENSCSIRST; #endif + ahc_outb(ahc, SIMODE1, simode1); + if (initiate_reset) + ahc_reset_current_bus(ahc); + ahc_clear_intstat(ahc); ahc_outb(ahc, SCSISEQ, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP)); restart_needed = TRUE; } @@ -5748,7 +5872,7 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) * Calculate the residual for a just completed SCB. */ void -ahc_calc_residual(struct scb *scb) +ahc_calc_residual(struct ahc_softc *ahc, struct scb *scb) { struct hardware_scb *hscb; struct status_pkt *spkt; @@ -6228,7 +6352,8 @@ ahc_dump_card_state(struct ahc_softc *ahc) printf("ACCUM = 0x%x, SINDEX = 0x%x, DINDEX = 0x%x, ARG_2 = 0x%x\n", ahc_inb(ahc, ACCUM), ahc_inb(ahc, SINDEX), ahc_inb(ahc, DINDEX), ahc_inb(ahc, ARG_2)); - printf("HCNT = 0x%x\n", ahc_inb(ahc, HCNT)); + printf("HCNT = 0x%x SCBPTR = 0x%x\n", ahc_inb(ahc, HCNT), + ahc_inb(ahc, SCBPTR)); printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x\n", ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL)); printf(" DFCNTRL = 0x%x, DFSTATUS = 0x%x\n", @@ -6301,6 +6426,17 @@ ahc_dump_card_state(struct ahc_softc *ahc) } printf("\n"); + printf("Sequencer SCB Info: "); + for (i = 0; i < ahc->scb_data->maxhscbs; i++) { + ahc_outb(ahc, SCBPTR, i); + printf("%d(c 0x%x, s 0x%x, l %d, t 0x%x) ", + i, ahc_inb(ahc, SCB_CONTROL), + ahc_inb(ahc, SCB_SCSIID), + ahc_inb(ahc, SCB_LUN), + ahc_inb(ahc, SCB_TAG)); + } + printf("\n"); + printf("Pending list: "); i = 0; LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) { @@ -6308,7 +6444,8 @@ ahc_dump_card_state(struct ahc_softc *ahc) break; if (scb != LIST_FIRST(&ahc->pending_scbs)) printf(", "); - printf("%d", scb->hscb->tag); + printf("%d(c 0x%x, s 0x%x, l %d)", scb->hscb->tag, + scb->hscb->control, scb->hscb->scsiid, scb->hscb->lun); if ((ahc->flags & AHC_PAGESCBS) == 0) { ahc_outb(ahc, SCBPTR, scb->hscb->tag); printf("(0x%x, 0x%x)", ahc_inb(ahc, SCB_CONTROL), @@ -6836,6 +6973,8 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) /* * Wait for more ATIOs from the peripheral driver for this lun. */ + if (bootverbose) + printf("%s: ATIOs exhausted\n", ahc_name(ahc)); return (1); } else ahc->flags &= ~AHC_TQINFIFO_BLOCKED; |