1139749Simp/*- 297883Sgibbs * Core routines and tables shareable across OS platforms. 397883Sgibbs * 4133122Sgibbs * Copyright (c) 1994-2002, 2004 Justin T. Gibbs. 5109588Sgibbs * Copyright (c) 2000-2003 Adaptec Inc. 697883Sgibbs * All rights reserved. 797883Sgibbs * 897883Sgibbs * Redistribution and use in source and binary forms, with or without 997883Sgibbs * modification, are permitted provided that the following conditions 1097883Sgibbs * are met: 1197883Sgibbs * 1. Redistributions of source code must retain the above copyright 1297883Sgibbs * notice, this list of conditions, and the following disclaimer, 1397883Sgibbs * without modification. 1497883Sgibbs * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1597883Sgibbs * substantially similar to the "NO WARRANTY" disclaimer below 1697883Sgibbs * ("Disclaimer") and any redistribution must be conditioned upon 1797883Sgibbs * including a substantially similar Disclaimer requirement for further 1897883Sgibbs * binary redistribution. 1997883Sgibbs * 3. Neither the names of the above-listed copyright holders nor the names 2097883Sgibbs * of any contributors may be used to endorse or promote products derived 2197883Sgibbs * from this software without specific prior written permission. 2297883Sgibbs * 2397883Sgibbs * Alternatively, this software may be distributed under the terms of the 2497883Sgibbs * GNU General Public License ("GPL") version 2 as published by the Free 2597883Sgibbs * Software Foundation. 2697883Sgibbs * 2797883Sgibbs * NO WARRANTY 2897883Sgibbs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2997883Sgibbs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3097883Sgibbs * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 3197883Sgibbs * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3297883Sgibbs * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3397883Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3497883Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3597883Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3697883Sgibbs * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 3797883Sgibbs * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3897883Sgibbs * POSSIBILITY OF SUCH DAMAGES. 3997883Sgibbs * 40129134Sgibbs * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#246 $ 4197883Sgibbs */ 4297883Sgibbs 4397883Sgibbs#ifdef __linux__ 4497883Sgibbs#include "aic79xx_osm.h" 4597883Sgibbs#include "aic79xx_inline.h" 4697883Sgibbs#include "aicasm/aicasm_insformat.h" 4797883Sgibbs#else 48123579Sgibbs#include <sys/cdefs.h> 49123579Sgibbs__FBSDID("$FreeBSD$"); 5097883Sgibbs#include <dev/aic7xxx/aic79xx_osm.h> 5197883Sgibbs#include <dev/aic7xxx/aic79xx_inline.h> 5297883Sgibbs#include <dev/aic7xxx/aicasm/aicasm_insformat.h> 5397883Sgibbs#endif 5497883Sgibbs 55102679Sgibbs/******************************** Globals *************************************/ 5697883Sgibbsstruct ahd_softc_tailq ahd_tailq = TAILQ_HEAD_INITIALIZER(ahd_tailq); 57125448Sgibbsuint32_t ahd_attach_to_HostRAID_controllers = 1; 5897883Sgibbs 5997883Sgibbs/***************************** Lookup Tables **********************************/ 6097883Sgibbschar *ahd_chip_names[] = 6197883Sgibbs{ 6297883Sgibbs "NONE", 6397883Sgibbs "aic7901", 64102679Sgibbs "aic7902", 65102679Sgibbs "aic7901A" 6697883Sgibbs}; 6797883Sgibbs 6897883Sgibbs/* 6997883Sgibbs * Hardware error codes. 7097883Sgibbs */ 7197883Sgibbsstruct ahd_hard_error_entry { 7297883Sgibbs uint8_t errno; 7397883Sgibbs char *errmesg; 7497883Sgibbs}; 7597883Sgibbs 7697883Sgibbsstatic struct ahd_hard_error_entry ahd_hard_errors[] = { 7797883Sgibbs { DSCTMOUT, "Discard Timer has timed out" }, 7897883Sgibbs { ILLOPCODE, "Illegal Opcode in sequencer program" }, 7997883Sgibbs { SQPARERR, "Sequencer Parity Error" }, 8097883Sgibbs { DPARERR, "Data-path Parity Error" }, 8197883Sgibbs { MPARERR, "Scratch or SCB Memory Parity Error" }, 8297883Sgibbs { CIOPARERR, "CIOBUS Parity Error" }, 8397883Sgibbs}; 8497883Sgibbsstatic const u_int num_errors = NUM_ELEMENTS(ahd_hard_errors); 8597883Sgibbs 8697883Sgibbsstatic struct ahd_phase_table_entry ahd_phase_table[] = 8797883Sgibbs{ 8897883Sgibbs { P_DATAOUT, MSG_NOOP, "in Data-out phase" }, 8997883Sgibbs { P_DATAIN, MSG_INITIATOR_DET_ERR, "in Data-in phase" }, 9097883Sgibbs { P_DATAOUT_DT, MSG_NOOP, "in DT Data-out phase" }, 9197883Sgibbs { P_DATAIN_DT, MSG_INITIATOR_DET_ERR, "in DT Data-in phase" }, 9297883Sgibbs { P_COMMAND, MSG_NOOP, "in Command phase" }, 9397883Sgibbs { P_MESGOUT, MSG_NOOP, "in Message-out phase" }, 9497883Sgibbs { P_STATUS, MSG_INITIATOR_DET_ERR, "in Status phase" }, 9597883Sgibbs { P_MESGIN, MSG_PARITY_ERROR, "in Message-in phase" }, 9697883Sgibbs { P_BUSFREE, MSG_NOOP, "while idle" }, 9797883Sgibbs { 0, MSG_NOOP, "in unknown phase" } 9897883Sgibbs}; 9997883Sgibbs 10097883Sgibbs/* 10197883Sgibbs * In most cases we only wish to itterate over real phases, so 10297883Sgibbs * exclude the last element from the count. 10397883Sgibbs */ 10497883Sgibbsstatic const u_int num_phases = NUM_ELEMENTS(ahd_phase_table) - 1; 10597883Sgibbs 10697883Sgibbs/* Our Sequencer Program */ 10797883Sgibbs#include "aic79xx_seq.h" 10897883Sgibbs 10997883Sgibbs/**************************** Function Declarations ***************************/ 11097883Sgibbsstatic void ahd_handle_transmission_error(struct ahd_softc *ahd); 11197883Sgibbsstatic void ahd_handle_lqiphase_error(struct ahd_softc *ahd, 11297883Sgibbs u_int lqistat1); 11397883Sgibbsstatic int ahd_handle_pkt_busfree(struct ahd_softc *ahd, 11497883Sgibbs u_int busfreetime); 11597883Sgibbsstatic int ahd_handle_nonpkt_busfree(struct ahd_softc *ahd); 116102679Sgibbsstatic void ahd_handle_proto_violation(struct ahd_softc *ahd); 11797883Sgibbsstatic void ahd_force_renegotiation(struct ahd_softc *ahd, 11897883Sgibbs struct ahd_devinfo *devinfo); 11997883Sgibbs 12097883Sgibbsstatic struct ahd_tmode_tstate* 12197883Sgibbs ahd_alloc_tstate(struct ahd_softc *ahd, 12297883Sgibbs u_int scsi_id, char channel); 12397883Sgibbs#ifdef AHD_TARGET_MODE 12497883Sgibbsstatic void ahd_free_tstate(struct ahd_softc *ahd, 12597883Sgibbs u_int scsi_id, char channel, int force); 12697883Sgibbs#endif 12797883Sgibbsstatic void ahd_devlimited_syncrate(struct ahd_softc *ahd, 12897883Sgibbs struct ahd_initiator_tinfo *, 12997883Sgibbs u_int *period, 13097883Sgibbs u_int *ppr_options, 13197883Sgibbs role_t role); 13297883Sgibbsstatic void ahd_update_neg_table(struct ahd_softc *ahd, 13397883Sgibbs struct ahd_devinfo *devinfo, 13497883Sgibbs struct ahd_transinfo *tinfo); 13597883Sgibbsstatic void ahd_update_pending_scbs(struct ahd_softc *ahd); 13697883Sgibbsstatic void ahd_fetch_devinfo(struct ahd_softc *ahd, 13797883Sgibbs struct ahd_devinfo *devinfo); 13897883Sgibbsstatic void ahd_scb_devinfo(struct ahd_softc *ahd, 13997883Sgibbs struct ahd_devinfo *devinfo, 14097883Sgibbs struct scb *scb); 14197883Sgibbsstatic void ahd_setup_initiator_msgout(struct ahd_softc *ahd, 14297883Sgibbs struct ahd_devinfo *devinfo, 14397883Sgibbs struct scb *scb); 14497883Sgibbsstatic void ahd_build_transfer_msg(struct ahd_softc *ahd, 14597883Sgibbs struct ahd_devinfo *devinfo); 14697883Sgibbsstatic void ahd_construct_sdtr(struct ahd_softc *ahd, 14797883Sgibbs struct ahd_devinfo *devinfo, 14897883Sgibbs u_int period, u_int offset); 14997883Sgibbsstatic void ahd_construct_wdtr(struct ahd_softc *ahd, 15097883Sgibbs struct ahd_devinfo *devinfo, 15197883Sgibbs u_int bus_width); 15297883Sgibbsstatic void ahd_construct_ppr(struct ahd_softc *ahd, 15397883Sgibbs struct ahd_devinfo *devinfo, 15497883Sgibbs u_int period, u_int offset, 15597883Sgibbs u_int bus_width, u_int ppr_options); 15697883Sgibbsstatic void ahd_clear_msg_state(struct ahd_softc *ahd); 15797883Sgibbsstatic void ahd_handle_message_phase(struct ahd_softc *ahd); 15897883Sgibbstypedef enum { 15997883Sgibbs AHDMSG_1B, 16097883Sgibbs AHDMSG_2B, 16197883Sgibbs AHDMSG_EXT 16297883Sgibbs} ahd_msgtype; 16397883Sgibbsstatic int ahd_sent_msg(struct ahd_softc *ahd, ahd_msgtype type, 16497883Sgibbs u_int msgval, int full); 16597883Sgibbsstatic int ahd_parse_msg(struct ahd_softc *ahd, 16697883Sgibbs struct ahd_devinfo *devinfo); 16797883Sgibbsstatic int ahd_handle_msg_reject(struct ahd_softc *ahd, 16897883Sgibbs struct ahd_devinfo *devinfo); 16997883Sgibbsstatic void ahd_handle_ign_wide_residue(struct ahd_softc *ahd, 17097883Sgibbs struct ahd_devinfo *devinfo); 17197883Sgibbsstatic void ahd_reinitialize_dataptrs(struct ahd_softc *ahd); 17297883Sgibbsstatic void ahd_handle_devreset(struct ahd_softc *ahd, 17397883Sgibbs struct ahd_devinfo *devinfo, 174109588Sgibbs u_int lun, cam_status status, 175109588Sgibbs char *message, int verbose_level); 176153072Sru#ifdef AHD_TARGET_MODE 17797883Sgibbsstatic void ahd_setup_target_msgin(struct ahd_softc *ahd, 17897883Sgibbs struct ahd_devinfo *devinfo, 17997883Sgibbs struct scb *scb); 18097883Sgibbs#endif 18197883Sgibbs 182106803Sscottlstatic u_int ahd_sglist_size(struct ahd_softc *ahd); 183106803Sscottlstatic u_int ahd_sglist_allocsize(struct ahd_softc *ahd); 18497883Sgibbsstatic bus_dmamap_callback_t 18597883Sgibbs ahd_dmamap_cb; 18697883Sgibbsstatic void ahd_initialize_hscbs(struct ahd_softc *ahd); 18797883Sgibbsstatic int ahd_init_scbdata(struct ahd_softc *ahd); 18897883Sgibbsstatic void ahd_fini_scbdata(struct ahd_softc *ahd); 18997883Sgibbsstatic void ahd_setup_iocell_workaround(struct ahd_softc *ahd); 19097883Sgibbsstatic void ahd_iocell_first_selection(struct ahd_softc *ahd); 191102679Sgibbsstatic void ahd_add_col_list(struct ahd_softc *ahd, 192102679Sgibbs struct scb *scb, u_int col_idx); 193102679Sgibbsstatic void ahd_rem_col_list(struct ahd_softc *ahd, 194102679Sgibbs struct scb *scb); 19597883Sgibbsstatic void ahd_chip_init(struct ahd_softc *ahd); 19697883Sgibbsstatic void ahd_qinfifo_requeue(struct ahd_softc *ahd, 19797883Sgibbs struct scb *prev_scb, 19897883Sgibbs struct scb *scb); 19997883Sgibbsstatic int ahd_qinfifo_count(struct ahd_softc *ahd); 20097883Sgibbsstatic int ahd_search_scb_list(struct ahd_softc *ahd, int target, 20197883Sgibbs char channel, int lun, u_int tag, 20297883Sgibbs role_t role, uint32_t status, 20397883Sgibbs ahd_search_action action, 204133122Sgibbs u_int *list_head, u_int *list_tail, 205133122Sgibbs u_int tid); 20697883Sgibbsstatic void ahd_stitch_tid_list(struct ahd_softc *ahd, 20797883Sgibbs u_int tid_prev, u_int tid_cur, 20897883Sgibbs u_int tid_next); 20997883Sgibbsstatic void ahd_add_scb_to_free_list(struct ahd_softc *ahd, 21097883Sgibbs u_int scbid); 21197883Sgibbsstatic u_int ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid, 21297883Sgibbs u_int prev, u_int next, u_int tid); 21397883Sgibbsstatic void ahd_reset_current_bus(struct ahd_softc *ahd); 21497883Sgibbsstatic ahd_callback_t ahd_reset_poll; 215109588Sgibbsstatic ahd_callback_t ahd_stat_timer; 21697883Sgibbs#ifdef AHD_DUMP_SEQ 21797883Sgibbsstatic void ahd_dumpseq(struct ahd_softc *ahd); 21897883Sgibbs#endif 21997883Sgibbsstatic void ahd_loadseq(struct ahd_softc *ahd); 22097883Sgibbsstatic int ahd_check_patch(struct ahd_softc *ahd, 22197883Sgibbs struct patch **start_patch, 22297883Sgibbs u_int start_instr, u_int *skip_addr); 22397883Sgibbsstatic u_int ahd_resolve_seqaddr(struct ahd_softc *ahd, 22497883Sgibbs u_int address); 22597883Sgibbsstatic void ahd_download_instr(struct ahd_softc *ahd, 22697883Sgibbs u_int instrptr, uint8_t *dconsts); 227107441Sscottlstatic int ahd_probe_stack_size(struct ahd_softc *ahd); 228129134Sgibbsstatic int ahd_other_scb_timeout(struct ahd_softc *ahd, 229123579Sgibbs struct scb *scb, 230123579Sgibbs struct scb *other_scb); 231116940Sgibbsstatic int ahd_scb_active_in_fifo(struct ahd_softc *ahd, 232116940Sgibbs struct scb *scb); 233116940Sgibbsstatic void ahd_run_data_fifo(struct ahd_softc *ahd, 234116940Sgibbs struct scb *scb); 235116940Sgibbs 23697883Sgibbs#ifdef AHD_TARGET_MODE 23797883Sgibbsstatic void ahd_queue_lstate_event(struct ahd_softc *ahd, 23897883Sgibbs struct ahd_tmode_lstate *lstate, 23997883Sgibbs u_int initiator_id, 24097883Sgibbs u_int event_type, 24197883Sgibbs u_int event_arg); 24297883Sgibbsstatic void ahd_update_scsiid(struct ahd_softc *ahd, 24397883Sgibbs u_int targid_mask); 24497883Sgibbsstatic int ahd_handle_target_cmd(struct ahd_softc *ahd, 24597883Sgibbs struct target_cmd *cmd); 24697883Sgibbs#endif 24797883Sgibbs 24897883Sgibbs/******************************** Private Inlines *****************************/ 24997883Sgibbsstatic __inline void ahd_assert_atn(struct ahd_softc *ahd); 25097883Sgibbsstatic __inline int ahd_currently_packetized(struct ahd_softc *ahd); 25197883Sgibbsstatic __inline int ahd_set_active_fifo(struct ahd_softc *ahd); 25297883Sgibbs 25397883Sgibbsstatic __inline void 25497883Sgibbsahd_assert_atn(struct ahd_softc *ahd) 25597883Sgibbs{ 25697883Sgibbs ahd_outb(ahd, SCSISIGO, ATNO); 25797883Sgibbs} 25897883Sgibbs 25997883Sgibbs/* 26097883Sgibbs * Determine if the current connection has a packetized 26197883Sgibbs * agreement. This does not necessarily mean that we 26297883Sgibbs * are currently in a packetized transfer. We could 26397883Sgibbs * just as easily be sending or receiving a message. 26497883Sgibbs */ 26597883Sgibbsstatic __inline int 26697883Sgibbsahd_currently_packetized(struct ahd_softc *ahd) 26797883Sgibbs{ 26897883Sgibbs ahd_mode_state saved_modes; 26997883Sgibbs int packetized; 27097883Sgibbs 27197883Sgibbs saved_modes = ahd_save_modes(ahd); 27297883Sgibbs if ((ahd->bugs & AHD_PKTIZED_STATUS_BUG) != 0) { 27397883Sgibbs /* 27497883Sgibbs * The packetized bit refers to the last 27597883Sgibbs * connection, not the current one. Check 27697883Sgibbs * for non-zero LQISTATE instead. 27797883Sgibbs */ 27897883Sgibbs ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 27997883Sgibbs packetized = ahd_inb(ahd, LQISTATE) != 0; 28097883Sgibbs } else { 28197883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 28297883Sgibbs packetized = ahd_inb(ahd, LQISTAT2) & PACKETIZED; 28397883Sgibbs } 28497883Sgibbs ahd_restore_modes(ahd, saved_modes); 28597883Sgibbs return (packetized); 28697883Sgibbs} 28797883Sgibbs 28897883Sgibbsstatic __inline int 28997883Sgibbsahd_set_active_fifo(struct ahd_softc *ahd) 29097883Sgibbs{ 29197883Sgibbs u_int active_fifo; 29297883Sgibbs 29397883Sgibbs AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 29497883Sgibbs active_fifo = ahd_inb(ahd, DFFSTAT) & CURRFIFO; 29597883Sgibbs switch (active_fifo) { 29697883Sgibbs case 0: 29797883Sgibbs case 1: 29897883Sgibbs ahd_set_modes(ahd, active_fifo, active_fifo); 29997883Sgibbs return (1); 30097883Sgibbs default: 30197883Sgibbs return (0); 30297883Sgibbs } 30397883Sgibbs} 30497883Sgibbs 30597883Sgibbs/************************* Sequencer Execution Control ************************/ 30697883Sgibbs/* 30797883Sgibbs * Restart the sequencer program from address zero 30897883Sgibbs */ 30997883Sgibbsvoid 31097883Sgibbsahd_restart(struct ahd_softc *ahd) 31197883Sgibbs{ 31297883Sgibbs 31397883Sgibbs ahd_pause(ahd); 31497883Sgibbs 31597883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 31697883Sgibbs 31797883Sgibbs /* No more pending messages */ 31897883Sgibbs ahd_clear_msg_state(ahd); 31997883Sgibbs ahd_outb(ahd, SCSISIGO, 0); /* De-assert BSY */ 32097883Sgibbs ahd_outb(ahd, MSG_OUT, MSG_NOOP); /* No message to send */ 32197883Sgibbs ahd_outb(ahd, SXFRCTL1, ahd_inb(ahd, SXFRCTL1) & ~BITBUCKET); 32297883Sgibbs ahd_outb(ahd, SEQINTCTL, 0); 32397883Sgibbs ahd_outb(ahd, LASTPHASE, P_BUSFREE); 32497883Sgibbs ahd_outb(ahd, SEQ_FLAGS, 0); 32597883Sgibbs ahd_outb(ahd, SAVED_SCSIID, 0xFF); 32697883Sgibbs ahd_outb(ahd, SAVED_LUN, 0xFF); 32797883Sgibbs 32897883Sgibbs /* 32997883Sgibbs * Ensure that the sequencer's idea of TQINPOS 33097883Sgibbs * matches our own. The sequencer increments TQINPOS 33197883Sgibbs * only after it sees a DMA complete and a reset could 33297883Sgibbs * occur before the increment leaving the kernel to believe 33397883Sgibbs * the command arrived but the sequencer to not. 33497883Sgibbs */ 33597883Sgibbs ahd_outb(ahd, TQINPOS, ahd->tqinfifonext); 33697883Sgibbs 33797883Sgibbs /* Always allow reselection */ 33897883Sgibbs ahd_outb(ahd, SCSISEQ1, 33997883Sgibbs ahd_inb(ahd, SCSISEQ_TEMPLATE) & (ENSELI|ENRSELI|ENAUTOATNP)); 34097883Sgibbs ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); 341129134Sgibbs 342129134Sgibbs /* 343129134Sgibbs * Clear any pending sequencer interrupt. It is no 344129134Sgibbs * longer relevant since we're resetting the Program 345129134Sgibbs * Counter. 346129134Sgibbs */ 347129134Sgibbs ahd_outb(ahd, CLRINT, CLRSEQINT); 348129134Sgibbs 34997883Sgibbs ahd_outb(ahd, SEQCTL0, FASTMODE|SEQRESET); 35097883Sgibbs ahd_unpause(ahd); 35197883Sgibbs} 35297883Sgibbs 35397883Sgibbsvoid 35497883Sgibbsahd_clear_fifo(struct ahd_softc *ahd, u_int fifo) 35597883Sgibbs{ 35697883Sgibbs ahd_mode_state saved_modes; 35797883Sgibbs 35897883Sgibbs#ifdef AHD_DEBUG 35997883Sgibbs if ((ahd_debug & AHD_SHOW_FIFOS) != 0) 36097883Sgibbs printf("%s: Clearing FIFO %d\n", ahd_name(ahd), fifo); 36197883Sgibbs#endif 36297883Sgibbs saved_modes = ahd_save_modes(ahd); 36397883Sgibbs ahd_set_modes(ahd, fifo, fifo); 36497883Sgibbs ahd_outb(ahd, DFFSXFRCTL, RSTCHN|CLRSHCNT); 36597883Sgibbs if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0) 36697883Sgibbs ahd_outb(ahd, CCSGCTL, CCSGRESET); 36797883Sgibbs ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR); 36897883Sgibbs ahd_outb(ahd, SG_STATE, 0); 36997883Sgibbs ahd_restore_modes(ahd, saved_modes); 37097883Sgibbs} 37197883Sgibbs 37297883Sgibbs/************************* Input/Output Queues ********************************/ 373109588Sgibbs/* 374109588Sgibbs * Flush and completed commands that are sitting in the command 375109588Sgibbs * complete queues down on the chip but have yet to be dma'ed back up. 376109588Sgibbs */ 37797883Sgibbsvoid 378109588Sgibbsahd_flush_qoutfifo(struct ahd_softc *ahd) 379109588Sgibbs{ 380109588Sgibbs struct scb *scb; 381109588Sgibbs ahd_mode_state saved_modes; 382109588Sgibbs u_int saved_scbptr; 383109588Sgibbs u_int ccscbctl; 384109588Sgibbs u_int scbid; 385109588Sgibbs u_int next_scbid; 386109588Sgibbs 387109588Sgibbs saved_modes = ahd_save_modes(ahd); 388116940Sgibbs 389116940Sgibbs /* 390123579Sgibbs * Flush the good status FIFO for completed packetized commands. 391116940Sgibbs */ 392116940Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 393109588Sgibbs saved_scbptr = ahd_get_scbptr(ahd); 394116940Sgibbs while ((ahd_inb(ahd, LQISTAT2) & LQIGSAVAIL) != 0) { 395116940Sgibbs u_int fifo_mode; 396116940Sgibbs u_int i; 397116940Sgibbs 398123579Sgibbs scbid = ahd_inw(ahd, GSFIFO); 399116940Sgibbs scb = ahd_lookup_scb(ahd, scbid); 400116940Sgibbs if (scb == NULL) { 401116940Sgibbs printf("%s: Warning - GSFIFO SCB %d invalid\n", 402116940Sgibbs ahd_name(ahd), scbid); 403199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 404116940Sgibbs continue; 405116940Sgibbs } 406116940Sgibbs /* 407116940Sgibbs * Determine if this transaction is still active in 408116940Sgibbs * any FIFO. If it is, we must flush that FIFO to 409116940Sgibbs * the host before completing the command. 410116940Sgibbs */ 411116940Sgibbs fifo_mode = 0; 412123579Sgibbsrescan_fifos: 413116940Sgibbs for (i = 0; i < 2; i++) { 414116940Sgibbs /* Toggle to the other mode. */ 415116940Sgibbs fifo_mode ^= 1; 416116940Sgibbs ahd_set_modes(ahd, fifo_mode, fifo_mode); 417123655Sgibbs 418123655Sgibbs if (ahd_scb_active_in_fifo(ahd, scb) == 0) 419116940Sgibbs continue; 420109588Sgibbs 421116940Sgibbs ahd_run_data_fifo(ahd, scb); 422116940Sgibbs 423116940Sgibbs /* 424123579Sgibbs * Running this FIFO may cause a CFG4DATA for 425123579Sgibbs * this same transaction to assert in the other 426123579Sgibbs * FIFO or a new snapshot SAVEPTRS interrupt 427123579Sgibbs * in this FIFO. Even running a FIFO may not 428123579Sgibbs * clear the transaction if we are still waiting 429123579Sgibbs * for data to drain to the host. We must loop 430123579Sgibbs * until the transaction is not active in either 431123579Sgibbs * FIFO just to be sure. Reset our loop counter 432123579Sgibbs * so we will visit both FIFOs again before 433123655Sgibbs * declaring this transaction finished. We 434123655Sgibbs * also delay a bit so that status has a chance 435123655Sgibbs * to change before we look at this FIFO again. 436116940Sgibbs */ 437123655Sgibbs aic_delay(200); 438123579Sgibbs goto rescan_fifos; 439116940Sgibbs } 440116940Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 441116940Sgibbs ahd_set_scbptr(ahd, scbid); 442116940Sgibbs if ((ahd_inb_scbram(ahd, SCB_SGPTR) & SG_LIST_NULL) == 0 443116940Sgibbs && ((ahd_inb_scbram(ahd, SCB_SGPTR) & SG_FULL_RESID) != 0 444116940Sgibbs || (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR) 445116940Sgibbs & SG_LIST_NULL) != 0)) { 446116940Sgibbs u_int comp_head; 447116940Sgibbs 448116940Sgibbs /* 449116940Sgibbs * The transfer completed with a residual. 450116940Sgibbs * Place this SCB on the complete DMA list 451123579Sgibbs * so that we update our in-core copy of the 452116940Sgibbs * SCB before completing the command. 453116940Sgibbs */ 454116940Sgibbs ahd_outb(ahd, SCB_SCSI_STATUS, 0); 455116940Sgibbs ahd_outb(ahd, SCB_SGPTR, 456116940Sgibbs ahd_inb_scbram(ahd, SCB_SGPTR) 457116940Sgibbs | SG_STATUS_VALID); 458125448Sgibbs ahd_outw(ahd, SCB_TAG, scbid); 459125448Sgibbs ahd_outw(ahd, SCB_NEXT_COMPLETE, SCB_LIST_NULL); 460116940Sgibbs comp_head = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD); 461125448Sgibbs if (SCBID_IS_NULL(comp_head)) { 462125448Sgibbs ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, scbid); 463125448Sgibbs ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, scbid); 464125448Sgibbs } else { 465125448Sgibbs u_int tail; 466125448Sgibbs 467125448Sgibbs tail = ahd_inw(ahd, COMPLETE_DMA_SCB_TAIL); 468125448Sgibbs ahd_set_scbptr(ahd, tail); 469125448Sgibbs ahd_outw(ahd, SCB_NEXT_COMPLETE, scbid); 470125448Sgibbs ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, scbid); 471125448Sgibbs ahd_set_scbptr(ahd, scbid); 472125448Sgibbs } 473116940Sgibbs } else 474116940Sgibbs ahd_complete_scb(ahd, scb); 475116940Sgibbs } 476116940Sgibbs ahd_set_scbptr(ahd, saved_scbptr); 477116940Sgibbs 478109588Sgibbs /* 479116940Sgibbs * Setup for command channel portion of flush. 480116940Sgibbs */ 481116940Sgibbs ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); 482116940Sgibbs 483116940Sgibbs /* 484109588Sgibbs * Wait for any inprogress DMA to complete and clear DMA state 485109588Sgibbs * if this if for an SCB in the qinfifo. 486109588Sgibbs */ 487116767Sgibbs while (((ccscbctl = ahd_inb(ahd, CCSCBCTL)) & (CCARREN|CCSCBEN)) != 0) { 488109588Sgibbs 489109588Sgibbs if ((ccscbctl & (CCSCBDIR|CCARREN)) == (CCSCBDIR|CCARREN)) { 490109588Sgibbs if ((ccscbctl & ARRDONE) != 0) 491109588Sgibbs break; 492109588Sgibbs } else if ((ccscbctl & CCSCBDONE) != 0) 493109588Sgibbs break; 494123579Sgibbs aic_delay(200); 495109588Sgibbs } 496123579Sgibbs /* 497123579Sgibbs * We leave the sequencer to cleanup in the case of DMA's to 498123579Sgibbs * update the qoutfifo. In all other cases (DMA's to the 499123579Sgibbs * chip or a push of an SCB from the COMPLETE_DMA_SCB list), 500123579Sgibbs * we disable the DMA engine so that the sequencer will not 501123579Sgibbs * attempt to handle the DMA completion. 502123579Sgibbs */ 503123579Sgibbs if ((ccscbctl & CCSCBDIR) != 0 || (ccscbctl & ARRDONE) != 0) 504109588Sgibbs ahd_outb(ahd, CCSCBCTL, ccscbctl & ~(CCARREN|CCSCBEN)); 505109588Sgibbs 506123579Sgibbs /* 507123579Sgibbs * Complete any SCBs that just finished 508123579Sgibbs * being DMA'ed into the qoutfifo. 509123579Sgibbs */ 510123579Sgibbs ahd_run_qoutfifo(ahd); 511123579Sgibbs 512116940Sgibbs saved_scbptr = ahd_get_scbptr(ahd); 513109588Sgibbs /* 514109588Sgibbs * Manually update/complete any completed SCBs that are waiting to be 515109588Sgibbs * DMA'ed back up to the host. 516109588Sgibbs */ 517109588Sgibbs scbid = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD); 518109588Sgibbs while (!SCBID_IS_NULL(scbid)) { 519109588Sgibbs uint8_t *hscb_ptr; 520109588Sgibbs u_int i; 521109588Sgibbs 522109588Sgibbs ahd_set_scbptr(ahd, scbid); 523111954Sgibbs next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); 524109588Sgibbs scb = ahd_lookup_scb(ahd, scbid); 525109588Sgibbs if (scb == NULL) { 526109588Sgibbs printf("%s: Warning - DMA-up and complete " 527109588Sgibbs "SCB %d invalid\n", ahd_name(ahd), scbid); 528199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 529109588Sgibbs continue; 530109588Sgibbs } 531109588Sgibbs hscb_ptr = (uint8_t *)scb->hscb; 532109588Sgibbs for (i = 0; i < sizeof(struct hardware_scb); i++) 533111954Sgibbs *hscb_ptr++ = ahd_inb_scbram(ahd, SCB_BASE + i); 534109588Sgibbs 535109588Sgibbs ahd_complete_scb(ahd, scb); 536109588Sgibbs scbid = next_scbid; 537109588Sgibbs } 538109588Sgibbs ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, SCB_LIST_NULL); 539125448Sgibbs ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, SCB_LIST_NULL); 540109588Sgibbs 541125448Sgibbs scbid = ahd_inw(ahd, COMPLETE_ON_QFREEZE_HEAD); 542125448Sgibbs while (!SCBID_IS_NULL(scbid)) { 543125448Sgibbs 544125448Sgibbs ahd_set_scbptr(ahd, scbid); 545125448Sgibbs next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); 546125448Sgibbs scb = ahd_lookup_scb(ahd, scbid); 547125448Sgibbs if (scb == NULL) { 548125448Sgibbs printf("%s: Warning - Complete Qfrz SCB %d invalid\n", 549125448Sgibbs ahd_name(ahd), scbid); 550199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 551125448Sgibbs continue; 552125448Sgibbs } 553125448Sgibbs 554125448Sgibbs ahd_complete_scb(ahd, scb); 555125448Sgibbs scbid = next_scbid; 556125448Sgibbs } 557125448Sgibbs ahd_outw(ahd, COMPLETE_ON_QFREEZE_HEAD, SCB_LIST_NULL); 558125448Sgibbs 559109588Sgibbs scbid = ahd_inw(ahd, COMPLETE_SCB_HEAD); 560109588Sgibbs while (!SCBID_IS_NULL(scbid)) { 561109588Sgibbs 562109588Sgibbs ahd_set_scbptr(ahd, scbid); 563111954Sgibbs next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); 564109588Sgibbs scb = ahd_lookup_scb(ahd, scbid); 565109588Sgibbs if (scb == NULL) { 566109588Sgibbs printf("%s: Warning - Complete SCB %d invalid\n", 567109588Sgibbs ahd_name(ahd), scbid); 568199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 569109588Sgibbs continue; 570109588Sgibbs } 571109588Sgibbs 572109588Sgibbs ahd_complete_scb(ahd, scb); 573109588Sgibbs scbid = next_scbid; 574109588Sgibbs } 575109588Sgibbs ahd_outw(ahd, COMPLETE_SCB_HEAD, SCB_LIST_NULL); 576116940Sgibbs 577116940Sgibbs /* 578116940Sgibbs * Restore state. 579116940Sgibbs */ 580109588Sgibbs ahd_set_scbptr(ahd, saved_scbptr); 581116940Sgibbs ahd_restore_modes(ahd, saved_modes); 582116940Sgibbs ahd->flags |= AHD_UPDATE_PEND_CMDS; 583116940Sgibbs} 584109588Sgibbs 585116940Sgibbs/* 586116940Sgibbs * Determine if an SCB for a packetized transaction 587116940Sgibbs * is active in a FIFO. 588116940Sgibbs */ 589116940Sgibbsstatic int 590116940Sgibbsahd_scb_active_in_fifo(struct ahd_softc *ahd, struct scb *scb) 591116940Sgibbs{ 592116940Sgibbs 593109588Sgibbs /* 594116940Sgibbs * The FIFO is only active for our transaction if 595116940Sgibbs * the SCBPTR matches the SCB's ID and the firmware 596116940Sgibbs * has installed a handler for the FIFO or we have 597116940Sgibbs * a pending SAVEPTRS or CFG4DATA interrupt. 598109588Sgibbs */ 599116940Sgibbs if (ahd_get_scbptr(ahd) != SCB_GET_TAG(scb) 600116940Sgibbs || ((ahd_inb(ahd, LONGJMP_ADDR+1) & INVALID_ADDR) != 0 601116940Sgibbs && (ahd_inb(ahd, SEQINTSRC) & (CFG4DATA|SAVEPTRS)) == 0)) 602116940Sgibbs return (0); 603116940Sgibbs 604116940Sgibbs return (1); 605116940Sgibbs} 606116940Sgibbs 607116940Sgibbs/* 608116940Sgibbs * Run a data fifo to completion for a transaction we know 609116940Sgibbs * has completed across the SCSI bus (good status has been 610116940Sgibbs * received). We are already set to the correct FIFO mode 611116940Sgibbs * on entry to this routine. 612116940Sgibbs * 613116940Sgibbs * This function attempts to operate exactly as the firmware 614116940Sgibbs * would when running this FIFO. Care must be taken to update 615116940Sgibbs * this routine any time the firmware's FIFO algorithm is 616116940Sgibbs * changed. 617116940Sgibbs */ 618116940Sgibbsstatic void 619116940Sgibbsahd_run_data_fifo(struct ahd_softc *ahd, struct scb *scb) 620116940Sgibbs{ 621116940Sgibbs u_int seqintsrc; 622116940Sgibbs 623123579Sgibbs seqintsrc = ahd_inb(ahd, SEQINTSRC); 624123579Sgibbs if ((seqintsrc & CFG4DATA) != 0) { 625123579Sgibbs uint32_t datacnt; 626123579Sgibbs uint32_t sgptr; 627116940Sgibbs 628123579Sgibbs /* 629123579Sgibbs * Clear full residual flag. 630123579Sgibbs */ 631123579Sgibbs sgptr = ahd_inl_scbram(ahd, SCB_SGPTR) & ~SG_FULL_RESID; 632123579Sgibbs ahd_outb(ahd, SCB_SGPTR, sgptr); 633116940Sgibbs 634123579Sgibbs /* 635123579Sgibbs * Load datacnt and address. 636123579Sgibbs */ 637123579Sgibbs datacnt = ahd_inl_scbram(ahd, SCB_DATACNT); 638123579Sgibbs if ((datacnt & AHD_DMA_LAST_SEG) != 0) { 639123579Sgibbs sgptr |= LAST_SEG; 640123579Sgibbs ahd_outb(ahd, SG_STATE, 0); 641123579Sgibbs } else 642123579Sgibbs ahd_outb(ahd, SG_STATE, LOADING_NEEDED); 643123579Sgibbs ahd_outq(ahd, HADDR, ahd_inq_scbram(ahd, SCB_DATAPTR)); 644123579Sgibbs ahd_outl(ahd, HCNT, datacnt & AHD_SG_LEN_MASK); 645123579Sgibbs ahd_outb(ahd, SG_CACHE_PRE, sgptr); 646123579Sgibbs ahd_outb(ahd, DFCNTRL, PRELOADEN|SCSIEN|HDMAEN); 647116940Sgibbs 648123579Sgibbs /* 649123579Sgibbs * Initialize Residual Fields. 650123579Sgibbs */ 651123579Sgibbs ahd_outb(ahd, SCB_RESIDUAL_DATACNT+3, datacnt >> 24); 652123579Sgibbs ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr & SG_PTR_MASK); 653116940Sgibbs 654123579Sgibbs /* 655123579Sgibbs * Mark the SCB as having a FIFO in use. 656123579Sgibbs */ 657123579Sgibbs ahd_outb(ahd, SCB_FIFO_USE_COUNT, 658123579Sgibbs ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) + 1); 659116940Sgibbs 660123579Sgibbs /* 661123579Sgibbs * Install a "fake" handler for this FIFO. 662123579Sgibbs */ 663123579Sgibbs ahd_outw(ahd, LONGJMP_ADDR, 0); 664116940Sgibbs 665123579Sgibbs /* 666123579Sgibbs * Notify the hardware that we have satisfied 667123579Sgibbs * this sequencer interrupt. 668123579Sgibbs */ 669123579Sgibbs ahd_outb(ahd, CLRSEQINTSRC, CLRCFG4DATA); 670123579Sgibbs } else if ((seqintsrc & SAVEPTRS) != 0) { 671123579Sgibbs uint32_t sgptr; 672123579Sgibbs uint32_t resid; 673123579Sgibbs 674123579Sgibbs if ((ahd_inb(ahd, LONGJMP_ADDR+1)&INVALID_ADDR) != 0) { 675116940Sgibbs /* 676123579Sgibbs * Snapshot Save Pointers. All that 677123579Sgibbs * is necessary to clear the snapshot 678123579Sgibbs * is a CLRCHN. 679116940Sgibbs */ 680123579Sgibbs goto clrchn; 681123579Sgibbs } 682116940Sgibbs 683123579Sgibbs /* 684123579Sgibbs * Disable S/G fetch so the DMA engine 685123579Sgibbs * is available to future users. 686123579Sgibbs */ 687123579Sgibbs if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0) 688123579Sgibbs ahd_outb(ahd, CCSGCTL, 0); 689123579Sgibbs ahd_outb(ahd, SG_STATE, 0); 690116940Sgibbs 691123579Sgibbs /* 692123579Sgibbs * Flush the data FIFO. Strickly only 693123579Sgibbs * necessary for Rev A parts. 694123579Sgibbs */ 695123579Sgibbs ahd_outb(ahd, DFCNTRL, ahd_inb(ahd, DFCNTRL) | FIFOFLUSH); 696116940Sgibbs 697123579Sgibbs /* 698123579Sgibbs * Calculate residual. 699123579Sgibbs */ 700123579Sgibbs sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR); 701123579Sgibbs resid = ahd_inl(ahd, SHCNT); 702123579Sgibbs resid |= ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+3) << 24; 703123579Sgibbs ahd_outl(ahd, SCB_RESIDUAL_DATACNT, resid); 704123579Sgibbs if ((ahd_inb(ahd, SG_CACHE_SHADOW) & LAST_SEG) == 0) { 705116940Sgibbs /* 706123579Sgibbs * Must back up to the correct S/G element. 707123579Sgibbs * Typically this just means resetting our 708123579Sgibbs * low byte to the offset in the SG_CACHE, 709123579Sgibbs * but if we wrapped, we have to correct 710123579Sgibbs * the other bytes of the sgptr too. 711116940Sgibbs */ 712123579Sgibbs if ((ahd_inb(ahd, SG_CACHE_SHADOW) & 0x80) != 0 713123579Sgibbs && (sgptr & 0x80) == 0) 714123579Sgibbs sgptr -= 0x100; 715123579Sgibbs sgptr &= ~0xFF; 716123579Sgibbs sgptr |= ahd_inb(ahd, SG_CACHE_SHADOW) 717123579Sgibbs & SG_ADDR_MASK; 718123579Sgibbs ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr); 719123579Sgibbs ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 3, 0); 720123579Sgibbs } else if ((resid & AHD_SG_LEN_MASK) == 0) { 721123579Sgibbs ahd_outb(ahd, SCB_RESIDUAL_SGPTR, 722123579Sgibbs sgptr | SG_LIST_NULL); 723123579Sgibbs } 724123579Sgibbs /* 725123579Sgibbs * Save Pointers. 726123579Sgibbs */ 727123579Sgibbs ahd_outq(ahd, SCB_DATAPTR, ahd_inq(ahd, SHADDR)); 728123579Sgibbs ahd_outl(ahd, SCB_DATACNT, resid); 729123579Sgibbs ahd_outl(ahd, SCB_SGPTR, sgptr); 730123579Sgibbs ahd_outb(ahd, CLRSEQINTSRC, CLRSAVEPTRS); 731123579Sgibbs ahd_outb(ahd, SEQIMODE, 732123579Sgibbs ahd_inb(ahd, SEQIMODE) | ENSAVEPTRS); 733123579Sgibbs /* 734123579Sgibbs * If the data is to the SCSI bus, we are 735123579Sgibbs * done, otherwise wait for FIFOEMP. 736123579Sgibbs */ 737123579Sgibbs if ((ahd_inb(ahd, DFCNTRL) & DIRECTION) != 0) 738123579Sgibbs goto clrchn; 739123579Sgibbs } else if ((ahd_inb(ahd, SG_STATE) & LOADING_NEEDED) != 0) { 740123579Sgibbs uint32_t sgptr; 741123579Sgibbs uint64_t data_addr; 742123579Sgibbs uint32_t data_len; 743123579Sgibbs u_int dfcntrl; 744116940Sgibbs 745123579Sgibbs /* 746123579Sgibbs * Disable S/G fetch so the DMA engine 747123579Sgibbs * is available to future users. We won't 748123579Sgibbs * be using the DMA engine to load segments. 749123579Sgibbs */ 750123579Sgibbs if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0) { 751123579Sgibbs ahd_outb(ahd, CCSGCTL, 0); 752123579Sgibbs ahd_outb(ahd, SG_STATE, LOADING_NEEDED); 753123579Sgibbs } 754116940Sgibbs 755123579Sgibbs /* 756123579Sgibbs * Wait for the DMA engine to notice that the 757123579Sgibbs * host transfer is enabled and that there is 758123579Sgibbs * space in the S/G FIFO for new segments before 759123579Sgibbs * loading more segments. 760123579Sgibbs */ 761123579Sgibbs if ((ahd_inb(ahd, DFSTATUS) & PRELOAD_AVAIL) != 0 762123579Sgibbs && (ahd_inb(ahd, DFCNTRL) & HDMAENACK) != 0) { 763116940Sgibbs 764116940Sgibbs /* 765116940Sgibbs * Determine the offset of the next S/G 766116940Sgibbs * element to load. 767116940Sgibbs */ 768116940Sgibbs sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR); 769116940Sgibbs sgptr &= SG_PTR_MASK; 770116940Sgibbs if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 771116940Sgibbs struct ahd_dma64_seg *sg; 772116940Sgibbs 773116940Sgibbs sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); 774116940Sgibbs data_addr = sg->addr; 775116940Sgibbs data_len = sg->len; 776116940Sgibbs sgptr += sizeof(*sg); 777116940Sgibbs } else { 778116940Sgibbs struct ahd_dma_seg *sg; 779116940Sgibbs 780116940Sgibbs sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); 781116940Sgibbs data_addr = sg->len & AHD_SG_HIGH_ADDR_MASK; 782116940Sgibbs data_addr <<= 8; 783116940Sgibbs data_addr |= sg->addr; 784116940Sgibbs data_len = sg->len; 785116940Sgibbs sgptr += sizeof(*sg); 786116940Sgibbs } 787116940Sgibbs 788116940Sgibbs /* 789116940Sgibbs * Update residual information. 790116940Sgibbs */ 791116940Sgibbs ahd_outb(ahd, SCB_RESIDUAL_DATACNT+3, data_len >> 24); 792116940Sgibbs ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr); 793116940Sgibbs 794116940Sgibbs /* 795116940Sgibbs * Load the S/G. 796116940Sgibbs */ 797116940Sgibbs if (data_len & AHD_DMA_LAST_SEG) { 798116940Sgibbs sgptr |= LAST_SEG; 799116940Sgibbs ahd_outb(ahd, SG_STATE, 0); 800116940Sgibbs } 801116940Sgibbs ahd_outq(ahd, HADDR, data_addr); 802116940Sgibbs ahd_outl(ahd, HCNT, data_len & AHD_SG_LEN_MASK); 803116940Sgibbs ahd_outb(ahd, SG_CACHE_PRE, sgptr & 0xFF); 804116940Sgibbs 805116940Sgibbs /* 806116940Sgibbs * Advertise the segment to the hardware. 807116940Sgibbs */ 808116940Sgibbs dfcntrl = ahd_inb(ahd, DFCNTRL)|PRELOADEN|HDMAEN; 809123579Sgibbs if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0) { 810116940Sgibbs /* 811116940Sgibbs * Use SCSIENWRDIS so that SCSIEN 812116940Sgibbs * is never modified by this 813116940Sgibbs * operation. 814116940Sgibbs */ 815116940Sgibbs dfcntrl |= SCSIENWRDIS; 816116940Sgibbs } 817116940Sgibbs ahd_outb(ahd, DFCNTRL, dfcntrl); 818123579Sgibbs } 819123579Sgibbs } else if ((ahd_inb(ahd, SG_CACHE_SHADOW) & LAST_SEG_DONE) != 0) { 820116940Sgibbs 821123579Sgibbs /* 822123579Sgibbs * Transfer completed to the end of SG list 823123579Sgibbs * and has flushed to the host. 824123579Sgibbs */ 825123579Sgibbs ahd_outb(ahd, SCB_SGPTR, 826123579Sgibbs ahd_inb_scbram(ahd, SCB_SGPTR) | SG_LIST_NULL); 827123579Sgibbs goto clrchn; 828123579Sgibbs } else if ((ahd_inb(ahd, DFSTATUS) & FIFOEMP) != 0) { 829123579Sgibbsclrchn: 830123579Sgibbs /* 831123579Sgibbs * Clear any handler for this FIFO, decrement 832123579Sgibbs * the FIFO use count for the SCB, and release 833123579Sgibbs * the FIFO. 834123579Sgibbs */ 835123579Sgibbs ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR); 836123579Sgibbs ahd_outb(ahd, SCB_FIFO_USE_COUNT, 837123579Sgibbs ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) - 1); 838123579Sgibbs ahd_outb(ahd, DFFSXFRCTL, CLRCHN); 839109588Sgibbs } 840109588Sgibbs} 841109588Sgibbs 842125448Sgibbs/* 843125448Sgibbs * Look for entries in the QoutFIFO that have completed. 844125448Sgibbs * The valid_tag completion field indicates the validity 845125448Sgibbs * of the entry - the valid value toggles each time through 846125448Sgibbs * the queue. We use the sg_status field in the completion 847125448Sgibbs * entry to avoid referencing the hscb if the completion 848125448Sgibbs * occurred with no errors and no residual. sg_status is 849125448Sgibbs * a copy of the first byte (little endian) of the sgptr 850125448Sgibbs * hscb field. 851125448Sgibbs */ 852109588Sgibbsvoid 85397883Sgibbsahd_run_qoutfifo(struct ahd_softc *ahd) 85497883Sgibbs{ 855125448Sgibbs struct ahd_completion *completion; 85697883Sgibbs struct scb *scb; 85797883Sgibbs u_int scb_index; 85897883Sgibbs 859109588Sgibbs if ((ahd->flags & AHD_RUNNING_QOUTFIFO) != 0) 860109588Sgibbs panic("ahd_run_qoutfifo recursion"); 861109588Sgibbs ahd->flags |= AHD_RUNNING_QOUTFIFO; 86297883Sgibbs ahd_sync_qoutfifo(ahd, BUS_DMASYNC_POSTREAD); 863125448Sgibbs for (;;) { 864125448Sgibbs completion = &ahd->qoutfifo[ahd->qoutfifonext]; 86597883Sgibbs 866125448Sgibbs if (completion->valid_tag != ahd->qoutfifonext_valid_tag) 867125448Sgibbs break; 868125448Sgibbs 869125448Sgibbs scb_index = aic_le16toh(completion->tag); 87097883Sgibbs scb = ahd_lookup_scb(ahd, scb_index); 87197883Sgibbs if (scb == NULL) { 87297883Sgibbs printf("%s: WARNING no command for scb %d " 87397883Sgibbs "(cmdcmplt)\nQOUTPOS = %d\n", 87497883Sgibbs ahd_name(ahd), scb_index, 87597883Sgibbs ahd->qoutfifonext); 876199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 87797883Sgibbs ahd_dump_card_state(ahd); 878125448Sgibbs } else if ((completion->sg_status & SG_STATUS_VALID) != 0) { 879125448Sgibbs ahd_handle_scb_status(ahd, scb); 880125448Sgibbs } else { 881125448Sgibbs ahd_done(ahd, scb); 882125448Sgibbs } 88397883Sgibbs 884102679Sgibbs ahd->qoutfifonext = (ahd->qoutfifonext+1) & (AHD_QOUT_SIZE-1); 885102679Sgibbs if (ahd->qoutfifonext == 0) 886125448Sgibbs ahd->qoutfifonext_valid_tag ^= QOUTFIFO_ENTRY_VALID; 88797883Sgibbs } 888109588Sgibbs ahd->flags &= ~AHD_RUNNING_QOUTFIFO; 88997883Sgibbs} 89097883Sgibbs 89197883Sgibbs/************************* Interrupt Handling *********************************/ 89297883Sgibbsvoid 89397883Sgibbsahd_handle_hwerrint(struct ahd_softc *ahd) 89497883Sgibbs{ 89597883Sgibbs /* 89697883Sgibbs * Some catastrophic hardware error has occurred. 89797883Sgibbs * Print it for the user and disable the controller. 89897883Sgibbs */ 89997883Sgibbs int i; 90097883Sgibbs int error; 90197883Sgibbs 90297883Sgibbs error = ahd_inb(ahd, ERROR); 90397883Sgibbs for (i = 0; i < num_errors; i++) { 904199260Sattilio if ((error & ahd_hard_errors[i].errno) != 0) { 90597883Sgibbs printf("%s: hwerrint, %s\n", 90697883Sgibbs ahd_name(ahd), ahd_hard_errors[i].errmesg); 907199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 908199260Sattilio } 90997883Sgibbs } 91097883Sgibbs 91197883Sgibbs ahd_dump_card_state(ahd); 91297883Sgibbs panic("BRKADRINT"); 91397883Sgibbs 914114623Sgibbs /* Tell everyone that this HBA is no longer available */ 91597883Sgibbs ahd_abort_scbs(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS, 91697883Sgibbs CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_UNKNOWN, 91797883Sgibbs CAM_NO_HBA); 91897883Sgibbs 91997883Sgibbs /* Tell the system that this controller has gone away. */ 92097883Sgibbs ahd_free(ahd); 92197883Sgibbs} 92297883Sgibbs 92397883Sgibbsvoid 92497883Sgibbsahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) 92597883Sgibbs{ 92697883Sgibbs u_int seqintcode; 92797883Sgibbs 92897883Sgibbs /* 92997883Sgibbs * Save the sequencer interrupt code and clear the SEQINT 93097883Sgibbs * bit. We will unpause the sequencer, if appropriate, 93197883Sgibbs * after servicing the request. 93297883Sgibbs */ 93397883Sgibbs seqintcode = ahd_inb(ahd, SEQINTCODE); 93497883Sgibbs ahd_outb(ahd, CLRINT, CLRSEQINT); 935107441Sscottl if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { 936107441Sscottl /* 937107441Sscottl * Unpause the sequencer and let it clear 938107441Sscottl * SEQINT by writing NO_SEQINT to it. This 939107441Sscottl * will cause the sequencer to be paused again, 940107441Sscottl * which is the expected state of this routine. 941107441Sscottl */ 942107441Sscottl ahd_unpause(ahd); 943107441Sscottl while (!ahd_is_paused(ahd)) 944107441Sscottl ; 945107441Sscottl ahd_outb(ahd, CLRINT, CLRSEQINT); 946107441Sscottl } 94797883Sgibbs ahd_update_modes(ahd); 94897883Sgibbs#ifdef AHD_DEBUG 94997883Sgibbs if ((ahd_debug & AHD_SHOW_MISC) != 0) 95097883Sgibbs printf("%s: Handle Seqint Called for code %d\n", 95197883Sgibbs ahd_name(ahd), seqintcode); 95297883Sgibbs#endif 95397883Sgibbs switch (seqintcode) { 95497883Sgibbs case ENTERING_NONPACK: 95597883Sgibbs { 95697883Sgibbs struct scb *scb; 95797883Sgibbs u_int scbid; 95897883Sgibbs 95997883Sgibbs AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 96097883Sgibbs ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 96197883Sgibbs scbid = ahd_get_scbptr(ahd); 96297883Sgibbs scb = ahd_lookup_scb(ahd, scbid); 96397883Sgibbs if (scb == NULL) { 96497883Sgibbs /* 96597883Sgibbs * Somehow need to know if this 96697883Sgibbs * is from a selection or reselection. 967116935Sgibbs * From that, we can determine target 96897883Sgibbs * ID so we at least have an I_T nexus. 96997883Sgibbs */ 97097883Sgibbs } else { 97197883Sgibbs ahd_outb(ahd, SAVED_SCSIID, scb->hscb->scsiid); 97297883Sgibbs ahd_outb(ahd, SAVED_LUN, scb->hscb->lun); 97397883Sgibbs ahd_outb(ahd, SEQ_FLAGS, 0x0); 97497883Sgibbs } 97597883Sgibbs if ((ahd_inb(ahd, LQISTAT2) & LQIPHASE_OUTPKT) != 0 97697883Sgibbs && (ahd_inb(ahd, SCSISIGO) & ATNO) != 0) { 97797883Sgibbs /* 97897883Sgibbs * Phase change after read stream with 97997883Sgibbs * CRC error with P0 asserted on last 98097883Sgibbs * packet. 98197883Sgibbs */ 982107441Sscottl#ifdef AHD_DEBUG 983107441Sscottl if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) 984107441Sscottl printf("%s: Assuming LQIPHASE_NLQ with " 985107441Sscottl "P0 assertion\n", ahd_name(ahd)); 986107441Sscottl#endif 98797883Sgibbs } 988107441Sscottl#ifdef AHD_DEBUG 989107441Sscottl if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) 990107441Sscottl printf("%s: Entering NONPACK\n", ahd_name(ahd)); 991107441Sscottl#endif 99297883Sgibbs break; 99397883Sgibbs } 99497883Sgibbs case INVALID_SEQINT: 99597883Sgibbs printf("%s: Invalid Sequencer interrupt occurred.\n", 99697883Sgibbs ahd_name(ahd)); 99797883Sgibbs ahd_dump_card_state(ahd); 99897883Sgibbs ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 999199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 100097883Sgibbs break; 100197883Sgibbs case STATUS_OVERRUN: 100297883Sgibbs { 1003114623Sgibbs struct scb *scb; 1004114623Sgibbs u_int scbid; 1005114623Sgibbs 1006114623Sgibbs scbid = ahd_get_scbptr(ahd); 1007114623Sgibbs scb = ahd_lookup_scb(ahd, scbid); 1008114623Sgibbs if (scb != NULL) 1009114623Sgibbs ahd_print_path(ahd, scb); 1010114623Sgibbs else 1011114623Sgibbs printf("%s: ", ahd_name(ahd)); 1012114623Sgibbs printf("SCB %d Packetized Status Overrun", scbid); 101397883Sgibbs ahd_dump_card_state(ahd); 101497883Sgibbs ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 1015199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 101697883Sgibbs break; 101797883Sgibbs } 101897883Sgibbs case CFG4ISTAT_INTR: 101997883Sgibbs { 102097883Sgibbs struct scb *scb; 102197883Sgibbs u_int scbid; 102297883Sgibbs 102397883Sgibbs scbid = ahd_get_scbptr(ahd); 102497883Sgibbs scb = ahd_lookup_scb(ahd, scbid); 102597883Sgibbs if (scb == NULL) { 102697883Sgibbs ahd_dump_card_state(ahd); 102797883Sgibbs printf("CFG4ISTAT: Free SCB %d referenced", scbid); 1028199260Sattilio AHD_FATAL_ERROR(ahd); 102997883Sgibbs panic("For safety"); 103097883Sgibbs } 103197883Sgibbs ahd_outq(ahd, HADDR, scb->sense_busaddr); 103297883Sgibbs ahd_outw(ahd, HCNT, AHD_SENSE_BUFSIZE); 103397883Sgibbs ahd_outb(ahd, HCNT + 2, 0); 103497883Sgibbs ahd_outb(ahd, SG_CACHE_PRE, SG_LAST_SEG); 103597883Sgibbs ahd_outb(ahd, DFCNTRL, PRELOADEN|SCSIEN|HDMAEN); 103697883Sgibbs break; 103797883Sgibbs } 103897883Sgibbs case ILLEGAL_PHASE: 103997883Sgibbs { 104097883Sgibbs u_int bus_phase; 104197883Sgibbs 104297883Sgibbs bus_phase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK; 104397883Sgibbs printf("%s: ILLEGAL_PHASE 0x%x\n", 104497883Sgibbs ahd_name(ahd), bus_phase); 104597883Sgibbs 104697883Sgibbs switch (bus_phase) { 104797883Sgibbs case P_DATAOUT: 104897883Sgibbs case P_DATAIN: 104997883Sgibbs case P_DATAOUT_DT: 105097883Sgibbs case P_DATAIN_DT: 105197883Sgibbs case P_MESGOUT: 105297883Sgibbs case P_STATUS: 105397883Sgibbs case P_MESGIN: 105497883Sgibbs ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 105597883Sgibbs printf("%s: Issued Bus Reset.\n", ahd_name(ahd)); 1056199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 105797883Sgibbs break; 105897883Sgibbs case P_COMMAND: 105997883Sgibbs { 106097883Sgibbs struct ahd_devinfo devinfo; 106197883Sgibbs struct scb *scb; 106297883Sgibbs struct ahd_initiator_tinfo *targ_info; 106397883Sgibbs struct ahd_tmode_tstate *tstate; 106497883Sgibbs struct ahd_transinfo *tinfo; 106597883Sgibbs u_int scbid; 106697883Sgibbs 106797883Sgibbs /* 106897883Sgibbs * If a target takes us into the command phase 106997883Sgibbs * assume that it has been externally reset and 107097883Sgibbs * has thus lost our previous packetized negotiation 107197883Sgibbs * agreement. Since we have not sent an identify 107297883Sgibbs * message and may not have fully qualified the 107397883Sgibbs * connection, we change our command to TUR, assert 107497883Sgibbs * ATN and ABORT the task when we go to message in 107597883Sgibbs * phase. The OSM will see the REQUEUE_REQUEST 107697883Sgibbs * status and retry the command. 107797883Sgibbs */ 107897883Sgibbs scbid = ahd_get_scbptr(ahd); 107997883Sgibbs scb = ahd_lookup_scb(ahd, scbid); 108097883Sgibbs if (scb == NULL) { 1081199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 108297883Sgibbs printf("Invalid phase with no valid SCB. " 108397883Sgibbs "Resetting bus.\n"); 108497883Sgibbs ahd_reset_channel(ahd, 'A', 108597883Sgibbs /*Initiate Reset*/TRUE); 108697883Sgibbs break; 108797883Sgibbs } 108897883Sgibbs ahd_compile_devinfo(&devinfo, SCB_GET_OUR_ID(scb), 108997883Sgibbs SCB_GET_TARGET(ahd, scb), 109097883Sgibbs SCB_GET_LUN(scb), 109197883Sgibbs SCB_GET_CHANNEL(ahd, scb), 109297883Sgibbs ROLE_INITIATOR); 109397883Sgibbs targ_info = ahd_fetch_transinfo(ahd, 109497883Sgibbs devinfo.channel, 109597883Sgibbs devinfo.our_scsiid, 109697883Sgibbs devinfo.target, 109797883Sgibbs &tstate); 109897883Sgibbs tinfo = &targ_info->curr; 109997883Sgibbs ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, 1100109588Sgibbs AHD_TRANS_ACTIVE, /*paused*/TRUE); 110197883Sgibbs ahd_set_syncrate(ahd, &devinfo, /*period*/0, 110297883Sgibbs /*offset*/0, /*ppr_options*/0, 110397883Sgibbs AHD_TRANS_ACTIVE, /*paused*/TRUE); 110497883Sgibbs ahd_outb(ahd, SCB_CDB_STORE, 0); 110597883Sgibbs ahd_outb(ahd, SCB_CDB_STORE+1, 0); 110697883Sgibbs ahd_outb(ahd, SCB_CDB_STORE+2, 0); 110797883Sgibbs ahd_outb(ahd, SCB_CDB_STORE+3, 0); 110897883Sgibbs ahd_outb(ahd, SCB_CDB_STORE+4, 0); 110997883Sgibbs ahd_outb(ahd, SCB_CDB_STORE+5, 0); 111097883Sgibbs ahd_outb(ahd, SCB_CDB_LEN, 6); 111197883Sgibbs scb->hscb->control &= ~(TAG_ENB|SCB_TAG_TYPE); 111297883Sgibbs scb->hscb->control |= MK_MESSAGE; 111397883Sgibbs ahd_outb(ahd, SCB_CONTROL, scb->hscb->control); 111497883Sgibbs ahd_outb(ahd, MSG_OUT, HOST_MSG); 111597883Sgibbs ahd_outb(ahd, SAVED_SCSIID, scb->hscb->scsiid); 111697883Sgibbs /* 111797883Sgibbs * The lun is 0, regardless of the SCB's lun 111897883Sgibbs * as we have not sent an identify message. 111997883Sgibbs */ 112097883Sgibbs ahd_outb(ahd, SAVED_LUN, 0); 112197883Sgibbs ahd_outb(ahd, SEQ_FLAGS, 0); 112297883Sgibbs ahd_assert_atn(ahd); 1123123579Sgibbs scb->flags &= ~SCB_PACKETIZED; 112497883Sgibbs scb->flags |= SCB_ABORT|SCB_CMDPHASE_ABORT; 112597883Sgibbs ahd_freeze_devq(ahd, scb); 1126123579Sgibbs aic_set_transaction_status(scb, CAM_REQUEUE_REQ); 1127123579Sgibbs aic_freeze_scb(scb); 112897883Sgibbs 112997883Sgibbs /* 113097883Sgibbs * Allow the sequencer to continue with 113197883Sgibbs * non-pack processing. 113297883Sgibbs */ 113397883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 113497883Sgibbs ahd_outb(ahd, CLRLQOINT1, CLRLQOPHACHGINPKT); 113597883Sgibbs if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) { 113697883Sgibbs ahd_outb(ahd, CLRLQOINT1, 0); 113797883Sgibbs } 1138107441Sscottl#ifdef AHD_DEBUG 1139107441Sscottl if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { 1140107441Sscottl ahd_print_path(ahd, scb); 1141199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 1142107441Sscottl printf("Unexpected command phase from " 1143107441Sscottl "packetized target\n"); 1144107441Sscottl } 1145107441Sscottl#endif 114697883Sgibbs break; 114797883Sgibbs } 114897883Sgibbs } 114997883Sgibbs break; 115097883Sgibbs } 115197883Sgibbs case CFG4OVERRUN: 1152107441Sscottl { 1153107441Sscottl struct scb *scb; 1154107441Sscottl u_int scb_index; 1155107441Sscottl 1156107441Sscottl#ifdef AHD_DEBUG 1157107441Sscottl if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { 1158107441Sscottl printf("%s: CFG4OVERRUN mode = %x\n", ahd_name(ahd), 1159107441Sscottl ahd_inb(ahd, MODE_PTR)); 1160107441Sscottl } 1161107441Sscottl#endif 1162107441Sscottl scb_index = ahd_get_scbptr(ahd); 1163107441Sscottl scb = ahd_lookup_scb(ahd, scb_index); 1164107441Sscottl if (scb == NULL) { 1165107441Sscottl /* 1166107441Sscottl * Attempt to transfer to an SCB that is 1167107441Sscottl * not outstanding. 1168107441Sscottl */ 1169107441Sscottl ahd_assert_atn(ahd); 1170107441Sscottl ahd_outb(ahd, MSG_OUT, HOST_MSG); 1171107441Sscottl ahd->msgout_buf[0] = MSG_ABORT_TASK; 1172107441Sscottl ahd->msgout_len = 1; 1173107441Sscottl ahd->msgout_index = 0; 1174107441Sscottl ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; 1175107441Sscottl /* 1176107441Sscottl * Clear status received flag to prevent any 1177107441Sscottl * attempt to complete this bogus SCB. 1178107441Sscottl */ 1179107441Sscottl ahd_outb(ahd, SCB_CONTROL, 1180116940Sgibbs ahd_inb_scbram(ahd, SCB_CONTROL) 1181116940Sgibbs & ~STATUS_RCVD); 1182107441Sscottl } 118397883Sgibbs break; 1184107441Sscottl } 118597883Sgibbs case DUMP_CARD_STATE: 118697883Sgibbs { 118797883Sgibbs ahd_dump_card_state(ahd); 118897883Sgibbs break; 118997883Sgibbs } 119097883Sgibbs case PDATA_REINIT: 119197883Sgibbs { 1192107441Sscottl#ifdef AHD_DEBUG 1193107441Sscottl if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { 1194107441Sscottl printf("%s: PDATA_REINIT - DFCNTRL = 0x%x " 1195107441Sscottl "SG_CACHE_SHADOW = 0x%x\n", 1196107441Sscottl ahd_name(ahd), ahd_inb(ahd, DFCNTRL), 1197107441Sscottl ahd_inb(ahd, SG_CACHE_SHADOW)); 1198107441Sscottl } 1199107441Sscottl#endif 120097883Sgibbs ahd_reinitialize_dataptrs(ahd); 120197883Sgibbs break; 120297883Sgibbs } 120397883Sgibbs case HOST_MSG_LOOP: 120497883Sgibbs { 120597883Sgibbs struct ahd_devinfo devinfo; 120697883Sgibbs 120797883Sgibbs /* 120897883Sgibbs * The sequencer has encountered a message phase 120997883Sgibbs * that requires host assistance for completion. 121097883Sgibbs * While handling the message phase(s), we will be 121197883Sgibbs * notified by the sequencer after each byte is 121297883Sgibbs * transfered so we can track bus phase changes. 121397883Sgibbs * 121497883Sgibbs * If this is the first time we've seen a HOST_MSG_LOOP 121597883Sgibbs * interrupt, initialize the state of the host message 121697883Sgibbs * loop. 121797883Sgibbs */ 121897883Sgibbs ahd_fetch_devinfo(ahd, &devinfo); 121997883Sgibbs if (ahd->msg_type == MSG_TYPE_NONE) { 122097883Sgibbs struct scb *scb; 122197883Sgibbs u_int scb_index; 122297883Sgibbs u_int bus_phase; 122397883Sgibbs 122497883Sgibbs bus_phase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK; 122597883Sgibbs if (bus_phase != P_MESGIN 122697883Sgibbs && bus_phase != P_MESGOUT) { 122797883Sgibbs printf("ahd_intr: HOST_MSG_LOOP bad " 1228107441Sscottl "phase 0x%x\n", bus_phase); 1229199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 123097883Sgibbs /* 123197883Sgibbs * Probably transitioned to bus free before 123297883Sgibbs * we got here. Just punt the message. 123397883Sgibbs */ 123497883Sgibbs ahd_dump_card_state(ahd); 123597883Sgibbs ahd_clear_intstat(ahd); 123697883Sgibbs ahd_restart(ahd); 123797883Sgibbs return; 123897883Sgibbs } 123997883Sgibbs 124097883Sgibbs scb_index = ahd_get_scbptr(ahd); 124197883Sgibbs scb = ahd_lookup_scb(ahd, scb_index); 124297883Sgibbs if (devinfo.role == ROLE_INITIATOR) { 124397883Sgibbs if (bus_phase == P_MESGOUT) 124497883Sgibbs ahd_setup_initiator_msgout(ahd, 124597883Sgibbs &devinfo, 124697883Sgibbs scb); 124797883Sgibbs else { 124897883Sgibbs ahd->msg_type = 124997883Sgibbs MSG_TYPE_INITIATOR_MSGIN; 125097883Sgibbs ahd->msgin_index = 0; 125197883Sgibbs } 125297883Sgibbs } 1253153072Sru#ifdef AHD_TARGET_MODE 125497883Sgibbs else { 125597883Sgibbs if (bus_phase == P_MESGOUT) { 125697883Sgibbs ahd->msg_type = 125797883Sgibbs MSG_TYPE_TARGET_MSGOUT; 125897883Sgibbs ahd->msgin_index = 0; 125997883Sgibbs } 126097883Sgibbs else 126197883Sgibbs ahd_setup_target_msgin(ahd, 126297883Sgibbs &devinfo, 126397883Sgibbs scb); 126497883Sgibbs } 126597883Sgibbs#endif 126697883Sgibbs } 126797883Sgibbs 126897883Sgibbs ahd_handle_message_phase(ahd); 126997883Sgibbs break; 127097883Sgibbs } 127197883Sgibbs case NO_MATCH: 127297883Sgibbs { 127397883Sgibbs /* Ensure we don't leave the selection hardware on */ 127497883Sgibbs AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 127597883Sgibbs ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO); 127697883Sgibbs 127797883Sgibbs printf("%s:%c:%d: no active SCB for reconnecting " 127897883Sgibbs "target - issuing BUS DEVICE RESET\n", 1279102679Sgibbs ahd_name(ahd), 'A', ahd_inb(ahd, SELID) >> 4); 128097883Sgibbs printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " 1281102679Sgibbs "REG0 == 0x%x ACCUM = 0x%x\n", 128297883Sgibbs ahd_inb(ahd, SAVED_SCSIID), ahd_inb(ahd, SAVED_LUN), 1283102679Sgibbs ahd_inw(ahd, REG0), ahd_inb(ahd, ACCUM)); 128497883Sgibbs printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " 128597883Sgibbs "SINDEX == 0x%x\n", 128697883Sgibbs ahd_inb(ahd, SEQ_FLAGS), ahd_get_scbptr(ahd), 128797883Sgibbs ahd_find_busy_tcl(ahd, 1288102679Sgibbs BUILD_TCL(ahd_inb(ahd, SAVED_SCSIID), 1289102679Sgibbs ahd_inb(ahd, SAVED_LUN))), 1290102679Sgibbs ahd_inw(ahd, SINDEX)); 129197883Sgibbs printf("SELID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " 129297883Sgibbs "SCB_CONTROL == 0x%x\n", 129397883Sgibbs ahd_inb(ahd, SELID), ahd_inb_scbram(ahd, SCB_SCSIID), 129497883Sgibbs ahd_inb_scbram(ahd, SCB_LUN), 129597883Sgibbs ahd_inb_scbram(ahd, SCB_CONTROL)); 129697883Sgibbs printf("SCSIBUS[0] == 0x%x, SCSISIGI == 0x%x\n", 129797883Sgibbs ahd_inb(ahd, SCSIBUS), ahd_inb(ahd, SCSISIGI)); 129897883Sgibbs printf("SXFRCTL0 == 0x%x\n", ahd_inb(ahd, SXFRCTL0)); 129997883Sgibbs printf("SEQCTL0 == 0x%x\n", ahd_inb(ahd, SEQCTL0)); 130097883Sgibbs ahd_dump_card_state(ahd); 130197883Sgibbs ahd->msgout_buf[0] = MSG_BUS_DEV_RESET; 130297883Sgibbs ahd->msgout_len = 1; 130397883Sgibbs ahd->msgout_index = 0; 130497883Sgibbs ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; 130597883Sgibbs ahd_outb(ahd, MSG_OUT, HOST_MSG); 130697883Sgibbs ahd_assert_atn(ahd); 130797883Sgibbs break; 130897883Sgibbs } 130997883Sgibbs case PROTO_VIOLATION: 131097883Sgibbs { 1311102679Sgibbs ahd_handle_proto_violation(ahd); 1312102679Sgibbs break; 131397883Sgibbs } 131497883Sgibbs case IGN_WIDE_RES: 131597883Sgibbs { 131697883Sgibbs struct ahd_devinfo devinfo; 131797883Sgibbs 131897883Sgibbs ahd_fetch_devinfo(ahd, &devinfo); 131997883Sgibbs ahd_handle_ign_wide_residue(ahd, &devinfo); 132097883Sgibbs break; 132197883Sgibbs } 132297883Sgibbs case BAD_PHASE: 132397883Sgibbs { 132497883Sgibbs u_int lastphase; 132597883Sgibbs 132697883Sgibbs lastphase = ahd_inb(ahd, LASTPHASE); 132797883Sgibbs printf("%s:%c:%d: unknown scsi bus phase %x, " 132897883Sgibbs "lastphase = 0x%x. Attempting to continue\n", 132997883Sgibbs ahd_name(ahd), 'A', 133097883Sgibbs SCSIID_TARGET(ahd, ahd_inb(ahd, SAVED_SCSIID)), 133197883Sgibbs lastphase, ahd_inb(ahd, SCSISIGI)); 1332199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 133397883Sgibbs break; 133497883Sgibbs } 133597883Sgibbs case MISSED_BUSFREE: 133697883Sgibbs { 133797883Sgibbs u_int lastphase; 133897883Sgibbs 133997883Sgibbs lastphase = ahd_inb(ahd, LASTPHASE); 134097883Sgibbs printf("%s:%c:%d: Missed busfree. " 134197883Sgibbs "Lastphase = 0x%x, Curphase = 0x%x\n", 134297883Sgibbs ahd_name(ahd), 'A', 134397883Sgibbs SCSIID_TARGET(ahd, ahd_inb(ahd, SAVED_SCSIID)), 134497883Sgibbs lastphase, ahd_inb(ahd, SCSISIGI)); 1345199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 134697883Sgibbs ahd_restart(ahd); 134797883Sgibbs return; 134897883Sgibbs } 134997883Sgibbs case DATA_OVERRUN: 135097883Sgibbs { 135197883Sgibbs /* 135297883Sgibbs * When the sequencer detects an overrun, it 135397883Sgibbs * places the controller in "BITBUCKET" mode 135497883Sgibbs * and allows the target to complete its transfer. 135597883Sgibbs * Unfortunately, none of the counters get updated 135697883Sgibbs * when the controller is in this mode, so we have 135797883Sgibbs * no way of knowing how large the overrun was. 135897883Sgibbs */ 135997883Sgibbs struct scb *scb; 1360107441Sscottl u_int scbindex; 1361107441Sscottl#ifdef AHD_DEBUG 1362107441Sscottl u_int lastphase; 1363107441Sscottl#endif 136497883Sgibbs 1365107441Sscottl scbindex = ahd_get_scbptr(ahd); 136697883Sgibbs scb = ahd_lookup_scb(ahd, scbindex); 1367107441Sscottl#ifdef AHD_DEBUG 1368107441Sscottl lastphase = ahd_inb(ahd, LASTPHASE); 1369107441Sscottl if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { 1370107441Sscottl ahd_print_path(ahd, scb); 1371107441Sscottl printf("data overrun detected %s. Tag == 0x%x.\n", 1372107441Sscottl ahd_lookup_phase_entry(lastphase)->phasemsg, 1373107441Sscottl SCB_GET_TAG(scb)); 1374107441Sscottl ahd_print_path(ahd, scb); 1375107441Sscottl printf("%s seen Data Phase. Length = %ld. " 1376107441Sscottl "NumSGs = %d.\n", 1377107441Sscottl ahd_inb(ahd, SEQ_FLAGS) & DPHASE 1378107441Sscottl ? "Have" : "Haven't", 1379123579Sgibbs aic_get_transfer_length(scb), scb->sg_count); 1380107441Sscottl ahd_dump_sglist(scb); 1381107441Sscottl } 1382107441Sscottl#endif 138397883Sgibbs 138497883Sgibbs /* 138597883Sgibbs * Set this and it will take effect when the 138697883Sgibbs * target does a command complete. 138797883Sgibbs */ 138897883Sgibbs ahd_freeze_devq(ahd, scb); 1389123579Sgibbs aic_set_transaction_status(scb, CAM_DATA_RUN_ERR); 1390123579Sgibbs aic_freeze_scb(scb); 139197883Sgibbs break; 139297883Sgibbs } 139397883Sgibbs case MKMSG_FAILED: 139497883Sgibbs { 139597883Sgibbs struct ahd_devinfo devinfo; 139697883Sgibbs struct scb *scb; 139797883Sgibbs u_int scbid; 139897883Sgibbs 139997883Sgibbs ahd_fetch_devinfo(ahd, &devinfo); 140097883Sgibbs printf("%s:%c:%d:%d: Attempt to issue message failed\n", 140197883Sgibbs ahd_name(ahd), devinfo.channel, devinfo.target, 140297883Sgibbs devinfo.lun); 140397883Sgibbs scbid = ahd_get_scbptr(ahd); 140497883Sgibbs scb = ahd_lookup_scb(ahd, scbid); 1405199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 140697883Sgibbs if (scb != NULL 140797883Sgibbs && (scb->flags & SCB_RECOVERY_SCB) != 0) 140897883Sgibbs /* 140997883Sgibbs * Ensure that we didn't put a second instance of this 141097883Sgibbs * SCB into the QINFIFO. 141197883Sgibbs */ 141297883Sgibbs ahd_search_qinfifo(ahd, SCB_GET_TARGET(ahd, scb), 141397883Sgibbs SCB_GET_CHANNEL(ahd, scb), 141497883Sgibbs SCB_GET_LUN(scb), SCB_GET_TAG(scb), 141597883Sgibbs ROLE_INITIATOR, /*status*/0, 141697883Sgibbs SEARCH_REMOVE); 141797883Sgibbs ahd_outb(ahd, SCB_CONTROL, 1418116940Sgibbs ahd_inb_scbram(ahd, SCB_CONTROL) & ~MK_MESSAGE); 141997883Sgibbs break; 142097883Sgibbs } 1421109588Sgibbs case TASKMGMT_FUNC_COMPLETE: 1422109588Sgibbs { 1423109588Sgibbs u_int scbid; 1424109588Sgibbs struct scb *scb; 1425109588Sgibbs 1426109588Sgibbs scbid = ahd_get_scbptr(ahd); 1427109588Sgibbs scb = ahd_lookup_scb(ahd, scbid); 1428109588Sgibbs if (scb != NULL) { 1429109588Sgibbs u_int lun; 1430109588Sgibbs u_int tag; 1431109588Sgibbs cam_status error; 1432109588Sgibbs 1433109588Sgibbs ahd_print_path(ahd, scb); 1434109588Sgibbs printf("Task Management Func 0x%x Complete\n", 1435109588Sgibbs scb->hscb->task_management); 1436109588Sgibbs lun = CAM_LUN_WILDCARD; 1437109588Sgibbs tag = SCB_LIST_NULL; 1438109588Sgibbs 1439109588Sgibbs switch (scb->hscb->task_management) { 1440109588Sgibbs case SIU_TASKMGMT_ABORT_TASK: 1441114623Sgibbs tag = SCB_GET_TAG(scb); 1442109588Sgibbs case SIU_TASKMGMT_ABORT_TASK_SET: 1443109588Sgibbs case SIU_TASKMGMT_CLEAR_TASK_SET: 1444109588Sgibbs lun = scb->hscb->lun; 1445109588Sgibbs error = CAM_REQ_ABORTED; 1446109588Sgibbs ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), 1447109588Sgibbs 'A', lun, tag, ROLE_INITIATOR, 1448109588Sgibbs error); 1449109588Sgibbs break; 1450109588Sgibbs case SIU_TASKMGMT_LUN_RESET: 1451109588Sgibbs lun = scb->hscb->lun; 1452109588Sgibbs case SIU_TASKMGMT_TARGET_RESET: 1453109588Sgibbs { 1454109588Sgibbs struct ahd_devinfo devinfo; 1455109588Sgibbs 1456109588Sgibbs ahd_scb_devinfo(ahd, &devinfo, scb); 1457109588Sgibbs error = CAM_BDR_SENT; 1458109588Sgibbs ahd_handle_devreset(ahd, &devinfo, lun, 1459109588Sgibbs CAM_BDR_SENT, 1460109588Sgibbs lun != CAM_LUN_WILDCARD 1461109588Sgibbs ? "Lun Reset" 1462109588Sgibbs : "Target Reset", 1463109588Sgibbs /*verbose_level*/0); 1464109588Sgibbs break; 1465109588Sgibbs } 1466109588Sgibbs default: 1467109588Sgibbs panic("Unexpected TaskMgmt Func\n"); 1468109588Sgibbs break; 1469109588Sgibbs } 1470109588Sgibbs } 1471109588Sgibbs break; 1472109588Sgibbs } 1473109588Sgibbs case TASKMGMT_CMD_CMPLT_OKAY: 1474109588Sgibbs { 1475109588Sgibbs u_int scbid; 1476109588Sgibbs struct scb *scb; 1477109588Sgibbs 1478109588Sgibbs /* 1479109588Sgibbs * An ABORT TASK TMF failed to be delivered before 1480109588Sgibbs * the targeted command completed normally. 1481109588Sgibbs */ 1482109588Sgibbs scbid = ahd_get_scbptr(ahd); 1483109588Sgibbs scb = ahd_lookup_scb(ahd, scbid); 1484109588Sgibbs if (scb != NULL) { 1485109588Sgibbs /* 1486109588Sgibbs * Remove the second instance of this SCB from 1487109588Sgibbs * the QINFIFO if it is still there. 1488109588Sgibbs */ 1489109588Sgibbs ahd_print_path(ahd, scb); 1490109588Sgibbs printf("SCB completes before TMF\n"); 1491109588Sgibbs /* 1492109588Sgibbs * Handle losing the race. Wait until any 1493109588Sgibbs * current selection completes. We will then 1494109588Sgibbs * set the TMF back to zero in this SCB so that 1495109588Sgibbs * the sequencer doesn't bother to issue another 1496109588Sgibbs * sequencer interrupt for its completion. 1497109588Sgibbs */ 1498109588Sgibbs while ((ahd_inb(ahd, SCSISEQ0) & ENSELO) != 0 1499109588Sgibbs && (ahd_inb(ahd, SSTAT0) & SELDO) == 0 1500109588Sgibbs && (ahd_inb(ahd, SSTAT1) & SELTO) == 0) 1501109588Sgibbs ; 1502109588Sgibbs ahd_outb(ahd, SCB_TASK_MANAGEMENT, 0); 1503109588Sgibbs ahd_search_qinfifo(ahd, SCB_GET_TARGET(ahd, scb), 1504109588Sgibbs SCB_GET_CHANNEL(ahd, scb), 1505114623Sgibbs SCB_GET_LUN(scb), SCB_GET_TAG(scb), 1506109588Sgibbs ROLE_INITIATOR, /*status*/0, 1507109588Sgibbs SEARCH_REMOVE); 1508109588Sgibbs } 1509109588Sgibbs break; 1510109588Sgibbs } 1511107441Sscottl case TRACEPOINT0: 1512107441Sscottl case TRACEPOINT1: 1513107441Sscottl case TRACEPOINT2: 1514107441Sscottl case TRACEPOINT3: 1515107441Sscottl printf("%s: Tracepoint %d\n", ahd_name(ahd), 1516107441Sscottl seqintcode - TRACEPOINT0); 1517107441Sscottl break; 1518107441Sscottl case NO_SEQINT: 1519107441Sscottl break; 1520107441Sscottl case SAW_HWERR: 1521107441Sscottl ahd_handle_hwerrint(ahd); 1522107441Sscottl break; 1523102679Sgibbs default: 1524102679Sgibbs printf("%s: Unexpected SEQINTCODE %d\n", ahd_name(ahd), 1525102679Sgibbs seqintcode); 1526102679Sgibbs break; 152797883Sgibbs } 152897883Sgibbs /* 152997883Sgibbs * The sequencer is paused immediately on 153097883Sgibbs * a SEQINT, so we should restart it when 153197883Sgibbs * we're done. 153297883Sgibbs */ 153397883Sgibbs ahd_unpause(ahd); 153497883Sgibbs} 153597883Sgibbs 153697883Sgibbsvoid 153797883Sgibbsahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) 153897883Sgibbs{ 153997883Sgibbs struct scb *scb; 154097883Sgibbs u_int status0; 154197883Sgibbs u_int status3; 154297883Sgibbs u_int status; 154397883Sgibbs u_int lqistat1; 154497883Sgibbs u_int lqostat0; 154597883Sgibbs u_int scbid; 1546107441Sscottl u_int busfreetime; 154797883Sgibbs 154897883Sgibbs ahd_update_modes(ahd); 154997883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 155097883Sgibbs 155197883Sgibbs status3 = ahd_inb(ahd, SSTAT3) & (NTRAMPERR|OSRAMPERR); 155297883Sgibbs status0 = ahd_inb(ahd, SSTAT0) & (IOERR|OVERRUN|SELDI|SELDO); 155397883Sgibbs status = ahd_inb(ahd, SSTAT1) & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR); 155497883Sgibbs lqistat1 = ahd_inb(ahd, LQISTAT1); 155597883Sgibbs lqostat0 = ahd_inb(ahd, LQOSTAT0); 1556107441Sscottl busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME; 155797883Sgibbs if ((status0 & (SELDI|SELDO)) != 0) { 155897883Sgibbs u_int simode0; 155997883Sgibbs 156097883Sgibbs ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 156197883Sgibbs simode0 = ahd_inb(ahd, SIMODE0); 1562102679Sgibbs status0 &= simode0 & (IOERR|OVERRUN|SELDI|SELDO); 156397883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 156497883Sgibbs } 156597883Sgibbs scbid = ahd_get_scbptr(ahd); 156697883Sgibbs scb = ahd_lookup_scb(ahd, scbid); 156797883Sgibbs if (scb != NULL 156897883Sgibbs && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) != 0) 156997883Sgibbs scb = NULL; 157097883Sgibbs 157197883Sgibbs if ((status0 & IOERR) != 0) { 1572102679Sgibbs u_int now_lvd; 157397883Sgibbs 157497883Sgibbs now_lvd = ahd_inb(ahd, SBLKCTL) & ENAB40; 157597883Sgibbs printf("%s: Transceiver State Has Changed to %s mode\n", 157697883Sgibbs ahd_name(ahd), now_lvd ? "LVD" : "SE"); 157797883Sgibbs ahd_outb(ahd, CLRSINT0, CLRIOERR); 157897883Sgibbs /* 1579102679Sgibbs * A change in I/O mode is equivalent to a bus reset. 158097883Sgibbs */ 1581114623Sgibbs ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 158297883Sgibbs ahd_pause(ahd); 158397883Sgibbs ahd_setup_iocell_workaround(ahd); 158497883Sgibbs ahd_unpause(ahd); 158597883Sgibbs } else if ((status0 & OVERRUN) != 0) { 1586129134Sgibbs 158797883Sgibbs printf("%s: SCSI offset overrun detected. Resetting bus.\n", 158897883Sgibbs ahd_name(ahd)); 1589199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 159097883Sgibbs ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 159197883Sgibbs } else if ((status & SCSIRSTI) != 0) { 1592129134Sgibbs 159397883Sgibbs printf("%s: Someone reset channel A\n", ahd_name(ahd)); 159497883Sgibbs ahd_reset_channel(ahd, 'A', /*Initiate Reset*/FALSE); 1595199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 159697883Sgibbs } else if ((status & SCSIPERR) != 0) { 1597129134Sgibbs 1598129134Sgibbs /* Make sure the sequencer is in a safe location. */ 1599129134Sgibbs ahd_clear_critical_section(ahd); 1600129134Sgibbs 160197883Sgibbs ahd_handle_transmission_error(ahd); 160297883Sgibbs } else if (lqostat0 != 0) { 1603129134Sgibbs 160497883Sgibbs printf("%s: lqostat0 == 0x%x!\n", ahd_name(ahd), lqostat0); 160597883Sgibbs ahd_outb(ahd, CLRLQOINT0, lqostat0); 1606129134Sgibbs if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) 160797883Sgibbs ahd_outb(ahd, CLRLQOINT1, 0); 160897883Sgibbs } else if ((status & SELTO) != 0) { 1609107441Sscottl u_int scbid; 161097883Sgibbs 161197883Sgibbs /* Stop the selection */ 161297883Sgibbs ahd_outb(ahd, SCSISEQ0, 0); 161397883Sgibbs 1614129134Sgibbs /* Make sure the sequencer is in a safe location. */ 1615129134Sgibbs ahd_clear_critical_section(ahd); 1616129134Sgibbs 161797883Sgibbs /* No more pending messages */ 161897883Sgibbs ahd_clear_msg_state(ahd); 161997883Sgibbs 162097883Sgibbs /* Clear interrupt state */ 162197883Sgibbs ahd_outb(ahd, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR); 162297883Sgibbs 162397883Sgibbs /* 162497883Sgibbs * Although the driver does not care about the 162597883Sgibbs * 'Selection in Progress' status bit, the busy 162697883Sgibbs * LED does. SELINGO is only cleared by a sucessfull 162797883Sgibbs * selection, so we must manually clear it to insure 162897883Sgibbs * the LED turns off just incase no future successful 162997883Sgibbs * selections occur (e.g. no devices on the bus). 163097883Sgibbs */ 163197883Sgibbs ahd_outb(ahd, CLRSINT0, CLRSELINGO); 163297883Sgibbs 163397883Sgibbs scbid = ahd_inw(ahd, WAITING_TID_HEAD); 163497883Sgibbs scb = ahd_lookup_scb(ahd, scbid); 163597883Sgibbs if (scb == NULL) { 163697883Sgibbs printf("%s: ahd_intr - referenced scb not " 163797883Sgibbs "valid during SELTO scb(0x%x)\n", 163897883Sgibbs ahd_name(ahd), scbid); 163997883Sgibbs ahd_dump_card_state(ahd); 1640199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 164197883Sgibbs } else { 1642107441Sscottl struct ahd_devinfo devinfo; 1643104023Sgibbs#ifdef AHD_DEBUG 1644104023Sgibbs if ((ahd_debug & AHD_SHOW_SELTO) != 0) { 1645104023Sgibbs ahd_print_path(ahd, scb); 1646104023Sgibbs printf("Saw Selection Timeout for SCB 0x%x\n", 1647104023Sgibbs scbid); 1648104023Sgibbs } 1649104023Sgibbs#endif 1650107441Sscottl ahd_scb_devinfo(ahd, &devinfo, scb); 1651123579Sgibbs aic_set_transaction_status(scb, CAM_SEL_TIMEOUT); 165297883Sgibbs ahd_freeze_devq(ahd, scb); 1653129134Sgibbs 1654129134Sgibbs /* 1655129134Sgibbs * Cancel any pending transactions on the device 1656129134Sgibbs * now that it seems to be missing. This will 1657129134Sgibbs * also revert us to async/narrow transfers until 1658129134Sgibbs * we can renegotiate with the device. 1659129134Sgibbs */ 1660129134Sgibbs ahd_handle_devreset(ahd, &devinfo, 1661129134Sgibbs CAM_LUN_WILDCARD, 1662129134Sgibbs CAM_SEL_TIMEOUT, 1663129134Sgibbs "Selection Timeout", 1664129134Sgibbs /*verbose_level*/1); 166597883Sgibbs } 166697883Sgibbs ahd_outb(ahd, CLRINT, CLRSCSIINT); 166797883Sgibbs ahd_iocell_first_selection(ahd); 1668109588Sgibbs ahd_unpause(ahd); 166997883Sgibbs } else if ((status0 & (SELDI|SELDO)) != 0) { 1670129134Sgibbs 167197883Sgibbs ahd_iocell_first_selection(ahd); 167297883Sgibbs ahd_unpause(ahd); 167397883Sgibbs } else if (status3 != 0) { 167497883Sgibbs printf("%s: SCSI Cell parity error SSTAT3 == 0x%x\n", 167597883Sgibbs ahd_name(ahd), status3); 1676199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 167797883Sgibbs ahd_outb(ahd, CLRSINT3, status3); 167897883Sgibbs } else if ((lqistat1 & (LQIPHASE_LQ|LQIPHASE_NLQ)) != 0) { 1679129134Sgibbs 1680129134Sgibbs /* Make sure the sequencer is in a safe location. */ 1681129134Sgibbs ahd_clear_critical_section(ahd); 1682129134Sgibbs 168397883Sgibbs ahd_handle_lqiphase_error(ahd, lqistat1); 1684111653Sgibbs } else if ((lqistat1 & LQICRCI_NLQ) != 0) { 1685111653Sgibbs /* 1686111653Sgibbs * This status can be delayed during some 1687111653Sgibbs * streaming operations. The SCSIPHASE 1688111653Sgibbs * handler has already dealt with this case 1689111653Sgibbs * so just clear the error. 1690111653Sgibbs */ 1691111653Sgibbs ahd_outb(ahd, CLRLQIINT1, CLRLQICRCI_NLQ); 1692133122Sgibbs } else if ((status & BUSFREE) != 0 1693133122Sgibbs || (lqistat1 & LQOBUSFREE) != 0) { 169497883Sgibbs u_int lqostat1; 169597883Sgibbs int restart; 169697883Sgibbs int clear_fifo; 169797883Sgibbs int packetized; 169897883Sgibbs u_int mode; 169997883Sgibbs 170097883Sgibbs /* 170197883Sgibbs * Clear our selection hardware as soon as possible. 170297883Sgibbs * We may have an entry in the waiting Q for this target, 170397883Sgibbs * that is affected by this busfree and we don't want to 170497883Sgibbs * go about selecting the target while we handle the event. 170597883Sgibbs */ 170697883Sgibbs ahd_outb(ahd, SCSISEQ0, 0); 170797883Sgibbs 1708129134Sgibbs /* Make sure the sequencer is in a safe location. */ 1709129134Sgibbs ahd_clear_critical_section(ahd); 1710129134Sgibbs 171197883Sgibbs /* 171297883Sgibbs * Determine what we were up to at the time of 171397883Sgibbs * the busfree. 171497883Sgibbs */ 171597883Sgibbs mode = AHD_MODE_SCSI; 171697883Sgibbs busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME; 171797883Sgibbs lqostat1 = ahd_inb(ahd, LQOSTAT1); 171897883Sgibbs switch (busfreetime) { 171997883Sgibbs case BUSFREE_DFF0: 172097883Sgibbs case BUSFREE_DFF1: 172197883Sgibbs { 172297883Sgibbs u_int scbid; 172397883Sgibbs struct scb *scb; 172497883Sgibbs 172597883Sgibbs mode = busfreetime == BUSFREE_DFF0 172697883Sgibbs ? AHD_MODE_DFF0 : AHD_MODE_DFF1; 172797883Sgibbs ahd_set_modes(ahd, mode, mode); 172897883Sgibbs scbid = ahd_get_scbptr(ahd); 172997883Sgibbs scb = ahd_lookup_scb(ahd, scbid); 173097883Sgibbs if (scb == NULL) { 1731114623Sgibbs printf("%s: Invalid SCB %d in DFF%d " 173297883Sgibbs "during unexpected busfree\n", 1733114623Sgibbs ahd_name(ahd), scbid, mode); 173497883Sgibbs packetized = 0; 1735199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 173697883Sgibbs } else 173797883Sgibbs packetized = (scb->flags & SCB_PACKETIZED) != 0; 173897883Sgibbs clear_fifo = 1; 173997883Sgibbs break; 174097883Sgibbs } 174197883Sgibbs case BUSFREE_LQO: 174297883Sgibbs clear_fifo = 0; 174397883Sgibbs packetized = 1; 174497883Sgibbs break; 174597883Sgibbs default: 174697883Sgibbs clear_fifo = 0; 174797883Sgibbs packetized = (lqostat1 & LQOBUSFREE) != 0; 174897883Sgibbs if (!packetized 1749125448Sgibbs && ahd_inb(ahd, LASTPHASE) == P_BUSFREE 1750129134Sgibbs && (ahd_inb(ahd, SSTAT0) & SELDI) == 0 1751125448Sgibbs && ((ahd_inb(ahd, SSTAT0) & SELDO) == 0 1752125448Sgibbs || (ahd_inb(ahd, SCSISEQ0) & ENSELO) == 0)) 1753125448Sgibbs /* 1754125448Sgibbs * Assume packetized if we are not 1755125448Sgibbs * on the bus in a non-packetized 1756125448Sgibbs * capacity and any pending selection 1757125448Sgibbs * was a packetized selection. 1758125448Sgibbs */ 175997883Sgibbs packetized = 1; 176097883Sgibbs break; 176197883Sgibbs } 176297883Sgibbs 176397883Sgibbs#ifdef AHD_DEBUG 176497883Sgibbs if ((ahd_debug & AHD_SHOW_MISC) != 0) 176597883Sgibbs printf("Saw Busfree. Busfreetime = 0x%x.\n", 176697883Sgibbs busfreetime); 176797883Sgibbs#endif 176897883Sgibbs /* 176997883Sgibbs * Busfrees that occur in non-packetized phases are 177097883Sgibbs * handled by the nonpkt_busfree handler. 177197883Sgibbs */ 177297883Sgibbs if (packetized && ahd_inb(ahd, LASTPHASE) == P_BUSFREE) { 177397883Sgibbs restart = ahd_handle_pkt_busfree(ahd, busfreetime); 177497883Sgibbs } else { 1775104023Sgibbs packetized = 0; 177697883Sgibbs restart = ahd_handle_nonpkt_busfree(ahd); 177797883Sgibbs } 177897883Sgibbs /* 177997883Sgibbs * Clear the busfree interrupt status. The setting of 1780104023Sgibbs * the interrupt is a pulse, so in a perfect world, we 1781104023Sgibbs * would not need to muck with the ENBUSFREE logic. This 1782104023Sgibbs * would ensure that if the bus moves on to another 1783104023Sgibbs * connection, busfree protection is still in force. If 1784104023Sgibbs * BUSFREEREV is broken, however, we must manually clear 1785104023Sgibbs * the ENBUSFREE if the busfree occurred during a non-pack 1786104023Sgibbs * connection so that we don't get false positives during 1787104023Sgibbs * future, packetized, connections. 178897883Sgibbs */ 1789104023Sgibbs ahd_outb(ahd, CLRSINT1, CLRBUSFREE); 1790104023Sgibbs if (packetized == 0 1791104023Sgibbs && (ahd->bugs & AHD_BUSFREEREV_BUG) != 0) 1792104023Sgibbs ahd_outb(ahd, SIMODE1, 1793104023Sgibbs ahd_inb(ahd, SIMODE1) & ~ENBUSFREE); 179497883Sgibbs 179597883Sgibbs if (clear_fifo) 179697883Sgibbs ahd_clear_fifo(ahd, mode); 179797883Sgibbs 179897883Sgibbs ahd_clear_msg_state(ahd); 1799104023Sgibbs ahd_outb(ahd, CLRINT, CLRSCSIINT); 1800102679Sgibbs if (restart) { 180197883Sgibbs ahd_restart(ahd); 1802102679Sgibbs } else { 180397883Sgibbs ahd_unpause(ahd); 180497883Sgibbs } 180597883Sgibbs } else { 180697883Sgibbs printf("%s: Missing case in ahd_handle_scsiint. status = %x\n", 180797883Sgibbs ahd_name(ahd), status); 180897883Sgibbs ahd_dump_card_state(ahd); 1809102679Sgibbs ahd_clear_intstat(ahd); 181097883Sgibbs ahd_unpause(ahd); 181197883Sgibbs } 181297883Sgibbs} 181397883Sgibbs 181497883Sgibbsstatic void 181597883Sgibbsahd_handle_transmission_error(struct ahd_softc *ahd) 181697883Sgibbs{ 1817107441Sscottl struct scb *scb; 1818107441Sscottl u_int scbid; 1819104023Sgibbs u_int lqistat1; 1820104023Sgibbs u_int lqistat2; 1821104023Sgibbs u_int msg_out; 1822104023Sgibbs u_int curphase; 1823104023Sgibbs u_int lastphase; 1824104023Sgibbs u_int perrdiag; 1825104023Sgibbs u_int cur_col; 1826109588Sgibbs int silent; 182797883Sgibbs 1828107441Sscottl scb = NULL; 182997883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 183097883Sgibbs lqistat1 = ahd_inb(ahd, LQISTAT1) & ~(LQIPHASE_LQ|LQIPHASE_NLQ); 183197883Sgibbs lqistat2 = ahd_inb(ahd, LQISTAT2); 183297883Sgibbs if ((lqistat1 & (LQICRCI_NLQ|LQICRCI_LQ)) == 0 183397883Sgibbs && (ahd->bugs & AHD_NLQICRC_DELAYED_BUG) != 0) { 183497883Sgibbs u_int lqistate; 183597883Sgibbs 183697883Sgibbs ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 183797883Sgibbs lqistate = ahd_inb(ahd, LQISTATE); 183897883Sgibbs if ((lqistate >= 0x1E && lqistate <= 0x24) 183997883Sgibbs || (lqistate == 0x29)) { 1840107441Sscottl#ifdef AHD_DEBUG 1841107441Sscottl if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { 1842107441Sscottl printf("%s: NLQCRC found via LQISTATE\n", 1843107441Sscottl ahd_name(ahd)); 1844107441Sscottl } 1845107441Sscottl#endif 184697883Sgibbs lqistat1 |= LQICRCI_NLQ; 184797883Sgibbs } 184897883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 184997883Sgibbs } 185097883Sgibbs 185197883Sgibbs ahd_outb(ahd, CLRLQIINT1, lqistat1); 185297883Sgibbs lastphase = ahd_inb(ahd, LASTPHASE); 185397883Sgibbs curphase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK; 185497883Sgibbs perrdiag = ahd_inb(ahd, PERRDIAG); 185597883Sgibbs msg_out = MSG_INITIATOR_DET_ERR; 185697883Sgibbs ahd_outb(ahd, CLRSINT1, CLRSCSIPERR); 1857109588Sgibbs 1858109588Sgibbs /* 1859109588Sgibbs * Try to find the SCB associated with this error. 1860109588Sgibbs */ 1861109588Sgibbs silent = FALSE; 1862109588Sgibbs if (lqistat1 == 0 1863109588Sgibbs || (lqistat1 & LQICRCI_NLQ) != 0) { 1864109588Sgibbs if ((lqistat1 & (LQICRCI_NLQ|LQIOVERI_NLQ)) != 0) 1865109588Sgibbs ahd_set_active_fifo(ahd); 1866109588Sgibbs scbid = ahd_get_scbptr(ahd); 1867109588Sgibbs scb = ahd_lookup_scb(ahd, scbid); 1868109588Sgibbs if (scb != NULL && SCB_IS_SILENT(scb)) 1869109588Sgibbs silent = TRUE; 1870109588Sgibbs } 1871109588Sgibbs 1872104023Sgibbs cur_col = 0; 1873109588Sgibbs if (silent == FALSE) { 1874109588Sgibbs printf("%s: Transmission error detected\n", ahd_name(ahd)); 1875109588Sgibbs ahd_lqistat1_print(lqistat1, &cur_col, 50); 1876109588Sgibbs ahd_lastphase_print(lastphase, &cur_col, 50); 1877109588Sgibbs ahd_scsisigi_print(curphase, &cur_col, 50); 1878109588Sgibbs ahd_perrdiag_print(perrdiag, &cur_col, 50); 1879109588Sgibbs printf("\n"); 1880199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 1881109588Sgibbs ahd_dump_card_state(ahd); 1882109588Sgibbs } 1883109588Sgibbs 188497883Sgibbs if ((lqistat1 & (LQIOVERI_LQ|LQIOVERI_NLQ)) != 0) { 1885109588Sgibbs if (silent == FALSE) { 1886109588Sgibbs printf("%s: Gross protocol error during incoming " 1887109588Sgibbs "packet. lqistat1 == 0x%x. Resetting bus.\n", 1888109588Sgibbs ahd_name(ahd), lqistat1); 1889199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 1890109588Sgibbs } 189197883Sgibbs ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 189297883Sgibbs return; 189397883Sgibbs } else if ((lqistat1 & LQICRCI_LQ) != 0) { 189497883Sgibbs /* 189597883Sgibbs * A CRC error has been detected on an incoming LQ. 189697883Sgibbs * The bus is currently hung on the last ACK. 189797883Sgibbs * Hit LQIRETRY to release the last ack, and 189897883Sgibbs * wait for the sequencer to determine that ATNO 189997883Sgibbs * is asserted while in message out to take us 190097883Sgibbs * to our host message loop. No NONPACKREQ or 190197883Sgibbs * LQIPHASE type errors will occur in this 190297883Sgibbs * scenario. After this first LQIRETRY, the LQI 190397883Sgibbs * manager will be in ISELO where it will 190497883Sgibbs * happily sit until another packet phase begins. 190597883Sgibbs * Unexpected bus free detection is enabled 190697883Sgibbs * through any phases that occur after we release 190797883Sgibbs * this last ack until the LQI manager sees a 190897883Sgibbs * packet phase. This implies we may have to 190997883Sgibbs * ignore a perfectly valid "unexected busfree" 191097883Sgibbs * after our "initiator detected error" message is 191197883Sgibbs * sent. A busfree is the expected response after 191297883Sgibbs * we tell the target that it's L_Q was corrupted. 191397883Sgibbs * (SPI4R09 10.7.3.3.3) 191497883Sgibbs */ 191597883Sgibbs ahd_outb(ahd, LQCTL2, LQIRETRY); 191697883Sgibbs printf("LQIRetry for LQICRCI_LQ to release ACK\n"); 1917199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 191897883Sgibbs } else if ((lqistat1 & LQICRCI_NLQ) != 0) { 191997883Sgibbs /* 192097883Sgibbs * We detected a CRC error in a NON-LQ packet. 192197883Sgibbs * The hardware has varying behavior in this situation 192297883Sgibbs * depending on whether this packet was part of a 192397883Sgibbs * stream or not. 192497883Sgibbs * 192597883Sgibbs * PKT by PKT mode: 192697883Sgibbs * The hardware has already acked the complete packet. 192797883Sgibbs * If the target honors our outstanding ATN condition, 192897883Sgibbs * we should be (or soon will be) in MSGOUT phase. 192997883Sgibbs * This will trigger the LQIPHASE_LQ status bit as the 193097883Sgibbs * hardware was expecting another LQ. Unexpected 193197883Sgibbs * busfree detection is enabled. Once LQIPHASE_LQ is 193297883Sgibbs * true (first entry into host message loop is much 193397883Sgibbs * the same), we must clear LQIPHASE_LQ and hit 193497883Sgibbs * LQIRETRY so the hardware is ready to handle 193597883Sgibbs * a future LQ. NONPACKREQ will not be asserted again 193697883Sgibbs * once we hit LQIRETRY until another packet is 193797883Sgibbs * processed. The target may either go busfree 193897883Sgibbs * or start another packet in response to our message. 193997883Sgibbs * 194097883Sgibbs * Read Streaming P0 asserted: 194197883Sgibbs * If we raise ATN and the target completes the entire 194297883Sgibbs * stream (P0 asserted during the last packet), the 194397883Sgibbs * hardware will ack all data and return to the ISTART 194497883Sgibbs * state. When the target reponds to our ATN condition, 194597883Sgibbs * LQIPHASE_LQ will be asserted. We should respond to 194697883Sgibbs * this with an LQIRETRY to prepare for any future 194797883Sgibbs * packets. NONPACKREQ will not be asserted again 194897883Sgibbs * once we hit LQIRETRY until another packet is 194997883Sgibbs * processed. The target may either go busfree or 195097883Sgibbs * start another packet in response to our message. 195197883Sgibbs * Busfree detection is enabled. 195297883Sgibbs * 195397883Sgibbs * Read Streaming P0 not asserted: 195497883Sgibbs * If we raise ATN and the target transitions to 195597883Sgibbs * MSGOUT in or after a packet where P0 is not 195697883Sgibbs * asserted, the hardware will assert LQIPHASE_NLQ. 195797883Sgibbs * We should respond to the LQIPHASE_NLQ with an 1958107441Sscottl * LQIRETRY. Should the target stay in a non-pkt 195997883Sgibbs * phase after we send our message, the hardware 196097883Sgibbs * will assert LQIPHASE_LQ. Recovery is then just as 196197883Sgibbs * listed above for the read streaming with P0 asserted. 196297883Sgibbs * Busfree detection is enabled. 196397883Sgibbs */ 1964109588Sgibbs if (silent == FALSE) 1965109588Sgibbs printf("LQICRC_NLQ\n"); 196697883Sgibbs if (scb == NULL) { 196797883Sgibbs printf("%s: No SCB valid for LQICRC_NLQ. " 196897883Sgibbs "Resetting bus\n", ahd_name(ahd)); 1969199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 197097883Sgibbs ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 197197883Sgibbs return; 197297883Sgibbs } 197397883Sgibbs } else if ((lqistat1 & LQIBADLQI) != 0) { 197497883Sgibbs printf("Need to handle BADLQI!\n"); 197597883Sgibbs ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 197697883Sgibbs return; 1977102679Sgibbs } else if ((perrdiag & (PARITYERR|PREVPHASE)) == PARITYERR) { 197897883Sgibbs if ((curphase & ~P_DATAIN_DT) != 0) { 197997883Sgibbs /* Ack the byte. So we can continue. */ 1980109588Sgibbs if (silent == FALSE) 1981109588Sgibbs printf("Acking %s to clear perror\n", 1982109588Sgibbs ahd_lookup_phase_entry(curphase)->phasemsg); 198397883Sgibbs ahd_inb(ahd, SCSIDAT); 198497883Sgibbs } 198597883Sgibbs 198697883Sgibbs if (curphase == P_MESGIN) 198797883Sgibbs msg_out = MSG_PARITY_ERROR; 198897883Sgibbs } 198997883Sgibbs 199097883Sgibbs /* 199197883Sgibbs * We've set the hardware to assert ATN if we 199297883Sgibbs * get a parity error on "in" phases, so all we 199397883Sgibbs * need to do is stuff the message buffer with 199497883Sgibbs * the appropriate message. "In" phases have set 199597883Sgibbs * mesg_out to something other than MSG_NOP. 199697883Sgibbs */ 199797883Sgibbs ahd->send_msg_perror = msg_out; 1998107441Sscottl if (scb != NULL && msg_out == MSG_INITIATOR_DET_ERR) 1999107441Sscottl scb->flags |= SCB_TRANSMISSION_ERROR; 200097883Sgibbs ahd_outb(ahd, MSG_OUT, HOST_MSG); 200197883Sgibbs ahd_outb(ahd, CLRINT, CLRSCSIINT); 200297883Sgibbs ahd_unpause(ahd); 200397883Sgibbs} 200497883Sgibbs 200597883Sgibbsstatic void 200697883Sgibbsahd_handle_lqiphase_error(struct ahd_softc *ahd, u_int lqistat1) 200797883Sgibbs{ 200897883Sgibbs /* 200997883Sgibbs * Clear the sources of the interrupts. 201097883Sgibbs */ 201197883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 201297883Sgibbs ahd_outb(ahd, CLRLQIINT1, lqistat1); 201397883Sgibbs 201497883Sgibbs /* 201597883Sgibbs * If the "illegal" phase changes were in response 201697883Sgibbs * to our ATN to flag a CRC error, AND we ended up 201797883Sgibbs * on packet boundaries, clear the error, restart the 201897883Sgibbs * LQI manager as appropriate, and go on our merry 201997883Sgibbs * way toward sending the message. Otherwise, reset 202097883Sgibbs * the bus to clear the error. 202197883Sgibbs */ 202297883Sgibbs ahd_set_active_fifo(ahd); 202397883Sgibbs if ((ahd_inb(ahd, SCSISIGO) & ATNO) != 0 202497883Sgibbs && (ahd_inb(ahd, MDFFSTAT) & DLZERO) != 0) { 202597883Sgibbs if ((lqistat1 & LQIPHASE_LQ) != 0) { 202697883Sgibbs printf("LQIRETRY for LQIPHASE_LQ\n"); 2027199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 202897883Sgibbs ahd_outb(ahd, LQCTL2, LQIRETRY); 202997883Sgibbs } else if ((lqistat1 & LQIPHASE_NLQ) != 0) { 2030107441Sscottl printf("LQIRETRY for LQIPHASE_NLQ\n"); 2031199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 203297883Sgibbs ahd_outb(ahd, LQCTL2, LQIRETRY); 203397883Sgibbs } else 203497883Sgibbs panic("ahd_handle_lqiphase_error: No phase errors\n"); 203597883Sgibbs ahd_dump_card_state(ahd); 203697883Sgibbs ahd_outb(ahd, CLRINT, CLRSCSIINT); 203797883Sgibbs ahd_unpause(ahd); 203897883Sgibbs } else { 203997883Sgibbs printf("Reseting Channel for LQI Phase error\n"); 2040199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 204197883Sgibbs ahd_dump_card_state(ahd); 204297883Sgibbs ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 204397883Sgibbs } 204497883Sgibbs} 204597883Sgibbs 204697883Sgibbs/* 204797883Sgibbs * Packetized unexpected or expected busfree. 2048104023Sgibbs * Entered in mode based on busfreetime. 204997883Sgibbs */ 205097883Sgibbsstatic int 205197883Sgibbsahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime) 205297883Sgibbs{ 205397883Sgibbs u_int lqostat1; 205497883Sgibbs 205597883Sgibbs AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 205697883Sgibbs ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 205797883Sgibbs lqostat1 = ahd_inb(ahd, LQOSTAT1); 205897883Sgibbs if ((lqostat1 & LQOBUSFREE) != 0) { 205997883Sgibbs struct scb *scb; 206097883Sgibbs u_int scbid; 2061104023Sgibbs u_int saved_scbptr; 206297883Sgibbs u_int waiting_h; 206397883Sgibbs u_int waiting_t; 206497883Sgibbs u_int next; 206597883Sgibbs 2066104023Sgibbs /* 2067104023Sgibbs * The LQO manager detected an unexpected busfree 2068104023Sgibbs * either: 2069104023Sgibbs * 2070104023Sgibbs * 1) During an outgoing LQ. 2071104023Sgibbs * 2) After an outgoing LQ but before the first 2072104023Sgibbs * REQ of the command packet. 2073104023Sgibbs * 3) During an outgoing command packet. 2074104023Sgibbs * 2075104023Sgibbs * In all cases, CURRSCB is pointing to the 2076104023Sgibbs * SCB that encountered the failure. Clean 2077104023Sgibbs * up the queue, clear SELDO and LQOBUSFREE, 2078104023Sgibbs * and allow the sequencer to restart the select 2079104023Sgibbs * out at its lesure. 2080104023Sgibbs */ 2081104023Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 2082104023Sgibbs scbid = ahd_inw(ahd, CURRSCB); 208397883Sgibbs scb = ahd_lookup_scb(ahd, scbid); 208497883Sgibbs if (scb == NULL) 208597883Sgibbs panic("SCB not valid during LQOBUSFREE"); 208697883Sgibbs /* 208797883Sgibbs * Clear the status. 208897883Sgibbs */ 208997883Sgibbs ahd_outb(ahd, CLRLQOINT1, CLRLQOBUSFREE); 2090104023Sgibbs if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) 209197883Sgibbs ahd_outb(ahd, CLRLQOINT1, 0); 2092104023Sgibbs ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO); 2093111653Sgibbs ahd_flush_device_writes(ahd); 2094104023Sgibbs ahd_outb(ahd, CLRSINT0, CLRSELDO); 2095104023Sgibbs 209697883Sgibbs /* 2097111653Sgibbs * Return the LQO manager to its idle loop. It will 2098111653Sgibbs * not do this automatically if the busfree occurs 2099111653Sgibbs * after the first REQ of either the LQ or command 2100111653Sgibbs * packet or between the LQ and command packet. 2101111653Sgibbs */ 2102111653Sgibbs ahd_outb(ahd, LQCTL2, ahd_inb(ahd, LQCTL2) | LQOTOIDLE); 2103111653Sgibbs 2104111653Sgibbs /* 2105104023Sgibbs * Update the waiting for selection queue so 2106104023Sgibbs * we restart on the correct SCB. 210797883Sgibbs */ 210897883Sgibbs waiting_h = ahd_inw(ahd, WAITING_TID_HEAD); 2109104023Sgibbs saved_scbptr = ahd_get_scbptr(ahd); 211097883Sgibbs if (waiting_h != scbid) { 211197883Sgibbs 211297883Sgibbs ahd_outw(ahd, WAITING_TID_HEAD, scbid); 211397883Sgibbs waiting_t = ahd_inw(ahd, WAITING_TID_TAIL); 211497883Sgibbs if (waiting_t == waiting_h) { 211597883Sgibbs ahd_outw(ahd, WAITING_TID_TAIL, scbid); 2116111653Sgibbs next = SCB_LIST_NULL; 211797883Sgibbs } else { 211897883Sgibbs ahd_set_scbptr(ahd, waiting_h); 2119111954Sgibbs next = ahd_inw_scbram(ahd, SCB_NEXT2); 212097883Sgibbs } 212197883Sgibbs ahd_set_scbptr(ahd, scbid); 212297883Sgibbs ahd_outw(ahd, SCB_NEXT2, next); 212397883Sgibbs } 2124104023Sgibbs ahd_set_scbptr(ahd, saved_scbptr); 2125107441Sscottl if (scb->crc_retry_count < AHD_MAX_LQ_CRC_ERRORS) { 2126109588Sgibbs if (SCB_IS_SILENT(scb) == FALSE) { 2127109588Sgibbs ahd_print_path(ahd, scb); 2128109588Sgibbs printf("Probable outgoing LQ CRC error. " 2129109588Sgibbs "Retrying command\n"); 2130199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 2131109588Sgibbs } 2132107441Sscottl scb->crc_retry_count++; 2133107441Sscottl } else { 2134123579Sgibbs aic_set_transaction_status(scb, CAM_UNCOR_PARITY); 2135123579Sgibbs aic_freeze_scb(scb); 2136107441Sscottl ahd_freeze_devq(ahd, scb); 2137107441Sscottl } 213897883Sgibbs /* Return unpausing the sequencer. */ 213997883Sgibbs return (0); 2140107441Sscottl } else if ((ahd_inb(ahd, PERRDIAG) & PARITYERR) != 0) { 2141107441Sscottl /* 2142107441Sscottl * Ignore what are really parity errors that 2143107441Sscottl * occur on the last REQ of a free running 2144107441Sscottl * clock prior to going busfree. Some drives 2145107441Sscottl * do not properly active negate just before 2146107441Sscottl * going busfree resulting in a parity glitch. 2147107441Sscottl */ 2148107441Sscottl ahd_outb(ahd, CLRSINT1, CLRSCSIPERR|CLRBUSFREE); 2149107441Sscottl#ifdef AHD_DEBUG 2150107441Sscottl if ((ahd_debug & AHD_SHOW_MASKED_ERRORS) != 0) 2151107441Sscottl printf("%s: Parity on last REQ detected " 2152107441Sscottl "during busfree phase.\n", 2153107441Sscottl ahd_name(ahd)); 2154107441Sscottl#endif 2155107441Sscottl /* Return unpausing the sequencer. */ 2156107441Sscottl return (0); 215797883Sgibbs } 215897883Sgibbs if (ahd->src_mode != AHD_MODE_SCSI) { 215997883Sgibbs u_int scbid; 216097883Sgibbs struct scb *scb; 216197883Sgibbs 216297883Sgibbs scbid = ahd_get_scbptr(ahd); 216397883Sgibbs scb = ahd_lookup_scb(ahd, scbid); 216497883Sgibbs ahd_print_path(ahd, scb); 216597883Sgibbs printf("Unexpected PKT busfree condition\n"); 2166199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 2167111653Sgibbs ahd_dump_card_state(ahd); 216897883Sgibbs ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), 'A', 216997883Sgibbs SCB_GET_LUN(scb), SCB_GET_TAG(scb), 217097883Sgibbs ROLE_INITIATOR, CAM_UNEXP_BUSFREE); 217197883Sgibbs 217297883Sgibbs /* Return restarting the sequencer. */ 217397883Sgibbs return (1); 217497883Sgibbs } 217597883Sgibbs printf("%s: Unexpected PKT busfree condition\n", ahd_name(ahd)); 2176199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 217797883Sgibbs ahd_dump_card_state(ahd); 217897883Sgibbs /* Restart the sequencer. */ 217997883Sgibbs return (1); 218097883Sgibbs} 218197883Sgibbs 218297883Sgibbs/* 218397883Sgibbs * Non-packetized unexpected or expected busfree. 218497883Sgibbs */ 218597883Sgibbsstatic int 218697883Sgibbsahd_handle_nonpkt_busfree(struct ahd_softc *ahd) 218797883Sgibbs{ 218897883Sgibbs struct ahd_devinfo devinfo; 218997883Sgibbs struct scb *scb; 219097883Sgibbs u_int lastphase; 219197883Sgibbs u_int saved_scsiid; 219297883Sgibbs u_int saved_lun; 219397883Sgibbs u_int target; 219497883Sgibbs u_int initiator_role_id; 219597883Sgibbs u_int scbid; 2196107441Sscottl u_int ppr_busfree; 219797883Sgibbs int printerror; 219897883Sgibbs 219997883Sgibbs /* 220097883Sgibbs * Look at what phase we were last in. If its message out, 220197883Sgibbs * chances are pretty good that the busfree was in response 220297883Sgibbs * to one of our abort requests. 220397883Sgibbs */ 220497883Sgibbs lastphase = ahd_inb(ahd, LASTPHASE); 220597883Sgibbs saved_scsiid = ahd_inb(ahd, SAVED_SCSIID); 220697883Sgibbs saved_lun = ahd_inb(ahd, SAVED_LUN); 220797883Sgibbs target = SCSIID_TARGET(ahd, saved_scsiid); 220897883Sgibbs initiator_role_id = SCSIID_OUR_ID(saved_scsiid); 220997883Sgibbs ahd_compile_devinfo(&devinfo, initiator_role_id, 221097883Sgibbs target, saved_lun, 'A', ROLE_INITIATOR); 221197883Sgibbs printerror = 1; 221297883Sgibbs 221397883Sgibbs scbid = ahd_get_scbptr(ahd); 221497883Sgibbs scb = ahd_lookup_scb(ahd, scbid); 221597883Sgibbs if (scb != NULL 221697883Sgibbs && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) != 0) 221797883Sgibbs scb = NULL; 221897883Sgibbs 2219107441Sscottl ppr_busfree = (ahd->msg_flags & MSG_FLAG_EXPECT_PPR_BUSFREE) != 0; 222097883Sgibbs if (lastphase == P_MESGOUT) { 222197883Sgibbs u_int tag; 222297883Sgibbs 222397883Sgibbs tag = SCB_LIST_NULL; 222497883Sgibbs if (ahd_sent_msg(ahd, AHDMSG_1B, MSG_ABORT_TAG, TRUE) 222597883Sgibbs || ahd_sent_msg(ahd, AHDMSG_1B, MSG_ABORT, TRUE)) { 222697883Sgibbs int found; 222797883Sgibbs int sent_msg; 222897883Sgibbs 2229102679Sgibbs if (scb == NULL) { 2230102679Sgibbs ahd_print_devinfo(ahd, &devinfo); 2231102679Sgibbs printf("Abort for unidentified " 2232102679Sgibbs "connection completed.\n"); 2233102679Sgibbs /* restart the sequencer. */ 2234102679Sgibbs return (1); 2235102679Sgibbs } 223697883Sgibbs sent_msg = ahd->msgout_buf[ahd->msgout_index - 1]; 223797883Sgibbs ahd_print_path(ahd, scb); 223897883Sgibbs printf("SCB %d - Abort%s Completed.\n", 223997883Sgibbs SCB_GET_TAG(scb), 224097883Sgibbs sent_msg == MSG_ABORT_TAG ? "" : " Tag"); 224197883Sgibbs 224297883Sgibbs if (sent_msg == MSG_ABORT_TAG) 224397883Sgibbs tag = SCB_GET_TAG(scb); 224497883Sgibbs 224597883Sgibbs if ((scb->flags & SCB_CMDPHASE_ABORT) != 0) { 224697883Sgibbs /* 224797883Sgibbs * This abort is in response to an 224897883Sgibbs * unexpected switch to command phase 224997883Sgibbs * for a packetized connection. Since 225097883Sgibbs * the identify message was never sent, 225197883Sgibbs * "saved lun" is 0. We really want to 225297883Sgibbs * abort only the SCB that encountered 225397883Sgibbs * this error, which could have a different 225497883Sgibbs * lun. The SCB will be retried so the OS 225597883Sgibbs * will see the UA after renegotiating to 225697883Sgibbs * packetized. 225797883Sgibbs */ 225897883Sgibbs tag = SCB_GET_TAG(scb); 225997883Sgibbs saved_lun = scb->hscb->lun; 226097883Sgibbs } 226197883Sgibbs found = ahd_abort_scbs(ahd, target, 'A', saved_lun, 226297883Sgibbs tag, ROLE_INITIATOR, 226397883Sgibbs CAM_REQ_ABORTED); 226497883Sgibbs printf("found == 0x%x\n", found); 226597883Sgibbs printerror = 0; 226697883Sgibbs } else if (ahd_sent_msg(ahd, AHDMSG_1B, 226797883Sgibbs MSG_BUS_DEV_RESET, TRUE)) { 226897883Sgibbs#ifdef __FreeBSD__ 226997883Sgibbs /* 227097883Sgibbs * Don't mark the user's request for this BDR 227197883Sgibbs * as completing with CAM_BDR_SENT. CAM3 227297883Sgibbs * specifies CAM_REQ_CMP. 227397883Sgibbs */ 227497883Sgibbs if (scb != NULL 227597883Sgibbs && scb->io_ctx->ccb_h.func_code== XPT_RESET_DEV 227697883Sgibbs && ahd_match_scb(ahd, scb, target, 'A', 227797883Sgibbs CAM_LUN_WILDCARD, SCB_LIST_NULL, 227897883Sgibbs ROLE_INITIATOR)) 2279123579Sgibbs aic_set_transaction_status(scb, CAM_REQ_CMP); 228097883Sgibbs#endif 2281109588Sgibbs ahd_handle_devreset(ahd, &devinfo, CAM_LUN_WILDCARD, 2282109588Sgibbs CAM_BDR_SENT, "Bus Device Reset", 228397883Sgibbs /*verbose_level*/0); 228497883Sgibbs printerror = 0; 2285107441Sscottl } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, FALSE) 2286107441Sscottl && ppr_busfree == 0) { 228797883Sgibbs struct ahd_initiator_tinfo *tinfo; 228897883Sgibbs struct ahd_tmode_tstate *tstate; 228997883Sgibbs 229097883Sgibbs /* 2291133122Sgibbs * PPR Rejected. 2292133122Sgibbs * 2293133122Sgibbs * If the previous negotiation was packetized, 2294133122Sgibbs * this could be because the device has been 2295133122Sgibbs * reset without our knowledge. Force our 2296133122Sgibbs * current negotiation to async and retry the 2297133122Sgibbs * negotiation. Otherwise retry the command 2298133122Sgibbs * with non-ppr negotiation. 229997883Sgibbs */ 2300107441Sscottl#ifdef AHD_DEBUG 2301107441Sscottl if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 2302107441Sscottl printf("PPR negotiation rejected busfree.\n"); 2303107441Sscottl#endif 230497883Sgibbs tinfo = ahd_fetch_transinfo(ahd, devinfo.channel, 230597883Sgibbs devinfo.our_scsiid, 230697883Sgibbs devinfo.target, &tstate); 2307133122Sgibbs if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ)!=0) { 2308133122Sgibbs ahd_set_width(ahd, &devinfo, 2309133122Sgibbs MSG_EXT_WDTR_BUS_8_BIT, 2310133122Sgibbs AHD_TRANS_CUR, 2311133122Sgibbs /*paused*/TRUE); 2312133122Sgibbs ahd_set_syncrate(ahd, &devinfo, 2313133122Sgibbs /*period*/0, /*offset*/0, 2314133122Sgibbs /*ppr_options*/0, 2315133122Sgibbs AHD_TRANS_CUR, 2316133122Sgibbs /*paused*/TRUE); 2317133122Sgibbs /* 2318133122Sgibbs * The expect PPR busfree handler below 2319133122Sgibbs * will effect the retry and necessary 2320133122Sgibbs * abort. 2321133122Sgibbs */ 2322133122Sgibbs } else { 2323133122Sgibbs tinfo->curr.transport_version = 2; 2324133122Sgibbs tinfo->goal.transport_version = 2; 2325133122Sgibbs tinfo->goal.ppr_options = 0; 2326133122Sgibbs /* 2327133122Sgibbs * Remove any SCBs in the waiting for selection 2328133122Sgibbs * queue that may also be for this target so 2329133122Sgibbs * that command ordering is preserved. 2330133122Sgibbs */ 2331133122Sgibbs ahd_freeze_devq(ahd, scb); 2332133122Sgibbs ahd_qinfifo_requeue_tail(ahd, scb); 2333133122Sgibbs printerror = 0; 2334133122Sgibbs } 2335115918Sgibbs } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, FALSE) 2336107441Sscottl && ppr_busfree == 0) { 233797883Sgibbs /* 2338115918Sgibbs * Negotiation Rejected. Go-narrow and 233997883Sgibbs * retry command. 234097883Sgibbs */ 2341107441Sscottl#ifdef AHD_DEBUG 2342107441Sscottl if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 2343115918Sgibbs printf("WDTR negotiation rejected busfree.\n"); 2344107441Sscottl#endif 234597883Sgibbs ahd_set_width(ahd, &devinfo, 234697883Sgibbs MSG_EXT_WDTR_BUS_8_BIT, 234797883Sgibbs AHD_TRANS_CUR|AHD_TRANS_GOAL, 234897883Sgibbs /*paused*/TRUE); 2349133122Sgibbs /* 2350133122Sgibbs * Remove any SCBs in the waiting for selection 2351133122Sgibbs * queue that may also be for this target so that 2352133122Sgibbs * command ordering is preserved. 2353133122Sgibbs */ 2354133122Sgibbs ahd_freeze_devq(ahd, scb); 2355115918Sgibbs ahd_qinfifo_requeue_tail(ahd, scb); 2356115918Sgibbs printerror = 0; 2357115918Sgibbs } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, FALSE) 2358115918Sgibbs && ppr_busfree == 0) { 2359115918Sgibbs /* 2360115918Sgibbs * Negotiation Rejected. Go-async and 2361115918Sgibbs * retry command. 2362115918Sgibbs */ 2363115918Sgibbs#ifdef AHD_DEBUG 2364115918Sgibbs if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 2365115918Sgibbs printf("SDTR negotiation rejected busfree.\n"); 2366115918Sgibbs#endif 236797883Sgibbs ahd_set_syncrate(ahd, &devinfo, 236897883Sgibbs /*period*/0, /*offset*/0, 236997883Sgibbs /*ppr_options*/0, 237097883Sgibbs AHD_TRANS_CUR|AHD_TRANS_GOAL, 237197883Sgibbs /*paused*/TRUE); 2372133122Sgibbs /* 2373133122Sgibbs * Remove any SCBs in the waiting for selection 2374133122Sgibbs * queue that may also be for this target so that 2375133122Sgibbs * command ordering is preserved. 2376133122Sgibbs */ 2377133122Sgibbs ahd_freeze_devq(ahd, scb); 237897883Sgibbs ahd_qinfifo_requeue_tail(ahd, scb); 237997883Sgibbs printerror = 0; 238097883Sgibbs } else if ((ahd->msg_flags & MSG_FLAG_EXPECT_IDE_BUSFREE) != 0 238197883Sgibbs && ahd_sent_msg(ahd, AHDMSG_1B, 238297883Sgibbs MSG_INITIATOR_DET_ERR, TRUE)) { 238397883Sgibbs 238497883Sgibbs#ifdef AHD_DEBUG 238597883Sgibbs if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 238697883Sgibbs printf("Expected IDE Busfree\n"); 238797883Sgibbs#endif 238897883Sgibbs printerror = 0; 2389107441Sscottl } else if ((ahd->msg_flags & MSG_FLAG_EXPECT_QASREJ_BUSFREE) 2390107441Sscottl && ahd_sent_msg(ahd, AHDMSG_1B, 2391107441Sscottl MSG_MESSAGE_REJECT, TRUE)) { 2392107441Sscottl 2393107441Sscottl#ifdef AHD_DEBUG 2394107441Sscottl if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 2395107441Sscottl printf("Expected QAS Reject Busfree\n"); 2396107441Sscottl#endif 2397107441Sscottl printerror = 0; 239897883Sgibbs } 2399102679Sgibbs } 240097883Sgibbs 2401102679Sgibbs /* 2402102679Sgibbs * The busfree required flag is honored at the end of 2403102679Sgibbs * the message phases. We check it last in case we 2404102679Sgibbs * had to send some other message that caused a busfree. 2405102679Sgibbs */ 2406102679Sgibbs if (printerror != 0 2407102679Sgibbs && (lastphase == P_MESGIN || lastphase == P_MESGOUT) 2408102679Sgibbs && ((ahd->msg_flags & MSG_FLAG_EXPECT_PPR_BUSFREE) != 0)) { 240997883Sgibbs 2410102679Sgibbs ahd_freeze_devq(ahd, scb); 2411123579Sgibbs aic_set_transaction_status(scb, CAM_REQUEUE_REQ); 2412123579Sgibbs aic_freeze_scb(scb); 2413102679Sgibbs if ((ahd->msg_flags & MSG_FLAG_IU_REQ_CHANGED) != 0) { 2414102679Sgibbs ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), 2415102679Sgibbs SCB_GET_CHANNEL(ahd, scb), 2416102679Sgibbs SCB_GET_LUN(scb), SCB_LIST_NULL, 2417102679Sgibbs ROLE_INITIATOR, CAM_REQ_ABORTED); 2418102679Sgibbs } else { 241997883Sgibbs#ifdef AHD_DEBUG 2420102679Sgibbs if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 2421102679Sgibbs printf("PPR Negotiation Busfree.\n"); 242297883Sgibbs#endif 2423102679Sgibbs ahd_done(ahd, scb); 242497883Sgibbs } 2425102679Sgibbs printerror = 0; 242697883Sgibbs } 242797883Sgibbs if (printerror != 0) { 242897883Sgibbs int aborted; 242997883Sgibbs 243097883Sgibbs aborted = 0; 243197883Sgibbs if (scb != NULL) { 243297883Sgibbs u_int tag; 243397883Sgibbs 243497883Sgibbs if ((scb->hscb->control & TAG_ENB) != 0) 243597883Sgibbs tag = SCB_GET_TAG(scb); 243697883Sgibbs else 243797883Sgibbs tag = SCB_LIST_NULL; 243897883Sgibbs ahd_print_path(ahd, scb); 243997883Sgibbs aborted = ahd_abort_scbs(ahd, target, 'A', 244097883Sgibbs SCB_GET_LUN(scb), tag, 244197883Sgibbs ROLE_INITIATOR, 244297883Sgibbs CAM_UNEXP_BUSFREE); 244397883Sgibbs } else { 244497883Sgibbs /* 244597883Sgibbs * We had not fully identified this connection, 244697883Sgibbs * so we cannot abort anything. 244797883Sgibbs */ 244897883Sgibbs printf("%s: ", ahd_name(ahd)); 244997883Sgibbs } 245097883Sgibbs printf("Unexpected busfree %s, %d SCBs aborted, " 245197883Sgibbs "PRGMCNT == 0x%x\n", 245297883Sgibbs ahd_lookup_phase_entry(lastphase)->phasemsg, 245397883Sgibbs aborted, 2454123579Sgibbs ahd_inw(ahd, PRGMCNT)); 2455199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 245697883Sgibbs ahd_dump_card_state(ahd); 2457133122Sgibbs if (lastphase != P_BUSFREE) 2458133122Sgibbs ahd_force_renegotiation(ahd, &devinfo); 245997883Sgibbs } 246097883Sgibbs /* Always restart the sequencer. */ 246197883Sgibbs return (1); 246297883Sgibbs} 246397883Sgibbs 2464102679Sgibbsstatic void 2465102679Sgibbsahd_handle_proto_violation(struct ahd_softc *ahd) 2466102679Sgibbs{ 2467102679Sgibbs struct ahd_devinfo devinfo; 2468102679Sgibbs struct scb *scb; 2469102679Sgibbs u_int scbid; 2470102679Sgibbs u_int seq_flags; 2471102679Sgibbs u_int curphase; 2472102679Sgibbs u_int lastphase; 2473102679Sgibbs int found; 2474102679Sgibbs 2475102679Sgibbs ahd_fetch_devinfo(ahd, &devinfo); 2476102679Sgibbs scbid = ahd_get_scbptr(ahd); 2477102679Sgibbs scb = ahd_lookup_scb(ahd, scbid); 2478102679Sgibbs seq_flags = ahd_inb(ahd, SEQ_FLAGS); 2479102679Sgibbs curphase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK; 2480102679Sgibbs lastphase = ahd_inb(ahd, LASTPHASE); 2481102679Sgibbs if ((seq_flags & NOT_IDENTIFIED) != 0) { 2482102679Sgibbs 2483102679Sgibbs /* 2484102679Sgibbs * The reconnecting target either did not send an 2485102679Sgibbs * identify message, or did, but we didn't find an SCB 2486102679Sgibbs * to match. 2487102679Sgibbs */ 2488102679Sgibbs ahd_print_devinfo(ahd, &devinfo); 2489102679Sgibbs printf("Target did not send an IDENTIFY message. " 2490102679Sgibbs "LASTPHASE = 0x%x.\n", lastphase); 2491199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 2492102679Sgibbs scb = NULL; 2493102679Sgibbs } else if (scb == NULL) { 2494102679Sgibbs /* 2495102679Sgibbs * We don't seem to have an SCB active for this 2496102679Sgibbs * transaction. Print an error and reset the bus. 2497102679Sgibbs */ 2498102679Sgibbs ahd_print_devinfo(ahd, &devinfo); 2499102679Sgibbs printf("No SCB found during protocol violation\n"); 2500199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 2501102679Sgibbs goto proto_violation_reset; 2502102679Sgibbs } else { 2503123579Sgibbs aic_set_transaction_status(scb, CAM_SEQUENCE_FAIL); 2504102679Sgibbs if ((seq_flags & NO_CDB_SENT) != 0) { 2505102679Sgibbs ahd_print_path(ahd, scb); 2506102679Sgibbs printf("No or incomplete CDB sent to device.\n"); 2507199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 2508111954Sgibbs } else if ((ahd_inb_scbram(ahd, SCB_CONTROL) 2509111954Sgibbs & STATUS_RCVD) == 0) { 2510102679Sgibbs /* 2511102679Sgibbs * The target never bothered to provide status to 2512102679Sgibbs * us prior to completing the command. Since we don't 2513102679Sgibbs * know the disposition of this command, we must attempt 2514102679Sgibbs * to abort it. Assert ATN and prepare to send an abort 2515102679Sgibbs * message. 2516102679Sgibbs */ 2517102679Sgibbs ahd_print_path(ahd, scb); 2518102679Sgibbs printf("Completed command without status.\n"); 2519102679Sgibbs } else { 2520102679Sgibbs ahd_print_path(ahd, scb); 2521102679Sgibbs printf("Unknown protocol violation.\n"); 2522199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 2523102679Sgibbs ahd_dump_card_state(ahd); 2524102679Sgibbs } 2525102679Sgibbs } 2526107441Sscottl if ((lastphase & ~P_DATAIN_DT) == 0 2527107441Sscottl || lastphase == P_COMMAND) { 2528102679Sgibbsproto_violation_reset: 2529102679Sgibbs /* 2530102679Sgibbs * Target either went directly to data 2531102679Sgibbs * phase or didn't respond to our ATN. 2532102679Sgibbs * The only safe thing to do is to blow 2533102679Sgibbs * it away with a bus reset. 2534102679Sgibbs */ 2535102679Sgibbs found = ahd_reset_channel(ahd, 'A', TRUE); 2536102679Sgibbs printf("%s: Issued Channel %c Bus Reset. " 2537102679Sgibbs "%d SCBs aborted\n", ahd_name(ahd), 'A', found); 2538199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 2539102679Sgibbs } else { 2540102679Sgibbs /* 2541102679Sgibbs * Leave the selection hardware off in case 2542102679Sgibbs * this abort attempt will affect yet to 2543102679Sgibbs * be sent commands. 2544102679Sgibbs */ 2545102679Sgibbs ahd_outb(ahd, SCSISEQ0, 2546102679Sgibbs ahd_inb(ahd, SCSISEQ0) & ~ENSELO); 2547102679Sgibbs ahd_assert_atn(ahd); 2548102679Sgibbs ahd_outb(ahd, MSG_OUT, HOST_MSG); 2549102679Sgibbs if (scb == NULL) { 2550102679Sgibbs ahd_print_devinfo(ahd, &devinfo); 2551102679Sgibbs ahd->msgout_buf[0] = MSG_ABORT_TASK; 2552102679Sgibbs ahd->msgout_len = 1; 2553102679Sgibbs ahd->msgout_index = 0; 2554102679Sgibbs ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; 2555102679Sgibbs } else { 2556102679Sgibbs ahd_print_path(ahd, scb); 2557102679Sgibbs scb->flags |= SCB_ABORT; 2558102679Sgibbs } 2559102679Sgibbs printf("Protocol violation %s. Attempting to abort.\n", 2560102679Sgibbs ahd_lookup_phase_entry(curphase)->phasemsg); 2561199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 2562102679Sgibbs } 2563102679Sgibbs} 2564102679Sgibbs 256597883Sgibbs/* 256697883Sgibbs * Force renegotiation to occur the next time we initiate 256797883Sgibbs * a command to the current device. 256897883Sgibbs */ 256997883Sgibbsstatic void 257097883Sgibbsahd_force_renegotiation(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) 257197883Sgibbs{ 257297883Sgibbs struct ahd_initiator_tinfo *targ_info; 257397883Sgibbs struct ahd_tmode_tstate *tstate; 257497883Sgibbs 2575107441Sscottl#ifdef AHD_DEBUG 2576107441Sscottl if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { 2577107441Sscottl ahd_print_devinfo(ahd, devinfo); 2578107441Sscottl printf("Forcing renegotiation\n"); 2579107441Sscottl } 2580107441Sscottl#endif 258197883Sgibbs targ_info = ahd_fetch_transinfo(ahd, 258297883Sgibbs devinfo->channel, 258397883Sgibbs devinfo->our_scsiid, 258497883Sgibbs devinfo->target, 258597883Sgibbs &tstate); 258697883Sgibbs ahd_update_neg_request(ahd, devinfo, tstate, 2587107441Sscottl targ_info, AHD_NEG_IF_NON_ASYNC); 258897883Sgibbs} 258997883Sgibbs 259097883Sgibbs#define AHD_MAX_STEPS 2000 259197883Sgibbsvoid 259297883Sgibbsahd_clear_critical_section(struct ahd_softc *ahd) 259397883Sgibbs{ 259497883Sgibbs ahd_mode_state saved_modes; 259597883Sgibbs int stepping; 259697883Sgibbs int steps; 2597107441Sscottl int first_instr; 2598107441Sscottl u_int simode0; 2599107441Sscottl u_int simode1; 2600107441Sscottl u_int simode3; 2601107441Sscottl u_int lqimode0; 2602107441Sscottl u_int lqimode1; 2603107441Sscottl u_int lqomode0; 2604107441Sscottl u_int lqomode1; 260597883Sgibbs 260697883Sgibbs if (ahd->num_critical_sections == 0) 260797883Sgibbs return; 260897883Sgibbs 260997883Sgibbs stepping = FALSE; 261097883Sgibbs steps = 0; 2611107441Sscottl first_instr = 0; 2612107441Sscottl simode0 = 0; 2613107441Sscottl simode1 = 0; 2614107441Sscottl simode3 = 0; 2615107441Sscottl lqimode0 = 0; 2616107441Sscottl lqimode1 = 0; 2617107441Sscottl lqomode0 = 0; 2618107441Sscottl lqomode1 = 0; 261997883Sgibbs saved_modes = ahd_save_modes(ahd); 262097883Sgibbs for (;;) { 262197883Sgibbs struct cs *cs; 262297883Sgibbs u_int seqaddr; 262397883Sgibbs u_int i; 262497883Sgibbs 262597883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 2626123579Sgibbs seqaddr = ahd_inw(ahd, CURADDR); 262797883Sgibbs 262897883Sgibbs cs = ahd->critical_sections; 262997883Sgibbs for (i = 0; i < ahd->num_critical_sections; i++, cs++) { 263097883Sgibbs 263197883Sgibbs if (cs->begin < seqaddr && cs->end >= seqaddr) 263297883Sgibbs break; 263397883Sgibbs } 263497883Sgibbs 263597883Sgibbs if (i == ahd->num_critical_sections) 263697883Sgibbs break; 263797883Sgibbs 263897883Sgibbs if (steps > AHD_MAX_STEPS) { 2639107441Sscottl printf("%s: Infinite loop in critical section\n" 2640107441Sscottl "%s: First Instruction 0x%x now 0x%x\n", 2641107441Sscottl ahd_name(ahd), ahd_name(ahd), first_instr, 2642107441Sscottl seqaddr); 2643199260Sattilio AHD_FATAL_ERROR(ahd); 264497883Sgibbs ahd_dump_card_state(ahd); 264597883Sgibbs panic("critical section loop"); 264697883Sgibbs } 264797883Sgibbs 264897883Sgibbs steps++; 2649107441Sscottl#ifdef AHD_DEBUG 2650107441Sscottl if ((ahd_debug & AHD_SHOW_MISC) != 0) 2651107441Sscottl printf("%s: Single stepping at 0x%x\n", ahd_name(ahd), 2652107441Sscottl seqaddr); 2653107441Sscottl#endif 265497883Sgibbs if (stepping == FALSE) { 265597883Sgibbs 2656107441Sscottl first_instr = seqaddr; 2657107441Sscottl ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 2658107441Sscottl simode0 = ahd_inb(ahd, SIMODE0); 2659107441Sscottl simode3 = ahd_inb(ahd, SIMODE3); 2660107441Sscottl lqimode0 = ahd_inb(ahd, LQIMODE0); 2661107441Sscottl lqimode1 = ahd_inb(ahd, LQIMODE1); 2662107441Sscottl lqomode0 = ahd_inb(ahd, LQOMODE0); 2663107441Sscottl lqomode1 = ahd_inb(ahd, LQOMODE1); 2664107441Sscottl ahd_outb(ahd, SIMODE0, 0); 2665107441Sscottl ahd_outb(ahd, SIMODE3, 0); 2666107441Sscottl ahd_outb(ahd, LQIMODE0, 0); 2667107441Sscottl ahd_outb(ahd, LQIMODE1, 0); 2668107441Sscottl ahd_outb(ahd, LQOMODE0, 0); 2669107441Sscottl ahd_outb(ahd, LQOMODE1, 0); 267097883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 2671116935Sgibbs simode1 = ahd_inb(ahd, SIMODE1); 2672116935Sgibbs /* 2673116935Sgibbs * We don't clear ENBUSFREE. Unfortunately 2674116935Sgibbs * we cannot re-enable busfree detection within 2675116935Sgibbs * the current connection, so we must leave it 2676116935Sgibbs * on while single stepping. 2677116935Sgibbs */ 2678116935Sgibbs ahd_outb(ahd, SIMODE1, simode1 & ENBUSFREE); 267997883Sgibbs ahd_outb(ahd, SEQCTL0, ahd_inb(ahd, SEQCTL0) | STEP); 268097883Sgibbs stepping = TRUE; 268197883Sgibbs } 2682107441Sscottl ahd_outb(ahd, CLRSINT1, CLRBUSFREE); 2683107441Sscottl ahd_outb(ahd, CLRINT, CLRSCSIINT); 268497883Sgibbs ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); 268597883Sgibbs ahd_outb(ahd, HCNTRL, ahd->unpause); 2686116935Sgibbs while (!ahd_is_paused(ahd)) 2687123579Sgibbs aic_delay(200); 268897883Sgibbs ahd_update_modes(ahd); 268997883Sgibbs } 269097883Sgibbs if (stepping) { 2691107441Sscottl ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 2692107441Sscottl ahd_outb(ahd, SIMODE0, simode0); 2693107441Sscottl ahd_outb(ahd, SIMODE3, simode3); 2694107441Sscottl ahd_outb(ahd, LQIMODE0, lqimode0); 2695107441Sscottl ahd_outb(ahd, LQIMODE1, lqimode1); 2696107441Sscottl ahd_outb(ahd, LQOMODE0, lqomode0); 2697107441Sscottl ahd_outb(ahd, LQOMODE1, lqomode1); 269897883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 269997883Sgibbs ahd_outb(ahd, SEQCTL0, ahd_inb(ahd, SEQCTL0) & ~STEP); 2700107441Sscottl ahd_outb(ahd, SIMODE1, simode1); 2701114623Sgibbs /* 2702114623Sgibbs * SCSIINT seems to glitch occassionally when 2703114623Sgibbs * the interrupt masks are restored. Clear SCSIINT 2704114623Sgibbs * one more time so that only persistent errors 2705114623Sgibbs * are seen as a real interrupt. 2706114623Sgibbs */ 2707114623Sgibbs ahd_outb(ahd, CLRINT, CLRSCSIINT); 270897883Sgibbs } 270997883Sgibbs ahd_restore_modes(ahd, saved_modes); 271097883Sgibbs} 271197883Sgibbs 271297883Sgibbs/* 271397883Sgibbs * Clear any pending interrupt status. 271497883Sgibbs */ 271597883Sgibbsvoid 271697883Sgibbsahd_clear_intstat(struct ahd_softc *ahd) 271797883Sgibbs{ 2718102679Sgibbs AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 2719102679Sgibbs ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 272097883Sgibbs /* Clear any interrupt conditions this may have caused */ 2721102679Sgibbs ahd_outb(ahd, CLRLQIINT0, CLRLQIATNQAS|CLRLQICRCT1|CLRLQICRCT2 2722102679Sgibbs |CLRLQIBADLQT|CLRLQIATNLQ|CLRLQIATNCMD); 2723102679Sgibbs ahd_outb(ahd, CLRLQIINT1, CLRLQIPHASE_LQ|CLRLQIPHASE_NLQ|CLRLIQABORT 2724102679Sgibbs |CLRLQICRCI_LQ|CLRLQICRCI_NLQ|CLRLQIBADLQI 2725102679Sgibbs |CLRLQIOVERI_LQ|CLRLQIOVERI_NLQ|CLRNONPACKREQ); 2726102679Sgibbs ahd_outb(ahd, CLRLQOINT0, CLRLQOTARGSCBPERR|CLRLQOSTOPT2|CLRLQOATNLQ 2727102679Sgibbs |CLRLQOATNPKT|CLRLQOTCRC); 2728102679Sgibbs ahd_outb(ahd, CLRLQOINT1, CLRLQOINITSCBPERR|CLRLQOSTOPI2|CLRLQOBADQAS 2729102679Sgibbs |CLRLQOBUSFREE|CLRLQOPHACHGINPKT); 2730104023Sgibbs if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) { 2731104023Sgibbs ahd_outb(ahd, CLRLQOINT0, 0); 2732104023Sgibbs ahd_outb(ahd, CLRLQOINT1, 0); 2733104023Sgibbs } 2734102679Sgibbs ahd_outb(ahd, CLRSINT3, CLRNTRAMPERR|CLROSRAMPERR); 273597883Sgibbs ahd_outb(ahd, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI 273697883Sgibbs |CLRBUSFREE|CLRSCSIPERR|CLRREQINIT); 2737107441Sscottl ahd_outb(ahd, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO 2738107441Sscottl |CLRIOERR|CLROVERRUN); 273997883Sgibbs ahd_outb(ahd, CLRINT, CLRSCSIINT); 274097883Sgibbs} 274197883Sgibbs 274297883Sgibbs/**************************** Debugging Routines ******************************/ 274397883Sgibbs#ifdef AHD_DEBUG 274497883Sgibbsuint32_t ahd_debug = AHD_DEBUG_OPTS; 274597883Sgibbs#endif 274697883Sgibbsvoid 274797883Sgibbsahd_print_scb(struct scb *scb) 274897883Sgibbs{ 274997883Sgibbs struct hardware_scb *hscb; 275097883Sgibbs int i; 275197883Sgibbs 275297883Sgibbs hscb = scb->hscb; 275397883Sgibbs printf("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n", 275497883Sgibbs (void *)scb, 275597883Sgibbs hscb->control, 275697883Sgibbs hscb->scsiid, 275797883Sgibbs hscb->lun, 275897883Sgibbs hscb->cdb_len); 275997883Sgibbs printf("Shared Data: "); 276097883Sgibbs for (i = 0; i < sizeof(hscb->shared_data.idata.cdb); i++) 276197883Sgibbs printf("%#02x", hscb->shared_data.idata.cdb[i]); 276297883Sgibbs printf(" dataptr:%#x%x datacnt:%#x sgptr:%#x tag:%#x\n", 2763123579Sgibbs (uint32_t)((aic_le64toh(hscb->dataptr) >> 32) & 0xFFFFFFFF), 2764123579Sgibbs (uint32_t)(aic_le64toh(hscb->dataptr) & 0xFFFFFFFF), 2765123579Sgibbs aic_le32toh(hscb->datacnt), 2766123579Sgibbs aic_le32toh(hscb->sgptr), 276797883Sgibbs SCB_GET_TAG(scb)); 276897883Sgibbs ahd_dump_sglist(scb); 276997883Sgibbs} 277097883Sgibbs 277197883Sgibbsvoid 277297883Sgibbsahd_dump_sglist(struct scb *scb) 277397883Sgibbs{ 277497883Sgibbs int i; 277597883Sgibbs 277697883Sgibbs if (scb->sg_count > 0) { 277797883Sgibbs if ((scb->ahd_softc->flags & AHD_64BIT_ADDRESSING) != 0) { 277897883Sgibbs struct ahd_dma64_seg *sg_list; 277997883Sgibbs 278097883Sgibbs sg_list = (struct ahd_dma64_seg*)scb->sg_list; 278197883Sgibbs for (i = 0; i < scb->sg_count; i++) { 278297883Sgibbs uint64_t addr; 2783104023Sgibbs uint32_t len; 278497883Sgibbs 2785123579Sgibbs addr = aic_le64toh(sg_list[i].addr); 2786123579Sgibbs len = aic_le32toh(sg_list[i].len); 2787104023Sgibbs printf("sg[%d] - Addr 0x%x%x : Length %d%s\n", 278897883Sgibbs i, 278997883Sgibbs (uint32_t)((addr >> 32) & 0xFFFFFFFF), 279097883Sgibbs (uint32_t)(addr & 0xFFFFFFFF), 2791104023Sgibbs sg_list[i].len & AHD_SG_LEN_MASK, 2792104023Sgibbs (sg_list[i].len & AHD_DMA_LAST_SEG) 2793104023Sgibbs ? " Last" : ""); 279497883Sgibbs } 279597883Sgibbs } else { 279697883Sgibbs struct ahd_dma_seg *sg_list; 279797883Sgibbs 279897883Sgibbs sg_list = (struct ahd_dma_seg*)scb->sg_list; 279997883Sgibbs for (i = 0; i < scb->sg_count; i++) { 2800104023Sgibbs uint32_t len; 2801104023Sgibbs 2802123579Sgibbs len = aic_le32toh(sg_list[i].len); 2803104023Sgibbs printf("sg[%d] - Addr 0x%x%x : Length %d%s\n", 280497883Sgibbs i, 2805116938Sgibbs (len & AHD_SG_HIGH_ADDR_MASK) >> 24, 2806123579Sgibbs aic_le32toh(sg_list[i].addr), 2807104023Sgibbs len & AHD_SG_LEN_MASK, 2808104023Sgibbs len & AHD_DMA_LAST_SEG ? " Last" : ""); 280997883Sgibbs } 281097883Sgibbs } 281197883Sgibbs } 281297883Sgibbs} 281397883Sgibbs 281497883Sgibbs/************************* Transfer Negotiation *******************************/ 281597883Sgibbs/* 281697883Sgibbs * Allocate per target mode instance (ID we respond to as a target) 281797883Sgibbs * transfer negotiation data structures. 281897883Sgibbs */ 281997883Sgibbsstatic struct ahd_tmode_tstate * 282097883Sgibbsahd_alloc_tstate(struct ahd_softc *ahd, u_int scsi_id, char channel) 282197883Sgibbs{ 282297883Sgibbs struct ahd_tmode_tstate *master_tstate; 282397883Sgibbs struct ahd_tmode_tstate *tstate; 282497883Sgibbs int i; 282597883Sgibbs 282697883Sgibbs master_tstate = ahd->enabled_targets[ahd->our_id]; 282797883Sgibbs if (ahd->enabled_targets[scsi_id] != NULL 282897883Sgibbs && ahd->enabled_targets[scsi_id] != master_tstate) 282997883Sgibbs panic("%s: ahd_alloc_tstate - Target already allocated", 283097883Sgibbs ahd_name(ahd)); 283197883Sgibbs tstate = malloc(sizeof(*tstate), M_DEVBUF, M_NOWAIT); 283297883Sgibbs if (tstate == NULL) 283397883Sgibbs return (NULL); 283497883Sgibbs 283597883Sgibbs /* 283697883Sgibbs * If we have allocated a master tstate, copy user settings from 283797883Sgibbs * the master tstate (taken from SRAM or the EEPROM) for this 283897883Sgibbs * channel, but reset our current and goal settings to async/narrow 283997883Sgibbs * until an initiator talks to us. 284097883Sgibbs */ 284197883Sgibbs if (master_tstate != NULL) { 284297883Sgibbs memcpy(tstate, master_tstate, sizeof(*tstate)); 284397883Sgibbs memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns)); 284497883Sgibbs for (i = 0; i < 16; i++) { 284597883Sgibbs memset(&tstate->transinfo[i].curr, 0, 284697883Sgibbs sizeof(tstate->transinfo[i].curr)); 284797883Sgibbs memset(&tstate->transinfo[i].goal, 0, 284897883Sgibbs sizeof(tstate->transinfo[i].goal)); 284997883Sgibbs } 285097883Sgibbs } else 285197883Sgibbs memset(tstate, 0, sizeof(*tstate)); 285297883Sgibbs ahd->enabled_targets[scsi_id] = tstate; 285397883Sgibbs return (tstate); 285497883Sgibbs} 285597883Sgibbs 285697883Sgibbs#ifdef AHD_TARGET_MODE 285797883Sgibbs/* 285897883Sgibbs * Free per target mode instance (ID we respond to as a target) 285997883Sgibbs * transfer negotiation data structures. 286097883Sgibbs */ 286197883Sgibbsstatic void 286297883Sgibbsahd_free_tstate(struct ahd_softc *ahd, u_int scsi_id, char channel, int force) 286397883Sgibbs{ 286497883Sgibbs struct ahd_tmode_tstate *tstate; 286597883Sgibbs 286697883Sgibbs /* 286797883Sgibbs * Don't clean up our "master" tstate. 286897883Sgibbs * It has our default user settings. 286997883Sgibbs */ 287097883Sgibbs if (scsi_id == ahd->our_id 287197883Sgibbs && force == FALSE) 287297883Sgibbs return; 287397883Sgibbs 287497883Sgibbs tstate = ahd->enabled_targets[scsi_id]; 287597883Sgibbs if (tstate != NULL) 287697883Sgibbs free(tstate, M_DEVBUF); 287797883Sgibbs ahd->enabled_targets[scsi_id] = NULL; 287897883Sgibbs} 287997883Sgibbs#endif 288097883Sgibbs 288197883Sgibbs/* 288297883Sgibbs * Called when we have an active connection to a target on the bus, 288397883Sgibbs * this function finds the nearest period to the input period limited 288497883Sgibbs * by the capabilities of the bus connectivity of and sync settings for 288597883Sgibbs * the target. 288697883Sgibbs */ 288797883Sgibbsvoid 288897883Sgibbsahd_devlimited_syncrate(struct ahd_softc *ahd, 288997883Sgibbs struct ahd_initiator_tinfo *tinfo, 289097883Sgibbs u_int *period, u_int *ppr_options, role_t role) 289197883Sgibbs{ 289297883Sgibbs struct ahd_transinfo *transinfo; 289397883Sgibbs u_int maxsync; 289497883Sgibbs 289597883Sgibbs if ((ahd_inb(ahd, SBLKCTL) & ENAB40) != 0 289697883Sgibbs && (ahd_inb(ahd, SSTAT2) & EXP_ACTIVE) == 0) { 289797883Sgibbs maxsync = AHD_SYNCRATE_PACED; 289897883Sgibbs } else { 289997883Sgibbs maxsync = AHD_SYNCRATE_ULTRA; 290097883Sgibbs /* Can't do DT related options on an SE bus */ 290197883Sgibbs *ppr_options &= MSG_EXT_PPR_QAS_REQ; 290297883Sgibbs } 290397883Sgibbs /* 290497883Sgibbs * Never allow a value higher than our current goal 290597883Sgibbs * period otherwise we may allow a target initiated 290697883Sgibbs * negotiation to go above the limit as set by the 290797883Sgibbs * user. In the case of an initiator initiated 290897883Sgibbs * sync negotiation, we limit based on the user 290997883Sgibbs * setting. This allows the system to still accept 291097883Sgibbs * incoming negotiations even if target initiated 291197883Sgibbs * negotiation is not performed. 291297883Sgibbs */ 291397883Sgibbs if (role == ROLE_TARGET) 291497883Sgibbs transinfo = &tinfo->user; 291597883Sgibbs else 291697883Sgibbs transinfo = &tinfo->goal; 291797883Sgibbs *ppr_options &= (transinfo->ppr_options|MSG_EXT_PPR_PCOMP_EN); 2918109588Sgibbs if (transinfo->width == MSG_EXT_WDTR_BUS_8_BIT) { 2919107441Sscottl maxsync = MAX(maxsync, AHD_SYNCRATE_ULTRA2); 2920109588Sgibbs *ppr_options &= ~MSG_EXT_PPR_DT_REQ; 2921109588Sgibbs } 292297883Sgibbs if (transinfo->period == 0) { 292397883Sgibbs *period = 0; 292497883Sgibbs *ppr_options = 0; 292597883Sgibbs } else { 292697883Sgibbs *period = MAX(*period, transinfo->period); 292797883Sgibbs ahd_find_syncrate(ahd, period, ppr_options, maxsync); 292897883Sgibbs } 292997883Sgibbs} 293097883Sgibbs 293197883Sgibbs/* 293297883Sgibbs * Look up the valid period to SCSIRATE conversion in our table. 293397883Sgibbs * Return the period and offset that should be sent to the target 293497883Sgibbs * if this was the beginning of an SDTR. 293597883Sgibbs */ 293697883Sgibbsvoid 293797883Sgibbsahd_find_syncrate(struct ahd_softc *ahd, u_int *period, 293897883Sgibbs u_int *ppr_options, u_int maxsync) 293997883Sgibbs{ 294097883Sgibbs if (*period < maxsync) 294197883Sgibbs *period = maxsync; 294297883Sgibbs 294397883Sgibbs if ((*ppr_options & MSG_EXT_PPR_DT_REQ) != 0 294497883Sgibbs && *period > AHD_SYNCRATE_MIN_DT) 294597883Sgibbs *ppr_options &= ~MSG_EXT_PPR_DT_REQ; 294697883Sgibbs 294797883Sgibbs if (*period > AHD_SYNCRATE_MIN) 294897883Sgibbs *period = 0; 294997883Sgibbs 295097883Sgibbs /* Honor PPR option conformance rules. */ 2951107441Sscottl if (*period > AHD_SYNCRATE_PACED) 2952107441Sscottl *ppr_options &= ~MSG_EXT_PPR_RTI; 2953107441Sscottl 295497883Sgibbs if ((*ppr_options & MSG_EXT_PPR_IU_REQ) == 0) 295597883Sgibbs *ppr_options &= (MSG_EXT_PPR_DT_REQ|MSG_EXT_PPR_QAS_REQ); 295697883Sgibbs 295797883Sgibbs if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0) 295897883Sgibbs *ppr_options &= MSG_EXT_PPR_QAS_REQ; 2959109588Sgibbs 2960109588Sgibbs /* Skip all PACED only entries if IU is not available */ 2961109588Sgibbs if ((*ppr_options & MSG_EXT_PPR_IU_REQ) == 0 2962109588Sgibbs && *period < AHD_SYNCRATE_DT) 2963109588Sgibbs *period = AHD_SYNCRATE_DT; 2964109588Sgibbs 2965109588Sgibbs /* Skip all DT only entries if DT is not available */ 2966109588Sgibbs if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0 2967109588Sgibbs && *period < AHD_SYNCRATE_ULTRA2) 2968109588Sgibbs *period = AHD_SYNCRATE_ULTRA2; 296997883Sgibbs} 297097883Sgibbs 297197883Sgibbs/* 297297883Sgibbs * Truncate the given synchronous offset to a value the 297397883Sgibbs * current adapter type and syncrate are capable of. 297497883Sgibbs */ 297597883Sgibbsvoid 297697883Sgibbsahd_validate_offset(struct ahd_softc *ahd, 297797883Sgibbs struct ahd_initiator_tinfo *tinfo, 297897883Sgibbs u_int period, u_int *offset, int wide, 297997883Sgibbs role_t role) 298097883Sgibbs{ 298197883Sgibbs u_int maxoffset; 298297883Sgibbs 298397883Sgibbs /* Limit offset to what we can do */ 298497883Sgibbs if (period == 0) 298597883Sgibbs maxoffset = 0; 2986107441Sscottl else if (period <= AHD_SYNCRATE_PACED) { 2987107441Sscottl if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) 2988107441Sscottl maxoffset = MAX_OFFSET_PACED_BUG; 2989107441Sscottl else 2990107441Sscottl maxoffset = MAX_OFFSET_PACED; 2991107441Sscottl } else 2992107441Sscottl maxoffset = MAX_OFFSET_NON_PACED; 299397883Sgibbs *offset = MIN(*offset, maxoffset); 299497883Sgibbs if (tinfo != NULL) { 299597883Sgibbs if (role == ROLE_TARGET) 299697883Sgibbs *offset = MIN(*offset, tinfo->user.offset); 299797883Sgibbs else 299897883Sgibbs *offset = MIN(*offset, tinfo->goal.offset); 299997883Sgibbs } 300097883Sgibbs} 300197883Sgibbs 300297883Sgibbs/* 300397883Sgibbs * Truncate the given transfer width parameter to a value the 300497883Sgibbs * current adapter type is capable of. 300597883Sgibbs */ 300697883Sgibbsvoid 300797883Sgibbsahd_validate_width(struct ahd_softc *ahd, struct ahd_initiator_tinfo *tinfo, 300897883Sgibbs u_int *bus_width, role_t role) 300997883Sgibbs{ 301097883Sgibbs switch (*bus_width) { 301197883Sgibbs default: 301297883Sgibbs if (ahd->features & AHD_WIDE) { 301397883Sgibbs /* Respond Wide */ 301497883Sgibbs *bus_width = MSG_EXT_WDTR_BUS_16_BIT; 301597883Sgibbs break; 301697883Sgibbs } 301797883Sgibbs /* FALLTHROUGH */ 301897883Sgibbs case MSG_EXT_WDTR_BUS_8_BIT: 301997883Sgibbs *bus_width = MSG_EXT_WDTR_BUS_8_BIT; 302097883Sgibbs break; 302197883Sgibbs } 302297883Sgibbs if (tinfo != NULL) { 302397883Sgibbs if (role == ROLE_TARGET) 302497883Sgibbs *bus_width = MIN(tinfo->user.width, *bus_width); 302597883Sgibbs else 302697883Sgibbs *bus_width = MIN(tinfo->goal.width, *bus_width); 302797883Sgibbs } 302897883Sgibbs} 302997883Sgibbs 303097883Sgibbs/* 303197883Sgibbs * Update the bitmask of targets for which the controller should 303297883Sgibbs * negotiate with at the next convenient oportunity. This currently 303397883Sgibbs * means the next time we send the initial identify messages for 303497883Sgibbs * a new transaction. 303597883Sgibbs */ 303697883Sgibbsint 303797883Sgibbsahd_update_neg_request(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 303897883Sgibbs struct ahd_tmode_tstate *tstate, 3039107441Sscottl struct ahd_initiator_tinfo *tinfo, ahd_neg_type neg_type) 304097883Sgibbs{ 304197883Sgibbs u_int auto_negotiate_orig; 304297883Sgibbs 304397883Sgibbs auto_negotiate_orig = tstate->auto_negotiate; 3044107441Sscottl if (neg_type == AHD_NEG_ALWAYS) { 3045107441Sscottl /* 3046107441Sscottl * Force our "current" settings to be 3047107441Sscottl * unknown so that unless a bus reset 3048107441Sscottl * occurs the need to renegotiate is 3049107441Sscottl * recorded persistently. 3050107441Sscottl */ 3051109588Sgibbs if ((ahd->features & AHD_WIDE) != 0) 3052109588Sgibbs tinfo->curr.width = AHD_WIDTH_UNKNOWN; 3053107441Sscottl tinfo->curr.period = AHD_PERIOD_UNKNOWN; 3054107441Sscottl tinfo->curr.offset = AHD_OFFSET_UNKNOWN; 3055107441Sscottl } 305697883Sgibbs if (tinfo->curr.period != tinfo->goal.period 305797883Sgibbs || tinfo->curr.width != tinfo->goal.width 305897883Sgibbs || tinfo->curr.offset != tinfo->goal.offset 305997883Sgibbs || tinfo->curr.ppr_options != tinfo->goal.ppr_options 3060107441Sscottl || (neg_type == AHD_NEG_IF_NON_ASYNC 3061107441Sscottl && (tinfo->goal.offset != 0 306297883Sgibbs || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT 306397883Sgibbs || tinfo->goal.ppr_options != 0))) 306497883Sgibbs tstate->auto_negotiate |= devinfo->target_mask; 306597883Sgibbs else 306697883Sgibbs tstate->auto_negotiate &= ~devinfo->target_mask; 306797883Sgibbs 306897883Sgibbs return (auto_negotiate_orig != tstate->auto_negotiate); 306997883Sgibbs} 307097883Sgibbs 307197883Sgibbs/* 307297883Sgibbs * Update the user/goal/curr tables of synchronous negotiation 307397883Sgibbs * parameters as well as, in the case of a current or active update, 307497883Sgibbs * any data structures on the host controller. In the case of an 307597883Sgibbs * active update, the specified target is currently talking to us on 307697883Sgibbs * the bus, so the transfer parameter update must take effect 307797883Sgibbs * immediately. 307897883Sgibbs */ 307997883Sgibbsvoid 308097883Sgibbsahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 308197883Sgibbs u_int period, u_int offset, u_int ppr_options, 308297883Sgibbs u_int type, int paused) 308397883Sgibbs{ 308497883Sgibbs struct ahd_initiator_tinfo *tinfo; 308597883Sgibbs struct ahd_tmode_tstate *tstate; 308697883Sgibbs u_int old_period; 308797883Sgibbs u_int old_offset; 308897883Sgibbs u_int old_ppr; 308997883Sgibbs int active; 309097883Sgibbs int update_needed; 309197883Sgibbs 309297883Sgibbs active = (type & AHD_TRANS_ACTIVE) == AHD_TRANS_ACTIVE; 309397883Sgibbs update_needed = 0; 309497883Sgibbs 309597883Sgibbs if (period == 0 || offset == 0) { 309697883Sgibbs period = 0; 309797883Sgibbs offset = 0; 309897883Sgibbs } 309997883Sgibbs 310097883Sgibbs tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid, 310197883Sgibbs devinfo->target, &tstate); 310297883Sgibbs 310397883Sgibbs if ((type & AHD_TRANS_USER) != 0) { 310497883Sgibbs tinfo->user.period = period; 310597883Sgibbs tinfo->user.offset = offset; 310697883Sgibbs tinfo->user.ppr_options = ppr_options; 310797883Sgibbs } 310897883Sgibbs 310997883Sgibbs if ((type & AHD_TRANS_GOAL) != 0) { 311097883Sgibbs tinfo->goal.period = period; 311197883Sgibbs tinfo->goal.offset = offset; 311297883Sgibbs tinfo->goal.ppr_options = ppr_options; 311397883Sgibbs } 311497883Sgibbs 311597883Sgibbs old_period = tinfo->curr.period; 311697883Sgibbs old_offset = tinfo->curr.offset; 311797883Sgibbs old_ppr = tinfo->curr.ppr_options; 311897883Sgibbs 311997883Sgibbs if ((type & AHD_TRANS_CUR) != 0 312097883Sgibbs && (old_period != period 312197883Sgibbs || old_offset != offset 312297883Sgibbs || old_ppr != ppr_options)) { 312397883Sgibbs 312497883Sgibbs update_needed++; 312597883Sgibbs 312697883Sgibbs tinfo->curr.period = period; 312797883Sgibbs tinfo->curr.offset = offset; 312897883Sgibbs tinfo->curr.ppr_options = ppr_options; 312997883Sgibbs 313097883Sgibbs ahd_send_async(ahd, devinfo->channel, devinfo->target, 313197883Sgibbs CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); 313297883Sgibbs if (bootverbose) { 313397883Sgibbs if (offset != 0) { 3134109588Sgibbs int options; 3135109588Sgibbs 313697883Sgibbs printf("%s: target %d synchronous with " 3137109588Sgibbs "period = 0x%x, offset = 0x%x", 313897883Sgibbs ahd_name(ahd), devinfo->target, 3139109588Sgibbs period, offset); 3140109588Sgibbs options = 0; 3141111954Sgibbs if ((ppr_options & MSG_EXT_PPR_RD_STRM) != 0) { 3142111954Sgibbs printf("(RDSTRM"); 3143111954Sgibbs options++; 3144111954Sgibbs } 3145109588Sgibbs if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) { 3146111954Sgibbs printf("%s", options ? "|DT" : "(DT"); 3147109588Sgibbs options++; 3148109588Sgibbs } 3149109588Sgibbs if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { 3150109588Sgibbs printf("%s", options ? "|IU" : "(IU"); 3151109588Sgibbs options++; 3152109588Sgibbs } 3153109588Sgibbs if ((ppr_options & MSG_EXT_PPR_RTI) != 0) { 3154109588Sgibbs printf("%s", options ? "|RTI" : "(RTI"); 3155109588Sgibbs options++; 3156109588Sgibbs } 3157109588Sgibbs if ((ppr_options & MSG_EXT_PPR_QAS_REQ) != 0) { 3158109588Sgibbs printf("%s", options ? "|QAS" : "(QAS"); 3159109588Sgibbs options++; 3160109588Sgibbs } 3161109588Sgibbs if (options != 0) 3162109588Sgibbs printf(")\n"); 3163109588Sgibbs else 3164109588Sgibbs printf("\n"); 316597883Sgibbs } else { 316697883Sgibbs printf("%s: target %d using " 3167109588Sgibbs "asynchronous transfers%s\n", 3168109588Sgibbs ahd_name(ahd), devinfo->target, 3169109588Sgibbs (ppr_options & MSG_EXT_PPR_QAS_REQ) != 0 3170109588Sgibbs ? "(QAS)" : ""); 317197883Sgibbs } 317297883Sgibbs } 317397883Sgibbs } 317497883Sgibbs /* 317597883Sgibbs * Always refresh the neg-table to handle the case of the 317697883Sgibbs * sequencer setting the ENATNO bit for a MK_MESSAGE request. 317797883Sgibbs * We will always renegotiate in that case if this is a 3178102679Sgibbs * packetized request. Also manage the busfree expected flag 3179102679Sgibbs * from this common routine so that we catch changes due to 3180102679Sgibbs * WDTR or SDTR messages. 318197883Sgibbs */ 3182102679Sgibbs if ((type & AHD_TRANS_CUR) != 0) { 3183102679Sgibbs if (!paused) 3184102679Sgibbs ahd_pause(ahd); 318597883Sgibbs ahd_update_neg_table(ahd, devinfo, &tinfo->curr); 3186102679Sgibbs if (!paused) 3187102679Sgibbs ahd_unpause(ahd); 3188102679Sgibbs if (ahd->msg_type != MSG_TYPE_NONE) { 3189102679Sgibbs if ((old_ppr & MSG_EXT_PPR_IU_REQ) 3190102679Sgibbs != (ppr_options & MSG_EXT_PPR_IU_REQ)) { 3191102679Sgibbs#ifdef AHD_DEBUG 3192107441Sscottl if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { 3193107441Sscottl ahd_print_devinfo(ahd, devinfo); 3194102679Sgibbs printf("Expecting IU Change busfree\n"); 3195107441Sscottl } 3196102679Sgibbs#endif 3197102679Sgibbs ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE 3198102679Sgibbs | MSG_FLAG_IU_REQ_CHANGED; 3199102679Sgibbs } 3200102679Sgibbs if ((old_ppr & MSG_EXT_PPR_IU_REQ) != 0) { 3201102679Sgibbs#ifdef AHD_DEBUG 3202102679Sgibbs if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 3203102679Sgibbs printf("PPR with IU_REQ outstanding\n"); 3204102679Sgibbs#endif 3205102679Sgibbs ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE; 3206102679Sgibbs } 3207102679Sgibbs } 3208102679Sgibbs } 320997883Sgibbs 321097883Sgibbs update_needed += ahd_update_neg_request(ahd, devinfo, tstate, 3211107441Sscottl tinfo, AHD_NEG_TO_GOAL); 321297883Sgibbs 3213102679Sgibbs if (update_needed && active) 321497883Sgibbs ahd_update_pending_scbs(ahd); 321597883Sgibbs} 321697883Sgibbs 321797883Sgibbs/* 321897883Sgibbs * Update the user/goal/curr tables of wide negotiation 321997883Sgibbs * parameters as well as, in the case of a current or active update, 322097883Sgibbs * any data structures on the host controller. In the case of an 322197883Sgibbs * active update, the specified target is currently talking to us on 322297883Sgibbs * the bus, so the transfer parameter update must take effect 322397883Sgibbs * immediately. 322497883Sgibbs */ 322597883Sgibbsvoid 322697883Sgibbsahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 322797883Sgibbs u_int width, u_int type, int paused) 322897883Sgibbs{ 322997883Sgibbs struct ahd_initiator_tinfo *tinfo; 323097883Sgibbs struct ahd_tmode_tstate *tstate; 323197883Sgibbs u_int oldwidth; 323297883Sgibbs int active; 323397883Sgibbs int update_needed; 323497883Sgibbs 323597883Sgibbs active = (type & AHD_TRANS_ACTIVE) == AHD_TRANS_ACTIVE; 323697883Sgibbs update_needed = 0; 323797883Sgibbs tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid, 323897883Sgibbs devinfo->target, &tstate); 323997883Sgibbs 324097883Sgibbs if ((type & AHD_TRANS_USER) != 0) 324197883Sgibbs tinfo->user.width = width; 324297883Sgibbs 324397883Sgibbs if ((type & AHD_TRANS_GOAL) != 0) 324497883Sgibbs tinfo->goal.width = width; 324597883Sgibbs 324697883Sgibbs oldwidth = tinfo->curr.width; 324797883Sgibbs if ((type & AHD_TRANS_CUR) != 0 && oldwidth != width) { 324897883Sgibbs 324997883Sgibbs update_needed++; 325097883Sgibbs 325197883Sgibbs tinfo->curr.width = width; 325297883Sgibbs ahd_send_async(ahd, devinfo->channel, devinfo->target, 325397883Sgibbs CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); 325497883Sgibbs if (bootverbose) { 325597883Sgibbs printf("%s: target %d using %dbit transfers\n", 325697883Sgibbs ahd_name(ahd), devinfo->target, 325797883Sgibbs 8 * (0x01 << width)); 325897883Sgibbs } 325997883Sgibbs } 3260102679Sgibbs 3261102679Sgibbs if ((type & AHD_TRANS_CUR) != 0) { 3262102679Sgibbs if (!paused) 3263102679Sgibbs ahd_pause(ahd); 326497883Sgibbs ahd_update_neg_table(ahd, devinfo, &tinfo->curr); 3265102679Sgibbs if (!paused) 3266102679Sgibbs ahd_unpause(ahd); 3267102679Sgibbs } 326897883Sgibbs 326997883Sgibbs update_needed += ahd_update_neg_request(ahd, devinfo, tstate, 3270107441Sscottl tinfo, AHD_NEG_TO_GOAL); 3271102679Sgibbs if (update_needed && active) 327297883Sgibbs ahd_update_pending_scbs(ahd); 3273102679Sgibbs 327497883Sgibbs} 327597883Sgibbs 327697883Sgibbs/* 327797883Sgibbs * Update the current state of tagged queuing for a given target. 327897883Sgibbs */ 327997883Sgibbsvoid 328097883Sgibbsahd_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 328197883Sgibbs ahd_queue_alg alg) 328297883Sgibbs{ 3283109588Sgibbs ahd_platform_set_tags(ahd, devinfo, alg); 3284109588Sgibbs ahd_send_async(ahd, devinfo->channel, devinfo->target, 3285109588Sgibbs devinfo->lun, AC_TRANSFER_NEG, &alg); 328697883Sgibbs} 328797883Sgibbs 328897883Sgibbsstatic void 328997883Sgibbsahd_update_neg_table(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 329097883Sgibbs struct ahd_transinfo *tinfo) 329197883Sgibbs{ 329297883Sgibbs ahd_mode_state saved_modes; 329397883Sgibbs u_int period; 329497883Sgibbs u_int ppr_opts; 329597883Sgibbs u_int con_opts; 329697883Sgibbs u_int offset; 3297109588Sgibbs u_int saved_negoaddr; 3298107441Sscottl uint8_t iocell_opts[sizeof(ahd->iocell_opts)]; 329997883Sgibbs 330097883Sgibbs saved_modes = ahd_save_modes(ahd); 330197883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 330297883Sgibbs 3303109588Sgibbs saved_negoaddr = ahd_inb(ahd, NEGOADDR); 330497883Sgibbs ahd_outb(ahd, NEGOADDR, devinfo->target); 330597883Sgibbs period = tinfo->period; 330697883Sgibbs offset = tinfo->offset; 3307107441Sscottl memcpy(iocell_opts, ahd->iocell_opts, sizeof(ahd->iocell_opts)); 3308107441Sscottl ppr_opts = tinfo->ppr_options & (MSG_EXT_PPR_QAS_REQ|MSG_EXT_PPR_DT_REQ 3309107441Sscottl |MSG_EXT_PPR_IU_REQ|MSG_EXT_PPR_RTI); 3310107441Sscottl con_opts = 0; 331197883Sgibbs if (period == 0) 331297883Sgibbs period = AHD_SYNCRATE_ASYNC; 331397883Sgibbs if (period == AHD_SYNCRATE_160) { 3314107441Sscottl 3315107441Sscottl if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) { 3316107441Sscottl /* 3317107441Sscottl * When the SPI4 spec was finalized, PACE transfers 3318107441Sscottl * was not made a configurable option in the PPR 3319107441Sscottl * message. Instead it is assumed to be enabled for 3320107441Sscottl * any syncrate faster than 80MHz. Nevertheless, 3321107441Sscottl * Harpoon2A4 allows this to be configurable. 3322107441Sscottl * 3323107441Sscottl * Harpoon2A4 also assumes at most 2 data bytes per 3324107441Sscottl * negotiated REQ/ACK offset. Paced transfers take 3325107441Sscottl * 4, so we must adjust our offset. 3326107441Sscottl */ 3327107441Sscottl ppr_opts |= PPROPT_PACE; 3328107441Sscottl offset *= 2; 3329107441Sscottl 3330107441Sscottl /* 3331107441Sscottl * Harpoon2A assumed that there would be a 3332107441Sscottl * fallback rate between 160MHz and 80Mhz, 3333107441Sscottl * so 7 is used as the period factor rather 3334107441Sscottl * than 8 for 160MHz. 3335107441Sscottl */ 3336107441Sscottl period = AHD_SYNCRATE_REVA_160; 3337107441Sscottl } 3338107441Sscottl if ((tinfo->ppr_options & MSG_EXT_PPR_PCOMP_EN) == 0) 3339107441Sscottl iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= 3340107441Sscottl ~AHD_PRECOMP_MASK; 3341107441Sscottl } else { 3342107441Sscottl /* 3343107441Sscottl * Precomp should be disabled for non-paced transfers. 3344107441Sscottl */ 3345107441Sscottl iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= ~AHD_PRECOMP_MASK; 3346107441Sscottl 3347107441Sscottl if ((ahd->features & AHD_NEW_IOCELL_OPTS) != 0 3348123579Sgibbs && (ppr_opts & MSG_EXT_PPR_DT_REQ) != 0 3349123579Sgibbs && (ppr_opts & MSG_EXT_PPR_IU_REQ) == 0) { 3350107441Sscottl /* 3351107441Sscottl * Slow down our CRC interval to be 3352123579Sgibbs * compatible with non-packetized 3353123579Sgibbs * U160 devices that can't handle a 3354123579Sgibbs * CRC at full speed. 3355107441Sscottl */ 3356107441Sscottl con_opts |= ENSLOWCRC; 3357107441Sscottl } 3358123579Sgibbs 3359123579Sgibbs if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) { 3360123579Sgibbs /* 3361123579Sgibbs * On H2A4, revert to a slower slewrate 3362123579Sgibbs * on non-paced transfers. 3363123579Sgibbs */ 3364123579Sgibbs iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= 3365123579Sgibbs ~AHD_SLEWRATE_MASK; 3366123579Sgibbs } 336797883Sgibbs } 336897883Sgibbs 3369107441Sscottl ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PRECOMP_SLEW); 3370107441Sscottl ahd_outb(ahd, ANNEXDAT, iocell_opts[AHD_PRECOMP_SLEW_INDEX]); 3371107441Sscottl ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_AMPLITUDE); 3372107441Sscottl ahd_outb(ahd, ANNEXDAT, iocell_opts[AHD_AMPLITUDE_INDEX]); 3373107441Sscottl 337497883Sgibbs ahd_outb(ahd, NEGPERIOD, period); 337597883Sgibbs ahd_outb(ahd, NEGPPROPTS, ppr_opts); 337697883Sgibbs ahd_outb(ahd, NEGOFFSET, offset); 337797883Sgibbs 337897883Sgibbs if (tinfo->width == MSG_EXT_WDTR_BUS_16_BIT) 337997883Sgibbs con_opts |= WIDEXFER; 338097883Sgibbs 338197883Sgibbs /* 338297883Sgibbs * During packetized transfers, the target will 338397883Sgibbs * give us the oportunity to send command packets 338497883Sgibbs * without us asserting attention. 338597883Sgibbs */ 338697883Sgibbs if ((tinfo->ppr_options & MSG_EXT_PPR_IU_REQ) == 0) 338797883Sgibbs con_opts |= ENAUTOATNO; 338897883Sgibbs ahd_outb(ahd, NEGCONOPTS, con_opts); 3389109588Sgibbs ahd_outb(ahd, NEGOADDR, saved_negoaddr); 339097883Sgibbs ahd_restore_modes(ahd, saved_modes); 339197883Sgibbs} 339297883Sgibbs 339397883Sgibbs/* 3394102679Sgibbs * When the transfer settings for a connection change, setup for 3395102679Sgibbs * negotiation in pending SCBs to effect the change as quickly as 3396102679Sgibbs * possible. We also cancel any negotiations that are scheduled 3397102679Sgibbs * for inflight SCBs that have not been started yet. 339897883Sgibbs */ 339997883Sgibbsstatic void 340097883Sgibbsahd_update_pending_scbs(struct ahd_softc *ahd) 340197883Sgibbs{ 340297883Sgibbs struct scb *pending_scb; 340397883Sgibbs int pending_scb_count; 340497883Sgibbs int paused; 340597883Sgibbs u_int saved_scbptr; 340697883Sgibbs ahd_mode_state saved_modes; 340797883Sgibbs 340897883Sgibbs /* 340997883Sgibbs * Traverse the pending SCB list and ensure that all of the 3410102679Sgibbs * SCBs there have the proper settings. We can only safely 3411102679Sgibbs * clear the negotiation required flag (setting requires the 3412102679Sgibbs * execution queue to be modified) and this is only possible 3413102679Sgibbs * if we are not already attempting to select out for this 3414102679Sgibbs * SCB. For this reason, all callers only call this routine 3415102679Sgibbs * if we are changing the negotiation settings for the currently 3416102679Sgibbs * active transaction on the bus. 341797883Sgibbs */ 341897883Sgibbs pending_scb_count = 0; 341997883Sgibbs LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) { 342097883Sgibbs struct ahd_devinfo devinfo; 342197883Sgibbs struct ahd_initiator_tinfo *tinfo; 342297883Sgibbs struct ahd_tmode_tstate *tstate; 342397883Sgibbs 342497883Sgibbs ahd_scb_devinfo(ahd, &devinfo, pending_scb); 342597883Sgibbs tinfo = ahd_fetch_transinfo(ahd, devinfo.channel, 342697883Sgibbs devinfo.our_scsiid, 342797883Sgibbs devinfo.target, &tstate); 342897883Sgibbs if ((tstate->auto_negotiate & devinfo.target_mask) == 0 342997883Sgibbs && (pending_scb->flags & SCB_AUTO_NEGOTIATE) != 0) { 343097883Sgibbs pending_scb->flags &= ~SCB_AUTO_NEGOTIATE; 3431133122Sgibbs pending_scb->hscb->control &= ~MK_MESSAGE; 343297883Sgibbs } 343397883Sgibbs ahd_sync_scb(ahd, pending_scb, 343497883Sgibbs BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 343597883Sgibbs pending_scb_count++; 343697883Sgibbs } 343797883Sgibbs 343897883Sgibbs if (pending_scb_count == 0) 343997883Sgibbs return; 344097883Sgibbs 344197883Sgibbs if (ahd_is_paused(ahd)) { 344297883Sgibbs paused = 1; 344397883Sgibbs } else { 344497883Sgibbs paused = 0; 344597883Sgibbs ahd_pause(ahd); 344697883Sgibbs } 344797883Sgibbs 3448102679Sgibbs /* 3449102679Sgibbs * Force the sequencer to reinitialize the selection for 3450102679Sgibbs * the command at the head of the execution queue if it 3451102679Sgibbs * has already been setup. The negotiation changes may 3452129134Sgibbs * effect whether we select-out with ATN. It is only 3453129134Sgibbs * safe to clear ENSELO when the bus is not free and no 3454129134Sgibbs * selection is in progres or completed. 3455102679Sgibbs */ 345697883Sgibbs saved_modes = ahd_save_modes(ahd); 345797883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 3458129134Sgibbs if ((ahd_inb(ahd, SCSISIGI) & BSYI) != 0 3459129134Sgibbs && (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) == 0) 3460129134Sgibbs ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO); 346197883Sgibbs saved_scbptr = ahd_get_scbptr(ahd); 346297883Sgibbs /* Ensure that the hscbs down on the card match the new information */ 3463133122Sgibbs LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) { 3464133122Sgibbs u_int scb_tag; 346597883Sgibbs u_int control; 346697883Sgibbs 3467133122Sgibbs scb_tag = SCB_GET_TAG(pending_scb); 3468116938Sgibbs ahd_set_scbptr(ahd, scb_tag); 346997883Sgibbs control = ahd_inb_scbram(ahd, SCB_CONTROL); 347097883Sgibbs control &= ~MK_MESSAGE; 3471133122Sgibbs control |= pending_scb->hscb->control & MK_MESSAGE; 347297883Sgibbs ahd_outb(ahd, SCB_CONTROL, control); 347397883Sgibbs } 3474104023Sgibbs ahd_set_scbptr(ahd, saved_scbptr); 347597883Sgibbs ahd_restore_modes(ahd, saved_modes); 347697883Sgibbs 347797883Sgibbs if (paused == 0) 347897883Sgibbs ahd_unpause(ahd); 347997883Sgibbs} 348097883Sgibbs 348197883Sgibbs/**************************** Pathing Information *****************************/ 348297883Sgibbsstatic void 348397883Sgibbsahd_fetch_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) 348497883Sgibbs{ 348597883Sgibbs ahd_mode_state saved_modes; 348697883Sgibbs u_int saved_scsiid; 348797883Sgibbs role_t role; 348897883Sgibbs int our_id; 348997883Sgibbs 349097883Sgibbs saved_modes = ahd_save_modes(ahd); 349197883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 349297883Sgibbs 349397883Sgibbs if (ahd_inb(ahd, SSTAT0) & TARGET) 349497883Sgibbs role = ROLE_TARGET; 349597883Sgibbs else 349697883Sgibbs role = ROLE_INITIATOR; 349797883Sgibbs 349897883Sgibbs if (role == ROLE_TARGET 349997883Sgibbs && (ahd_inb(ahd, SEQ_FLAGS) & CMDPHASE_PENDING) != 0) { 350097883Sgibbs /* We were selected, so pull our id from TARGIDIN */ 350197883Sgibbs our_id = ahd_inb(ahd, TARGIDIN) & OID; 350297883Sgibbs } else if (role == ROLE_TARGET) 350397883Sgibbs our_id = ahd_inb(ahd, TOWNID); 350497883Sgibbs else 350597883Sgibbs our_id = ahd_inb(ahd, IOWNID); 350697883Sgibbs 350797883Sgibbs saved_scsiid = ahd_inb(ahd, SAVED_SCSIID); 350897883Sgibbs ahd_compile_devinfo(devinfo, 350997883Sgibbs our_id, 351097883Sgibbs SCSIID_TARGET(ahd, saved_scsiid), 351197883Sgibbs ahd_inb(ahd, SAVED_LUN), 351297883Sgibbs SCSIID_CHANNEL(ahd, saved_scsiid), 351397883Sgibbs role); 351497883Sgibbs ahd_restore_modes(ahd, saved_modes); 351597883Sgibbs} 351697883Sgibbs 3517107441Sscottlvoid 3518102679Sgibbsahd_print_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) 3519102679Sgibbs{ 3520107441Sscottl printf("%s:%c:%d:%d: ", ahd_name(ahd), 'A', 3521102679Sgibbs devinfo->target, devinfo->lun); 3522102679Sgibbs} 3523102679Sgibbs 352497883Sgibbsstruct ahd_phase_table_entry* 352597883Sgibbsahd_lookup_phase_entry(int phase) 352697883Sgibbs{ 352797883Sgibbs struct ahd_phase_table_entry *entry; 352897883Sgibbs struct ahd_phase_table_entry *last_entry; 352997883Sgibbs 353097883Sgibbs /* 353197883Sgibbs * num_phases doesn't include the default entry which 353297883Sgibbs * will be returned if the phase doesn't match. 353397883Sgibbs */ 353497883Sgibbs last_entry = &ahd_phase_table[num_phases]; 353597883Sgibbs for (entry = ahd_phase_table; entry < last_entry; entry++) { 353697883Sgibbs if (phase == entry->phase) 353797883Sgibbs break; 353897883Sgibbs } 353997883Sgibbs return (entry); 354097883Sgibbs} 354197883Sgibbs 354297883Sgibbsvoid 354397883Sgibbsahd_compile_devinfo(struct ahd_devinfo *devinfo, u_int our_id, u_int target, 354497883Sgibbs u_int lun, char channel, role_t role) 354597883Sgibbs{ 354697883Sgibbs devinfo->our_scsiid = our_id; 354797883Sgibbs devinfo->target = target; 354897883Sgibbs devinfo->lun = lun; 354997883Sgibbs devinfo->target_offset = target; 355097883Sgibbs devinfo->channel = channel; 355197883Sgibbs devinfo->role = role; 355297883Sgibbs if (channel == 'B') 355397883Sgibbs devinfo->target_offset += 8; 355497883Sgibbs devinfo->target_mask = (0x01 << devinfo->target_offset); 355597883Sgibbs} 355697883Sgibbs 355797883Sgibbsstatic void 355897883Sgibbsahd_scb_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 355997883Sgibbs struct scb *scb) 356097883Sgibbs{ 356197883Sgibbs role_t role; 356297883Sgibbs int our_id; 356397883Sgibbs 356497883Sgibbs our_id = SCSIID_OUR_ID(scb->hscb->scsiid); 356597883Sgibbs role = ROLE_INITIATOR; 356697883Sgibbs if ((scb->hscb->control & TARGET_SCB) != 0) 356797883Sgibbs role = ROLE_TARGET; 356897883Sgibbs ahd_compile_devinfo(devinfo, our_id, SCB_GET_TARGET(ahd, scb), 356997883Sgibbs SCB_GET_LUN(scb), SCB_GET_CHANNEL(ahd, scb), role); 357097883Sgibbs} 357197883Sgibbs 357297883Sgibbs 357397883Sgibbs/************************ Message Phase Processing ****************************/ 357497883Sgibbs/* 357597883Sgibbs * When an initiator transaction with the MK_MESSAGE flag either reconnects 357697883Sgibbs * or enters the initial message out phase, we are interrupted. Fill our 357797883Sgibbs * outgoing message buffer with the appropriate message and beging handing 357897883Sgibbs * the message phase(s) manually. 357997883Sgibbs */ 358097883Sgibbsstatic void 358197883Sgibbsahd_setup_initiator_msgout(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 358297883Sgibbs struct scb *scb) 358397883Sgibbs{ 358497883Sgibbs /* 358597883Sgibbs * To facilitate adding multiple messages together, 358697883Sgibbs * each routine should increment the index and len 358797883Sgibbs * variables instead of setting them explicitly. 358897883Sgibbs */ 358997883Sgibbs ahd->msgout_index = 0; 359097883Sgibbs ahd->msgout_len = 0; 359197883Sgibbs 359297883Sgibbs if (ahd_currently_packetized(ahd)) 359397883Sgibbs ahd->msg_flags |= MSG_FLAG_PACKETIZED; 359497883Sgibbs 359597883Sgibbs if (ahd->send_msg_perror 359697883Sgibbs && ahd_inb(ahd, MSG_OUT) == HOST_MSG) { 359797883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = ahd->send_msg_perror; 359897883Sgibbs ahd->msgout_len++; 359997883Sgibbs ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; 3600107441Sscottl#ifdef AHD_DEBUG 3601107441Sscottl if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 3602107441Sscottl printf("Setting up for Parity Error delivery\n"); 3603107441Sscottl#endif 360497883Sgibbs return; 360597883Sgibbs } else if (scb == NULL) { 360697883Sgibbs printf("%s: WARNING. No pending message for " 360797883Sgibbs "I_T msgin. Issuing NO-OP\n", ahd_name(ahd)); 3608199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 360997883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = MSG_NOOP; 361097883Sgibbs ahd->msgout_len++; 361197883Sgibbs ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; 361297883Sgibbs return; 361397883Sgibbs } 361497883Sgibbs 361597883Sgibbs if ((scb->flags & SCB_DEVICE_RESET) == 0 361697883Sgibbs && (scb->flags & SCB_PACKETIZED) == 0 361797883Sgibbs && ahd_inb(ahd, MSG_OUT) == MSG_IDENTIFYFLAG) { 361897883Sgibbs u_int identify_msg; 361997883Sgibbs 362097883Sgibbs identify_msg = MSG_IDENTIFYFLAG | SCB_GET_LUN(scb); 362197883Sgibbs if ((scb->hscb->control & DISCENB) != 0) 362297883Sgibbs identify_msg |= MSG_IDENTIFY_DISCFLAG; 362397883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = identify_msg; 362497883Sgibbs ahd->msgout_len++; 362597883Sgibbs 362697883Sgibbs if ((scb->hscb->control & TAG_ENB) != 0) { 362797883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = 362897883Sgibbs scb->hscb->control & (TAG_ENB|SCB_TAG_TYPE); 362997883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = SCB_GET_TAG(scb); 363097883Sgibbs ahd->msgout_len += 2; 363197883Sgibbs } 363297883Sgibbs } 363397883Sgibbs 363497883Sgibbs if (scb->flags & SCB_DEVICE_RESET) { 363597883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = MSG_BUS_DEV_RESET; 363697883Sgibbs ahd->msgout_len++; 363797883Sgibbs ahd_print_path(ahd, scb); 363897883Sgibbs printf("Bus Device Reset Message Sent\n"); 3639199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 364097883Sgibbs /* 364197883Sgibbs * Clear our selection hardware in advance of 364297883Sgibbs * the busfree. We may have an entry in the waiting 364397883Sgibbs * Q for this target, and we don't want to go about 364497883Sgibbs * selecting while we handle the busfree and blow it 364597883Sgibbs * away. 364697883Sgibbs */ 364797883Sgibbs ahd_outb(ahd, SCSISEQ0, 0); 364897883Sgibbs } else if ((scb->flags & SCB_ABORT) != 0) { 364997883Sgibbs 365097883Sgibbs if ((scb->hscb->control & TAG_ENB) != 0) { 365197883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = MSG_ABORT_TAG; 365297883Sgibbs } else { 365397883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = MSG_ABORT; 365497883Sgibbs } 365597883Sgibbs ahd->msgout_len++; 365697883Sgibbs ahd_print_path(ahd, scb); 365797883Sgibbs printf("Abort%s Message Sent\n", 365897883Sgibbs (scb->hscb->control & TAG_ENB) != 0 ? " Tag" : ""); 3659199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 366097883Sgibbs /* 366197883Sgibbs * Clear our selection hardware in advance of 366297883Sgibbs * the busfree. We may have an entry in the waiting 366397883Sgibbs * Q for this target, and we don't want to go about 366497883Sgibbs * selecting while we handle the busfree and blow it 366597883Sgibbs * away. 366697883Sgibbs */ 366797883Sgibbs ahd_outb(ahd, SCSISEQ0, 0); 366897883Sgibbs } else if ((scb->flags & (SCB_AUTO_NEGOTIATE|SCB_NEGOTIATE)) != 0) { 366997883Sgibbs ahd_build_transfer_msg(ahd, devinfo); 367097883Sgibbs /* 367197883Sgibbs * Clear our selection hardware in advance of potential 367297883Sgibbs * PPR IU status change busfree. We may have an entry in 367397883Sgibbs * the waiting Q for this target, and we don't want to go 367497883Sgibbs * about selecting while we handle the busfree and blow 367597883Sgibbs * it away. 367697883Sgibbs */ 367797883Sgibbs ahd_outb(ahd, SCSISEQ0, 0); 367897883Sgibbs } else { 367997883Sgibbs printf("ahd_intr: AWAITING_MSG for an SCB that " 368097883Sgibbs "does not have a waiting message\n"); 368197883Sgibbs printf("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid, 368297883Sgibbs devinfo->target_mask); 3683199260Sattilio AHD_FATAL_ERROR(ahd); 3684109588Sgibbs panic("SCB = %d, SCB Control = %x:%x, MSG_OUT = %x " 368597883Sgibbs "SCB flags = %x", SCB_GET_TAG(scb), scb->hscb->control, 3686116940Sgibbs ahd_inb_scbram(ahd, SCB_CONTROL), ahd_inb(ahd, MSG_OUT), 3687109588Sgibbs scb->flags); 368897883Sgibbs } 368997883Sgibbs 369097883Sgibbs /* 369197883Sgibbs * Clear the MK_MESSAGE flag from the SCB so we aren't 369297883Sgibbs * asked to send this message again. 369397883Sgibbs */ 369497883Sgibbs ahd_outb(ahd, SCB_CONTROL, 369597883Sgibbs ahd_inb_scbram(ahd, SCB_CONTROL) & ~MK_MESSAGE); 369697883Sgibbs scb->hscb->control &= ~MK_MESSAGE; 369797883Sgibbs ahd->msgout_index = 0; 369897883Sgibbs ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; 369997883Sgibbs} 370097883Sgibbs 370197883Sgibbs/* 370297883Sgibbs * Build an appropriate transfer negotiation message for the 370397883Sgibbs * currently active target. 370497883Sgibbs */ 370597883Sgibbsstatic void 370697883Sgibbsahd_build_transfer_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) 370797883Sgibbs{ 370897883Sgibbs /* 370997883Sgibbs * We need to initiate transfer negotiations. 371097883Sgibbs * If our current and goal settings are identical, 371197883Sgibbs * we want to renegotiate due to a check condition. 371297883Sgibbs */ 371397883Sgibbs struct ahd_initiator_tinfo *tinfo; 371497883Sgibbs struct ahd_tmode_tstate *tstate; 371597883Sgibbs int dowide; 371697883Sgibbs int dosync; 371797883Sgibbs int doppr; 371897883Sgibbs u_int period; 371997883Sgibbs u_int ppr_options; 372097883Sgibbs u_int offset; 372197883Sgibbs 372297883Sgibbs tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid, 372397883Sgibbs devinfo->target, &tstate); 372497883Sgibbs /* 372597883Sgibbs * Filter our period based on the current connection. 372697883Sgibbs * If we can't perform DT transfers on this segment (not in LVD 372797883Sgibbs * mode for instance), then our decision to issue a PPR message 372897883Sgibbs * may change. 372997883Sgibbs */ 373097883Sgibbs period = tinfo->goal.period; 3731115918Sgibbs offset = tinfo->goal.offset; 373297883Sgibbs ppr_options = tinfo->goal.ppr_options; 373397883Sgibbs /* Target initiated PPR is not allowed in the SCSI spec */ 373497883Sgibbs if (devinfo->role == ROLE_TARGET) 373597883Sgibbs ppr_options = 0; 373697883Sgibbs ahd_devlimited_syncrate(ahd, tinfo, &period, 373797883Sgibbs &ppr_options, devinfo->role); 373897883Sgibbs dowide = tinfo->curr.width != tinfo->goal.width; 3739115918Sgibbs dosync = tinfo->curr.offset != offset || tinfo->curr.period != period; 3740107441Sscottl /* 3741107441Sscottl * Only use PPR if we have options that need it, even if the device 3742107441Sscottl * claims to support it. There might be an expander in the way 3743107441Sscottl * that doesn't. 3744107441Sscottl */ 3745107441Sscottl doppr = ppr_options != 0; 374697883Sgibbs 374797883Sgibbs if (!dowide && !dosync && !doppr) { 374897883Sgibbs dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT; 3749115918Sgibbs dosync = tinfo->goal.offset != 0; 375097883Sgibbs } 375197883Sgibbs 375297883Sgibbs if (!dowide && !dosync && !doppr) { 3753107441Sscottl /* 3754107441Sscottl * Force async with a WDTR message if we have a wide bus, 3755107441Sscottl * or just issue an SDTR with a 0 offset. 3756107441Sscottl */ 3757107441Sscottl if ((ahd->features & AHD_WIDE) != 0) 3758107441Sscottl dowide = 1; 3759107441Sscottl else 3760107441Sscottl dosync = 1; 3761107441Sscottl 3762107441Sscottl if (bootverbose) { 3763107441Sscottl ahd_print_devinfo(ahd, devinfo); 3764107441Sscottl printf("Ensuring async\n"); 3765107441Sscottl } 376697883Sgibbs } 376797883Sgibbs /* Target initiated PPR is not allowed in the SCSI spec */ 376897883Sgibbs if (devinfo->role == ROLE_TARGET) 3769107441Sscottl doppr = 0; 377097883Sgibbs 377197883Sgibbs /* 377297883Sgibbs * Both the PPR message and SDTR message require the 377397883Sgibbs * goal syncrate to be limited to what the target device 377497883Sgibbs * is capable of handling (based on whether an LVD->SE 377597883Sgibbs * expander is on the bus), so combine these two cases. 377697883Sgibbs * Regardless, guarantee that if we are using WDTR and SDTR 377797883Sgibbs * messages that WDTR comes first. 377897883Sgibbs */ 3779107441Sscottl if (doppr || (dosync && !dowide)) { 378097883Sgibbs 378197883Sgibbs offset = tinfo->goal.offset; 378297883Sgibbs ahd_validate_offset(ahd, tinfo, period, &offset, 3783107441Sscottl doppr ? tinfo->goal.width 3784107441Sscottl : tinfo->curr.width, 378597883Sgibbs devinfo->role); 3786107441Sscottl if (doppr) { 378797883Sgibbs ahd_construct_ppr(ahd, devinfo, period, offset, 378897883Sgibbs tinfo->goal.width, ppr_options); 378997883Sgibbs } else { 379097883Sgibbs ahd_construct_sdtr(ahd, devinfo, period, offset); 379197883Sgibbs } 379297883Sgibbs } else { 379397883Sgibbs ahd_construct_wdtr(ahd, devinfo, tinfo->goal.width); 379497883Sgibbs } 379597883Sgibbs} 379697883Sgibbs 379797883Sgibbs/* 379897883Sgibbs * Build a synchronous negotiation message in our message 379997883Sgibbs * buffer based on the input parameters. 380097883Sgibbs */ 380197883Sgibbsstatic void 380297883Sgibbsahd_construct_sdtr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 380397883Sgibbs u_int period, u_int offset) 380497883Sgibbs{ 3805107441Sscottl if (offset == 0) 3806107441Sscottl period = AHD_ASYNC_XFER_PERIOD; 380797883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = MSG_EXTENDED; 380897883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_SDTR_LEN; 380997883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_SDTR; 381097883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = period; 381197883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = offset; 381297883Sgibbs ahd->msgout_len += 5; 381397883Sgibbs if (bootverbose) { 381497883Sgibbs printf("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n", 381597883Sgibbs ahd_name(ahd), devinfo->channel, devinfo->target, 381697883Sgibbs devinfo->lun, period, offset); 381797883Sgibbs } 381897883Sgibbs} 381997883Sgibbs 382097883Sgibbs/* 382197883Sgibbs * Build a wide negotiateion message in our message 382297883Sgibbs * buffer based on the input parameters. 382397883Sgibbs */ 382497883Sgibbsstatic void 382597883Sgibbsahd_construct_wdtr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 382697883Sgibbs u_int bus_width) 382797883Sgibbs{ 382897883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = MSG_EXTENDED; 382997883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_WDTR_LEN; 383097883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_WDTR; 383197883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = bus_width; 383297883Sgibbs ahd->msgout_len += 4; 383397883Sgibbs if (bootverbose) { 383497883Sgibbs printf("(%s:%c:%d:%d): Sending WDTR %x\n", 383597883Sgibbs ahd_name(ahd), devinfo->channel, devinfo->target, 383697883Sgibbs devinfo->lun, bus_width); 383797883Sgibbs } 383897883Sgibbs} 383997883Sgibbs 384097883Sgibbs/* 384197883Sgibbs * Build a parallel protocol request message in our message 384297883Sgibbs * buffer based on the input parameters. 384397883Sgibbs */ 384497883Sgibbsstatic void 384597883Sgibbsahd_construct_ppr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 384697883Sgibbs u_int period, u_int offset, u_int bus_width, 384797883Sgibbs u_int ppr_options) 384897883Sgibbs{ 384997883Sgibbs /* 385097883Sgibbs * Always request precompensation from 385197883Sgibbs * the other target if we are running 385297883Sgibbs * at paced syncrates. 385397883Sgibbs */ 385497883Sgibbs if (period <= AHD_SYNCRATE_PACED) 385597883Sgibbs ppr_options |= MSG_EXT_PPR_PCOMP_EN; 3856107441Sscottl if (offset == 0) 3857107441Sscottl period = AHD_ASYNC_XFER_PERIOD; 385897883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = MSG_EXTENDED; 385997883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_PPR_LEN; 386097883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_PPR; 386197883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = period; 386297883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = 0; 386397883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = offset; 386497883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = bus_width; 386597883Sgibbs ahd->msgout_buf[ahd->msgout_index++] = ppr_options; 386697883Sgibbs ahd->msgout_len += 8; 386797883Sgibbs if (bootverbose) { 386897883Sgibbs printf("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, " 386997883Sgibbs "offset %x, ppr_options %x\n", ahd_name(ahd), 387097883Sgibbs devinfo->channel, devinfo->target, devinfo->lun, 387197883Sgibbs bus_width, period, offset, ppr_options); 387297883Sgibbs } 387397883Sgibbs} 387497883Sgibbs 387597883Sgibbs/* 387697883Sgibbs * Clear any active message state. 387797883Sgibbs */ 387897883Sgibbsstatic void 387997883Sgibbsahd_clear_msg_state(struct ahd_softc *ahd) 388097883Sgibbs{ 388197883Sgibbs ahd_mode_state saved_modes; 388297883Sgibbs 388397883Sgibbs saved_modes = ahd_save_modes(ahd); 388497883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 388597883Sgibbs ahd->send_msg_perror = 0; 388697883Sgibbs ahd->msg_flags = MSG_FLAG_NONE; 388797883Sgibbs ahd->msgout_len = 0; 388897883Sgibbs ahd->msgin_index = 0; 388997883Sgibbs ahd->msg_type = MSG_TYPE_NONE; 389097883Sgibbs if ((ahd_inb(ahd, SCSISIGO) & ATNO) != 0) { 389197883Sgibbs /* 389297883Sgibbs * The target didn't care to respond to our 389397883Sgibbs * message request, so clear ATN. 389497883Sgibbs */ 389597883Sgibbs ahd_outb(ahd, CLRSINT1, CLRATNO); 389697883Sgibbs } 389797883Sgibbs ahd_outb(ahd, MSG_OUT, MSG_NOOP); 389897883Sgibbs ahd_outb(ahd, SEQ_FLAGS2, 389997883Sgibbs ahd_inb(ahd, SEQ_FLAGS2) & ~TARGET_MSG_PENDING); 390097883Sgibbs ahd_restore_modes(ahd, saved_modes); 390197883Sgibbs} 390297883Sgibbs 390397883Sgibbs/* 390497883Sgibbs * Manual message loop handler. 390597883Sgibbs */ 390697883Sgibbsstatic void 390797883Sgibbsahd_handle_message_phase(struct ahd_softc *ahd) 390897883Sgibbs{ 390997883Sgibbs struct ahd_devinfo devinfo; 391097883Sgibbs u_int bus_phase; 391197883Sgibbs int end_session; 391297883Sgibbs 391397883Sgibbs ahd_fetch_devinfo(ahd, &devinfo); 391497883Sgibbs end_session = FALSE; 391597883Sgibbs bus_phase = ahd_inb(ahd, LASTPHASE); 391697883Sgibbs 391797883Sgibbs if ((ahd_inb(ahd, LQISTAT2) & LQIPHASE_OUTPKT) != 0) { 391897883Sgibbs printf("LQIRETRY for LQIPHASE_OUTPKT\n"); 391997883Sgibbs ahd_outb(ahd, LQCTL2, LQIRETRY); 392097883Sgibbs } 392197883Sgibbsreswitch: 392297883Sgibbs switch (ahd->msg_type) { 392397883Sgibbs case MSG_TYPE_INITIATOR_MSGOUT: 392497883Sgibbs { 392597883Sgibbs int lastbyte; 392697883Sgibbs int phasemis; 392797883Sgibbs int msgdone; 392897883Sgibbs 392997883Sgibbs if (ahd->msgout_len == 0 && ahd->send_msg_perror == 0) 393097883Sgibbs panic("HOST_MSG_LOOP interrupt with no active message"); 393197883Sgibbs 393297883Sgibbs#ifdef AHD_DEBUG 3933102679Sgibbs if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { 3934102679Sgibbs ahd_print_devinfo(ahd, &devinfo); 3935102679Sgibbs printf("INITIATOR_MSG_OUT"); 3936102679Sgibbs } 393797883Sgibbs#endif 393897883Sgibbs phasemis = bus_phase != P_MESGOUT; 393997883Sgibbs if (phasemis) { 394097883Sgibbs#ifdef AHD_DEBUG 394197883Sgibbs if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { 3942102679Sgibbs printf(" PHASEMIS %s\n", 394397883Sgibbs ahd_lookup_phase_entry(bus_phase) 394497883Sgibbs ->phasemsg); 394597883Sgibbs } 394697883Sgibbs#endif 394797883Sgibbs if (bus_phase == P_MESGIN) { 394897883Sgibbs /* 394997883Sgibbs * Change gears and see if 395097883Sgibbs * this messages is of interest to 395197883Sgibbs * us or should be passed back to 395297883Sgibbs * the sequencer. 395397883Sgibbs */ 395497883Sgibbs ahd_outb(ahd, CLRSINT1, CLRATNO); 395597883Sgibbs ahd->send_msg_perror = 0; 395697883Sgibbs ahd->msg_type = MSG_TYPE_INITIATOR_MSGIN; 395797883Sgibbs ahd->msgin_index = 0; 395897883Sgibbs goto reswitch; 395997883Sgibbs } 396097883Sgibbs end_session = TRUE; 396197883Sgibbs break; 396297883Sgibbs } 396397883Sgibbs 396497883Sgibbs if (ahd->send_msg_perror) { 396597883Sgibbs ahd_outb(ahd, CLRSINT1, CLRATNO); 396697883Sgibbs ahd_outb(ahd, CLRSINT1, CLRREQINIT); 396797883Sgibbs#ifdef AHD_DEBUG 396897883Sgibbs if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 396997883Sgibbs printf(" byte 0x%x\n", ahd->send_msg_perror); 397097883Sgibbs#endif 397197883Sgibbs /* 397297883Sgibbs * If we are notifying the target of a CRC error 397397883Sgibbs * during packetized operations, the target is 397497883Sgibbs * within its rights to acknowledge our message 397597883Sgibbs * with a busfree. 397697883Sgibbs */ 397797883Sgibbs if ((ahd->msg_flags & MSG_FLAG_PACKETIZED) != 0 397897883Sgibbs && ahd->send_msg_perror == MSG_INITIATOR_DET_ERR) 397997883Sgibbs ahd->msg_flags |= MSG_FLAG_EXPECT_IDE_BUSFREE; 398097883Sgibbs 398197883Sgibbs ahd_outb(ahd, RETURN_2, ahd->send_msg_perror); 398297883Sgibbs ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_WRITE); 398397883Sgibbs break; 398497883Sgibbs } 398597883Sgibbs 398697883Sgibbs msgdone = ahd->msgout_index == ahd->msgout_len; 398797883Sgibbs if (msgdone) { 398897883Sgibbs /* 398997883Sgibbs * The target has requested a retry. 399097883Sgibbs * Re-assert ATN, reset our message index to 399197883Sgibbs * 0, and try again. 399297883Sgibbs */ 399397883Sgibbs ahd->msgout_index = 0; 399497883Sgibbs ahd_assert_atn(ahd); 399597883Sgibbs } 399697883Sgibbs 399797883Sgibbs lastbyte = ahd->msgout_index == (ahd->msgout_len - 1); 399897883Sgibbs if (lastbyte) { 399997883Sgibbs /* Last byte is signified by dropping ATN */ 400097883Sgibbs ahd_outb(ahd, CLRSINT1, CLRATNO); 400197883Sgibbs } 400297883Sgibbs 400397883Sgibbs /* 400497883Sgibbs * Clear our interrupt status and present 400597883Sgibbs * the next byte on the bus. 400697883Sgibbs */ 400797883Sgibbs ahd_outb(ahd, CLRSINT1, CLRREQINIT); 400897883Sgibbs#ifdef AHD_DEBUG 400997883Sgibbs if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 401097883Sgibbs printf(" byte 0x%x\n", 401197883Sgibbs ahd->msgout_buf[ahd->msgout_index]); 401297883Sgibbs#endif 401397883Sgibbs ahd_outb(ahd, RETURN_2, ahd->msgout_buf[ahd->msgout_index++]); 401497883Sgibbs ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_WRITE); 401597883Sgibbs break; 401697883Sgibbs } 401797883Sgibbs case MSG_TYPE_INITIATOR_MSGIN: 401897883Sgibbs { 401997883Sgibbs int phasemis; 402097883Sgibbs int message_done; 402197883Sgibbs 402297883Sgibbs#ifdef AHD_DEBUG 4023102679Sgibbs if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { 4024102679Sgibbs ahd_print_devinfo(ahd, &devinfo); 4025102679Sgibbs printf("INITIATOR_MSG_IN"); 4026102679Sgibbs } 402797883Sgibbs#endif 402897883Sgibbs phasemis = bus_phase != P_MESGIN; 402997883Sgibbs if (phasemis) { 403097883Sgibbs#ifdef AHD_DEBUG 403197883Sgibbs if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { 403297883Sgibbs printf(" PHASEMIS %s\n", 403397883Sgibbs ahd_lookup_phase_entry(bus_phase) 403497883Sgibbs ->phasemsg); 403597883Sgibbs } 403697883Sgibbs#endif 403797883Sgibbs ahd->msgin_index = 0; 403897883Sgibbs if (bus_phase == P_MESGOUT 403997883Sgibbs && (ahd->send_msg_perror != 0 404097883Sgibbs || (ahd->msgout_len != 0 404197883Sgibbs && ahd->msgout_index == 0))) { 404297883Sgibbs ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; 404397883Sgibbs goto reswitch; 404497883Sgibbs } 404597883Sgibbs end_session = TRUE; 404697883Sgibbs break; 404797883Sgibbs } 404897883Sgibbs 404997883Sgibbs /* Pull the byte in without acking it */ 405097883Sgibbs ahd->msgin_buf[ahd->msgin_index] = ahd_inb(ahd, SCSIBUS); 405197883Sgibbs#ifdef AHD_DEBUG 405297883Sgibbs if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 405397883Sgibbs printf(" byte 0x%x\n", 405497883Sgibbs ahd->msgin_buf[ahd->msgin_index]); 405597883Sgibbs#endif 405697883Sgibbs 405797883Sgibbs message_done = ahd_parse_msg(ahd, &devinfo); 405897883Sgibbs 405997883Sgibbs if (message_done) { 406097883Sgibbs /* 406197883Sgibbs * Clear our incoming message buffer in case there 406297883Sgibbs * is another message following this one. 406397883Sgibbs */ 406497883Sgibbs ahd->msgin_index = 0; 406597883Sgibbs 406697883Sgibbs /* 406797883Sgibbs * If this message illicited a response, 406897883Sgibbs * assert ATN so the target takes us to the 406997883Sgibbs * message out phase. 407097883Sgibbs */ 4071109588Sgibbs if (ahd->msgout_len != 0) { 4072109588Sgibbs#ifdef AHD_DEBUG 4073109588Sgibbs if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { 4074109588Sgibbs ahd_print_devinfo(ahd, &devinfo); 4075109588Sgibbs printf("Asserting ATN for response\n"); 4076109588Sgibbs } 4077109588Sgibbs#endif 407897883Sgibbs ahd_assert_atn(ahd); 4079109588Sgibbs } 408097883Sgibbs } else 408197883Sgibbs ahd->msgin_index++; 408297883Sgibbs 408397883Sgibbs if (message_done == MSGLOOP_TERMINATED) { 408497883Sgibbs end_session = TRUE; 408597883Sgibbs } else { 408697883Sgibbs /* Ack the byte */ 408797883Sgibbs ahd_outb(ahd, CLRSINT1, CLRREQINIT); 408897883Sgibbs ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_READ); 408997883Sgibbs } 409097883Sgibbs break; 409197883Sgibbs } 409297883Sgibbs case MSG_TYPE_TARGET_MSGIN: 409397883Sgibbs { 409497883Sgibbs int msgdone; 409597883Sgibbs int msgout_request; 409697883Sgibbs 409797883Sgibbs /* 409897883Sgibbs * By default, the message loop will continue. 409997883Sgibbs */ 410097883Sgibbs ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG); 410197883Sgibbs 410297883Sgibbs if (ahd->msgout_len == 0) 410397883Sgibbs panic("Target MSGIN with no active message"); 410497883Sgibbs 410597883Sgibbs /* 410697883Sgibbs * If we interrupted a mesgout session, the initiator 410797883Sgibbs * will not know this until our first REQ. So, we 410897883Sgibbs * only honor mesgout requests after we've sent our 410997883Sgibbs * first byte. 411097883Sgibbs */ 411197883Sgibbs if ((ahd_inb(ahd, SCSISIGI) & ATNI) != 0 411297883Sgibbs && ahd->msgout_index > 0) 411397883Sgibbs msgout_request = TRUE; 411497883Sgibbs else 411597883Sgibbs msgout_request = FALSE; 411697883Sgibbs 411797883Sgibbs if (msgout_request) { 411897883Sgibbs 411997883Sgibbs /* 412097883Sgibbs * Change gears and see if 412197883Sgibbs * this messages is of interest to 412297883Sgibbs * us or should be passed back to 412397883Sgibbs * the sequencer. 412497883Sgibbs */ 412597883Sgibbs ahd->msg_type = MSG_TYPE_TARGET_MSGOUT; 412697883Sgibbs ahd_outb(ahd, SCSISIGO, P_MESGOUT | BSYO); 412797883Sgibbs ahd->msgin_index = 0; 412897883Sgibbs /* Dummy read to REQ for first byte */ 412997883Sgibbs ahd_inb(ahd, SCSIDAT); 413097883Sgibbs ahd_outb(ahd, SXFRCTL0, 413197883Sgibbs ahd_inb(ahd, SXFRCTL0) | SPIOEN); 413297883Sgibbs break; 413397883Sgibbs } 413497883Sgibbs 413597883Sgibbs msgdone = ahd->msgout_index == ahd->msgout_len; 413697883Sgibbs if (msgdone) { 413797883Sgibbs ahd_outb(ahd, SXFRCTL0, 413897883Sgibbs ahd_inb(ahd, SXFRCTL0) & ~SPIOEN); 413997883Sgibbs end_session = TRUE; 414097883Sgibbs break; 414197883Sgibbs } 414297883Sgibbs 414397883Sgibbs /* 414497883Sgibbs * Present the next byte on the bus. 414597883Sgibbs */ 414697883Sgibbs ahd_outb(ahd, SXFRCTL0, ahd_inb(ahd, SXFRCTL0) | SPIOEN); 414797883Sgibbs ahd_outb(ahd, SCSIDAT, ahd->msgout_buf[ahd->msgout_index++]); 414897883Sgibbs break; 414997883Sgibbs } 415097883Sgibbs case MSG_TYPE_TARGET_MSGOUT: 415197883Sgibbs { 415297883Sgibbs int lastbyte; 415397883Sgibbs int msgdone; 415497883Sgibbs 415597883Sgibbs /* 415697883Sgibbs * By default, the message loop will continue. 415797883Sgibbs */ 415897883Sgibbs ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG); 415997883Sgibbs 416097883Sgibbs /* 416197883Sgibbs * The initiator signals that this is 416297883Sgibbs * the last byte by dropping ATN. 416397883Sgibbs */ 416497883Sgibbs lastbyte = (ahd_inb(ahd, SCSISIGI) & ATNI) == 0; 416597883Sgibbs 416697883Sgibbs /* 416797883Sgibbs * Read the latched byte, but turn off SPIOEN first 416897883Sgibbs * so that we don't inadvertently cause a REQ for the 416997883Sgibbs * next byte. 417097883Sgibbs */ 417197883Sgibbs ahd_outb(ahd, SXFRCTL0, ahd_inb(ahd, SXFRCTL0) & ~SPIOEN); 417297883Sgibbs ahd->msgin_buf[ahd->msgin_index] = ahd_inb(ahd, SCSIDAT); 417397883Sgibbs msgdone = ahd_parse_msg(ahd, &devinfo); 417497883Sgibbs if (msgdone == MSGLOOP_TERMINATED) { 417597883Sgibbs /* 417697883Sgibbs * The message is *really* done in that it caused 417797883Sgibbs * us to go to bus free. The sequencer has already 417897883Sgibbs * been reset at this point, so pull the ejection 417997883Sgibbs * handle. 418097883Sgibbs */ 418197883Sgibbs return; 418297883Sgibbs } 418397883Sgibbs 418497883Sgibbs ahd->msgin_index++; 418597883Sgibbs 418697883Sgibbs /* 418797883Sgibbs * XXX Read spec about initiator dropping ATN too soon 418897883Sgibbs * and use msgdone to detect it. 418997883Sgibbs */ 419097883Sgibbs if (msgdone == MSGLOOP_MSGCOMPLETE) { 419197883Sgibbs ahd->msgin_index = 0; 419297883Sgibbs 419397883Sgibbs /* 419497883Sgibbs * If this message illicited a response, transition 419597883Sgibbs * to the Message in phase and send it. 419697883Sgibbs */ 419797883Sgibbs if (ahd->msgout_len != 0) { 419897883Sgibbs ahd_outb(ahd, SCSISIGO, P_MESGIN | BSYO); 419997883Sgibbs ahd_outb(ahd, SXFRCTL0, 420097883Sgibbs ahd_inb(ahd, SXFRCTL0) | SPIOEN); 420197883Sgibbs ahd->msg_type = MSG_TYPE_TARGET_MSGIN; 420297883Sgibbs ahd->msgin_index = 0; 420397883Sgibbs break; 420497883Sgibbs } 420597883Sgibbs } 420697883Sgibbs 420797883Sgibbs if (lastbyte) 420897883Sgibbs end_session = TRUE; 420997883Sgibbs else { 421097883Sgibbs /* Ask for the next byte. */ 421197883Sgibbs ahd_outb(ahd, SXFRCTL0, 421297883Sgibbs ahd_inb(ahd, SXFRCTL0) | SPIOEN); 421397883Sgibbs } 421497883Sgibbs 421597883Sgibbs break; 421697883Sgibbs } 421797883Sgibbs default: 421897883Sgibbs panic("Unknown REQINIT message type"); 421997883Sgibbs } 422097883Sgibbs 422197883Sgibbs if (end_session) { 422297883Sgibbs if ((ahd->msg_flags & MSG_FLAG_PACKETIZED) != 0) { 422397883Sgibbs printf("%s: Returning to Idle Loop\n", 422497883Sgibbs ahd_name(ahd)); 4225116935Sgibbs ahd_clear_msg_state(ahd); 4226116935Sgibbs 4227116935Sgibbs /* 4228116935Sgibbs * Perform the equivalent of a clear_target_state. 4229116935Sgibbs */ 423097883Sgibbs ahd_outb(ahd, LASTPHASE, P_BUSFREE); 4231116935Sgibbs ahd_outb(ahd, SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT); 423297883Sgibbs ahd_outb(ahd, SEQCTL0, FASTMODE|SEQRESET); 423397883Sgibbs } else { 423497883Sgibbs ahd_clear_msg_state(ahd); 423597883Sgibbs ahd_outb(ahd, RETURN_1, EXIT_MSG_LOOP); 423697883Sgibbs } 423797883Sgibbs } 423897883Sgibbs} 423997883Sgibbs 424097883Sgibbs/* 424197883Sgibbs * See if we sent a particular extended message to the target. 424297883Sgibbs * If "full" is true, return true only if the target saw the full 424397883Sgibbs * message. If "full" is false, return true if the target saw at 424497883Sgibbs * least the first byte of the message. 424597883Sgibbs */ 424697883Sgibbsstatic int 424797883Sgibbsahd_sent_msg(struct ahd_softc *ahd, ahd_msgtype type, u_int msgval, int full) 424897883Sgibbs{ 424997883Sgibbs int found; 425097883Sgibbs u_int index; 425197883Sgibbs 425297883Sgibbs found = FALSE; 425397883Sgibbs index = 0; 425497883Sgibbs 425597883Sgibbs while (index < ahd->msgout_len) { 425697883Sgibbs if (ahd->msgout_buf[index] == MSG_EXTENDED) { 425797883Sgibbs u_int end_index; 425897883Sgibbs 425997883Sgibbs end_index = index + 1 + ahd->msgout_buf[index + 1]; 426097883Sgibbs if (ahd->msgout_buf[index+2] == msgval 426197883Sgibbs && type == AHDMSG_EXT) { 426297883Sgibbs 426397883Sgibbs if (full) { 426497883Sgibbs if (ahd->msgout_index > end_index) 426597883Sgibbs found = TRUE; 426697883Sgibbs } else if (ahd->msgout_index > index) 426797883Sgibbs found = TRUE; 426897883Sgibbs } 426997883Sgibbs index = end_index; 427097883Sgibbs } else if (ahd->msgout_buf[index] >= MSG_SIMPLE_TASK 427197883Sgibbs && ahd->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) { 427297883Sgibbs 427397883Sgibbs /* Skip tag type and tag id or residue param*/ 427497883Sgibbs index += 2; 427597883Sgibbs } else { 427697883Sgibbs /* Single byte message */ 427797883Sgibbs if (type == AHDMSG_1B 4278109588Sgibbs && ahd->msgout_index > index 4279109588Sgibbs && (ahd->msgout_buf[index] == msgval 4280109588Sgibbs || ((ahd->msgout_buf[index] & MSG_IDENTIFYFLAG) != 0 4281109588Sgibbs && msgval == MSG_IDENTIFYFLAG))) 428297883Sgibbs found = TRUE; 428397883Sgibbs index++; 428497883Sgibbs } 428597883Sgibbs 428697883Sgibbs if (found) 428797883Sgibbs break; 428897883Sgibbs } 428997883Sgibbs return (found); 429097883Sgibbs} 429197883Sgibbs 429297883Sgibbs/* 429397883Sgibbs * Wait for a complete incoming message, parse it, and respond accordingly. 429497883Sgibbs */ 429597883Sgibbsstatic int 429697883Sgibbsahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) 429797883Sgibbs{ 429897883Sgibbs struct ahd_initiator_tinfo *tinfo; 429997883Sgibbs struct ahd_tmode_tstate *tstate; 430097883Sgibbs int reject; 430197883Sgibbs int done; 430297883Sgibbs int response; 430397883Sgibbs 430497883Sgibbs done = MSGLOOP_IN_PROG; 430597883Sgibbs response = FALSE; 430697883Sgibbs reject = FALSE; 430797883Sgibbs tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid, 430897883Sgibbs devinfo->target, &tstate); 430997883Sgibbs 431097883Sgibbs /* 4311114623Sgibbs * Parse as much of the message as is available, 431297883Sgibbs * rejecting it if we don't support it. When 4313114623Sgibbs * the entire message is available and has been 431497883Sgibbs * handled, return MSGLOOP_MSGCOMPLETE, indicating 431597883Sgibbs * that we have parsed an entire message. 431697883Sgibbs * 431797883Sgibbs * In the case of extended messages, we accept the length 431897883Sgibbs * byte outright and perform more checking once we know the 431997883Sgibbs * extended message type. 432097883Sgibbs */ 432197883Sgibbs switch (ahd->msgin_buf[0]) { 432297883Sgibbs case MSG_DISCONNECT: 432397883Sgibbs case MSG_SAVEDATAPOINTER: 432497883Sgibbs case MSG_CMDCOMPLETE: 432597883Sgibbs case MSG_RESTOREPOINTERS: 432697883Sgibbs case MSG_IGN_WIDE_RESIDUE: 432797883Sgibbs /* 432897883Sgibbs * End our message loop as these are messages 432997883Sgibbs * the sequencer handles on its own. 433097883Sgibbs */ 433197883Sgibbs done = MSGLOOP_TERMINATED; 433297883Sgibbs break; 433397883Sgibbs case MSG_MESSAGE_REJECT: 433497883Sgibbs response = ahd_handle_msg_reject(ahd, devinfo); 433597883Sgibbs /* FALLTHROUGH */ 433697883Sgibbs case MSG_NOOP: 433797883Sgibbs done = MSGLOOP_MSGCOMPLETE; 433897883Sgibbs break; 433997883Sgibbs case MSG_EXTENDED: 434097883Sgibbs { 434197883Sgibbs /* Wait for enough of the message to begin validation */ 434297883Sgibbs if (ahd->msgin_index < 2) 434397883Sgibbs break; 434497883Sgibbs switch (ahd->msgin_buf[2]) { 434597883Sgibbs case MSG_EXT_SDTR: 434697883Sgibbs { 434797883Sgibbs u_int period; 434897883Sgibbs u_int ppr_options; 434997883Sgibbs u_int offset; 435097883Sgibbs u_int saved_offset; 435197883Sgibbs 435297883Sgibbs if (ahd->msgin_buf[1] != MSG_EXT_SDTR_LEN) { 435397883Sgibbs reject = TRUE; 435497883Sgibbs break; 435597883Sgibbs } 435697883Sgibbs 435797883Sgibbs /* 435897883Sgibbs * Wait until we have both args before validating 435997883Sgibbs * and acting on this message. 436097883Sgibbs * 436197883Sgibbs * Add one to MSG_EXT_SDTR_LEN to account for 436297883Sgibbs * the extended message preamble. 436397883Sgibbs */ 436497883Sgibbs if (ahd->msgin_index < (MSG_EXT_SDTR_LEN + 1)) 436597883Sgibbs break; 436697883Sgibbs 436797883Sgibbs period = ahd->msgin_buf[3]; 436897883Sgibbs ppr_options = 0; 436997883Sgibbs saved_offset = offset = ahd->msgin_buf[4]; 437097883Sgibbs ahd_devlimited_syncrate(ahd, tinfo, &period, 437197883Sgibbs &ppr_options, devinfo->role); 437297883Sgibbs ahd_validate_offset(ahd, tinfo, period, &offset, 437397883Sgibbs tinfo->curr.width, devinfo->role); 437497883Sgibbs if (bootverbose) { 437597883Sgibbs printf("(%s:%c:%d:%d): Received " 437697883Sgibbs "SDTR period %x, offset %x\n\t" 437797883Sgibbs "Filtered to period %x, offset %x\n", 437897883Sgibbs ahd_name(ahd), devinfo->channel, 437997883Sgibbs devinfo->target, devinfo->lun, 438097883Sgibbs ahd->msgin_buf[3], saved_offset, 438197883Sgibbs period, offset); 438297883Sgibbs } 438397883Sgibbs ahd_set_syncrate(ahd, devinfo, period, 438497883Sgibbs offset, ppr_options, 438597883Sgibbs AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, 438697883Sgibbs /*paused*/TRUE); 438797883Sgibbs 438897883Sgibbs /* 438997883Sgibbs * See if we initiated Sync Negotiation 439097883Sgibbs * and didn't have to fall down to async 439197883Sgibbs * transfers. 439297883Sgibbs */ 439397883Sgibbs if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, TRUE)) { 439497883Sgibbs /* We started it */ 439597883Sgibbs if (saved_offset != offset) { 439697883Sgibbs /* Went too low - force async */ 439797883Sgibbs reject = TRUE; 439897883Sgibbs } 439997883Sgibbs } else { 440097883Sgibbs /* 440197883Sgibbs * Send our own SDTR in reply 440297883Sgibbs */ 440397883Sgibbs if (bootverbose 440497883Sgibbs && devinfo->role == ROLE_INITIATOR) { 440597883Sgibbs printf("(%s:%c:%d:%d): Target " 440697883Sgibbs "Initiated SDTR\n", 440797883Sgibbs ahd_name(ahd), devinfo->channel, 440897883Sgibbs devinfo->target, devinfo->lun); 440997883Sgibbs } 441097883Sgibbs ahd->msgout_index = 0; 441197883Sgibbs ahd->msgout_len = 0; 441297883Sgibbs ahd_construct_sdtr(ahd, devinfo, 441397883Sgibbs period, offset); 441497883Sgibbs ahd->msgout_index = 0; 441597883Sgibbs response = TRUE; 441697883Sgibbs } 441797883Sgibbs done = MSGLOOP_MSGCOMPLETE; 441897883Sgibbs break; 441997883Sgibbs } 442097883Sgibbs case MSG_EXT_WDTR: 442197883Sgibbs { 442297883Sgibbs u_int bus_width; 442397883Sgibbs u_int saved_width; 442497883Sgibbs u_int sending_reply; 442597883Sgibbs 442697883Sgibbs sending_reply = FALSE; 442797883Sgibbs if (ahd->msgin_buf[1] != MSG_EXT_WDTR_LEN) { 442897883Sgibbs reject = TRUE; 442997883Sgibbs break; 443097883Sgibbs } 443197883Sgibbs 443297883Sgibbs /* 443397883Sgibbs * Wait until we have our arg before validating 443497883Sgibbs * and acting on this message. 443597883Sgibbs * 443697883Sgibbs * Add one to MSG_EXT_WDTR_LEN to account for 443797883Sgibbs * the extended message preamble. 443897883Sgibbs */ 443997883Sgibbs if (ahd->msgin_index < (MSG_EXT_WDTR_LEN + 1)) 444097883Sgibbs break; 444197883Sgibbs 444297883Sgibbs bus_width = ahd->msgin_buf[3]; 444397883Sgibbs saved_width = bus_width; 444497883Sgibbs ahd_validate_width(ahd, tinfo, &bus_width, 444597883Sgibbs devinfo->role); 444697883Sgibbs if (bootverbose) { 444797883Sgibbs printf("(%s:%c:%d:%d): Received WDTR " 444897883Sgibbs "%x filtered to %x\n", 444997883Sgibbs ahd_name(ahd), devinfo->channel, 445097883Sgibbs devinfo->target, devinfo->lun, 445197883Sgibbs saved_width, bus_width); 445297883Sgibbs } 445397883Sgibbs 445497883Sgibbs if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, TRUE)) { 445597883Sgibbs /* 445697883Sgibbs * Don't send a WDTR back to the 445797883Sgibbs * target, since we asked first. 445897883Sgibbs * If the width went higher than our 445997883Sgibbs * request, reject it. 446097883Sgibbs */ 446197883Sgibbs if (saved_width > bus_width) { 446297883Sgibbs reject = TRUE; 446397883Sgibbs printf("(%s:%c:%d:%d): requested %dBit " 446497883Sgibbs "transfers. Rejecting...\n", 446597883Sgibbs ahd_name(ahd), devinfo->channel, 446697883Sgibbs devinfo->target, devinfo->lun, 446797883Sgibbs 8 * (0x01 << bus_width)); 446897883Sgibbs bus_width = 0; 446997883Sgibbs } 447097883Sgibbs } else { 447197883Sgibbs /* 447297883Sgibbs * Send our own WDTR in reply 447397883Sgibbs */ 447497883Sgibbs if (bootverbose 447597883Sgibbs && devinfo->role == ROLE_INITIATOR) { 447697883Sgibbs printf("(%s:%c:%d:%d): Target " 447797883Sgibbs "Initiated WDTR\n", 447897883Sgibbs ahd_name(ahd), devinfo->channel, 447997883Sgibbs devinfo->target, devinfo->lun); 448097883Sgibbs } 448197883Sgibbs ahd->msgout_index = 0; 448297883Sgibbs ahd->msgout_len = 0; 448397883Sgibbs ahd_construct_wdtr(ahd, devinfo, bus_width); 448497883Sgibbs ahd->msgout_index = 0; 448597883Sgibbs response = TRUE; 448697883Sgibbs sending_reply = TRUE; 448797883Sgibbs } 4488115918Sgibbs /* 4489115918Sgibbs * After a wide message, we are async, but 4490115918Sgibbs * some devices don't seem to honor this portion 4491115918Sgibbs * of the spec. Force a renegotiation of the 4492115918Sgibbs * sync component of our transfer agreement even 4493115918Sgibbs * if our goal is async. By updating our width 4494115918Sgibbs * after forcing the negotiation, we avoid 4495115918Sgibbs * renegotiating for width. 4496115918Sgibbs */ 4497115918Sgibbs ahd_update_neg_request(ahd, devinfo, tstate, 4498115918Sgibbs tinfo, AHD_NEG_ALWAYS); 449997883Sgibbs ahd_set_width(ahd, devinfo, bus_width, 450097883Sgibbs AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, 450197883Sgibbs /*paused*/TRUE); 450297883Sgibbs if (sending_reply == FALSE && reject == FALSE) { 450397883Sgibbs 4504115918Sgibbs /* 4505115918Sgibbs * We will always have an SDTR to send. 4506115918Sgibbs */ 4507115918Sgibbs ahd->msgout_index = 0; 4508115918Sgibbs ahd->msgout_len = 0; 4509115918Sgibbs ahd_build_transfer_msg(ahd, devinfo); 4510115918Sgibbs ahd->msgout_index = 0; 4511115918Sgibbs response = TRUE; 451297883Sgibbs } 451397883Sgibbs done = MSGLOOP_MSGCOMPLETE; 451497883Sgibbs break; 451597883Sgibbs } 451697883Sgibbs case MSG_EXT_PPR: 451797883Sgibbs { 451897883Sgibbs u_int period; 451997883Sgibbs u_int offset; 452097883Sgibbs u_int bus_width; 452197883Sgibbs u_int ppr_options; 452297883Sgibbs u_int saved_width; 452397883Sgibbs u_int saved_offset; 452497883Sgibbs u_int saved_ppr_options; 452597883Sgibbs 452697883Sgibbs if (ahd->msgin_buf[1] != MSG_EXT_PPR_LEN) { 452797883Sgibbs reject = TRUE; 452897883Sgibbs break; 452997883Sgibbs } 453097883Sgibbs 453197883Sgibbs /* 453297883Sgibbs * Wait until we have all args before validating 453397883Sgibbs * and acting on this message. 453497883Sgibbs * 453597883Sgibbs * Add one to MSG_EXT_PPR_LEN to account for 453697883Sgibbs * the extended message preamble. 453797883Sgibbs */ 453897883Sgibbs if (ahd->msgin_index < (MSG_EXT_PPR_LEN + 1)) 453997883Sgibbs break; 454097883Sgibbs 454197883Sgibbs period = ahd->msgin_buf[3]; 454297883Sgibbs offset = ahd->msgin_buf[5]; 454397883Sgibbs bus_width = ahd->msgin_buf[6]; 454497883Sgibbs saved_width = bus_width; 454597883Sgibbs ppr_options = ahd->msgin_buf[7]; 454697883Sgibbs /* 454797883Sgibbs * According to the spec, a DT only 454897883Sgibbs * period factor with no DT option 454997883Sgibbs * set implies async. 455097883Sgibbs */ 455197883Sgibbs if ((ppr_options & MSG_EXT_PPR_DT_REQ) == 0 455297883Sgibbs && period <= 9) 455397883Sgibbs offset = 0; 455497883Sgibbs saved_ppr_options = ppr_options; 455597883Sgibbs saved_offset = offset; 455697883Sgibbs 455797883Sgibbs /* 455897883Sgibbs * Transfer options are only available if we 455997883Sgibbs * are negotiating wide. 456097883Sgibbs */ 456197883Sgibbs if (bus_width == 0) 456297883Sgibbs ppr_options &= MSG_EXT_PPR_QAS_REQ; 456397883Sgibbs 456497883Sgibbs ahd_validate_width(ahd, tinfo, &bus_width, 456597883Sgibbs devinfo->role); 456697883Sgibbs ahd_devlimited_syncrate(ahd, tinfo, &period, 456797883Sgibbs &ppr_options, devinfo->role); 456897883Sgibbs ahd_validate_offset(ahd, tinfo, period, &offset, 456997883Sgibbs bus_width, devinfo->role); 457097883Sgibbs 457197883Sgibbs if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, TRUE)) { 457297883Sgibbs /* 457397883Sgibbs * If we are unable to do any of the 457497883Sgibbs * requested options (we went too low), 457597883Sgibbs * then we'll have to reject the message. 457697883Sgibbs */ 457797883Sgibbs if (saved_width > bus_width 457897883Sgibbs || saved_offset != offset 457997883Sgibbs || saved_ppr_options != ppr_options) { 458097883Sgibbs reject = TRUE; 458197883Sgibbs period = 0; 458297883Sgibbs offset = 0; 458397883Sgibbs bus_width = 0; 458497883Sgibbs ppr_options = 0; 458597883Sgibbs } 458697883Sgibbs } else { 458797883Sgibbs if (devinfo->role != ROLE_TARGET) 458897883Sgibbs printf("(%s:%c:%d:%d): Target " 458997883Sgibbs "Initiated PPR\n", 459097883Sgibbs ahd_name(ahd), devinfo->channel, 459197883Sgibbs devinfo->target, devinfo->lun); 459297883Sgibbs else 459397883Sgibbs printf("(%s:%c:%d:%d): Initiator " 459497883Sgibbs "Initiated PPR\n", 459597883Sgibbs ahd_name(ahd), devinfo->channel, 459697883Sgibbs devinfo->target, devinfo->lun); 459797883Sgibbs ahd->msgout_index = 0; 459897883Sgibbs ahd->msgout_len = 0; 459997883Sgibbs ahd_construct_ppr(ahd, devinfo, period, offset, 460097883Sgibbs bus_width, ppr_options); 460197883Sgibbs ahd->msgout_index = 0; 460297883Sgibbs response = TRUE; 460397883Sgibbs } 460497883Sgibbs if (bootverbose) { 460597883Sgibbs printf("(%s:%c:%d:%d): Received PPR width %x, " 460697883Sgibbs "period %x, offset %x,options %x\n" 460797883Sgibbs "\tFiltered to width %x, period %x, " 460897883Sgibbs "offset %x, options %x\n", 460997883Sgibbs ahd_name(ahd), devinfo->channel, 461097883Sgibbs devinfo->target, devinfo->lun, 461197883Sgibbs saved_width, ahd->msgin_buf[3], 461297883Sgibbs saved_offset, saved_ppr_options, 461397883Sgibbs bus_width, period, offset, ppr_options); 461497883Sgibbs } 461597883Sgibbs ahd_set_width(ahd, devinfo, bus_width, 461697883Sgibbs AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, 461797883Sgibbs /*paused*/TRUE); 461897883Sgibbs ahd_set_syncrate(ahd, devinfo, period, 461997883Sgibbs offset, ppr_options, 462097883Sgibbs AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, 462197883Sgibbs /*paused*/TRUE); 462297883Sgibbs 462397883Sgibbs done = MSGLOOP_MSGCOMPLETE; 462497883Sgibbs break; 462597883Sgibbs } 462697883Sgibbs default: 462797883Sgibbs /* Unknown extended message. Reject it. */ 462897883Sgibbs reject = TRUE; 462997883Sgibbs break; 463097883Sgibbs } 463197883Sgibbs break; 463297883Sgibbs } 463397883Sgibbs#ifdef AHD_TARGET_MODE 463497883Sgibbs case MSG_BUS_DEV_RESET: 4635109588Sgibbs ahd_handle_devreset(ahd, devinfo, CAM_LUN_WILDCARD, 463697883Sgibbs CAM_BDR_SENT, 463797883Sgibbs "Bus Device Reset Received", 463897883Sgibbs /*verbose_level*/0); 463997883Sgibbs ahd_restart(ahd); 464097883Sgibbs done = MSGLOOP_TERMINATED; 464197883Sgibbs break; 464297883Sgibbs case MSG_ABORT_TAG: 464397883Sgibbs case MSG_ABORT: 464497883Sgibbs case MSG_CLEAR_QUEUE: 464597883Sgibbs { 464697883Sgibbs int tag; 464797883Sgibbs 464897883Sgibbs /* Target mode messages */ 464997883Sgibbs if (devinfo->role != ROLE_TARGET) { 465097883Sgibbs reject = TRUE; 465197883Sgibbs break; 465297883Sgibbs } 465397883Sgibbs tag = SCB_LIST_NULL; 465497883Sgibbs if (ahd->msgin_buf[0] == MSG_ABORT_TAG) 465597883Sgibbs tag = ahd_inb(ahd, INITIATOR_TAG); 465697883Sgibbs ahd_abort_scbs(ahd, devinfo->target, devinfo->channel, 465797883Sgibbs devinfo->lun, tag, ROLE_TARGET, 465897883Sgibbs CAM_REQ_ABORTED); 465997883Sgibbs 466097883Sgibbs tstate = ahd->enabled_targets[devinfo->our_scsiid]; 466197883Sgibbs if (tstate != NULL) { 466297883Sgibbs struct ahd_tmode_lstate* lstate; 466397883Sgibbs 466497883Sgibbs lstate = tstate->enabled_luns[devinfo->lun]; 466597883Sgibbs if (lstate != NULL) { 466697883Sgibbs ahd_queue_lstate_event(ahd, lstate, 466797883Sgibbs devinfo->our_scsiid, 466897883Sgibbs ahd->msgin_buf[0], 466997883Sgibbs /*arg*/tag); 467097883Sgibbs ahd_send_lstate_events(ahd, lstate); 467197883Sgibbs } 467297883Sgibbs } 467397883Sgibbs ahd_restart(ahd); 467497883Sgibbs done = MSGLOOP_TERMINATED; 467597883Sgibbs break; 467697883Sgibbs } 467797883Sgibbs#endif 467897883Sgibbs case MSG_QAS_REQUEST: 4679107441Sscottl#ifdef AHD_DEBUG 4680107441Sscottl if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 4681107441Sscottl printf("%s: QAS request. SCSISIGI == 0x%x\n", 4682107441Sscottl ahd_name(ahd), ahd_inb(ahd, SCSISIGI)); 4683107441Sscottl#endif 4684107441Sscottl ahd->msg_flags |= MSG_FLAG_EXPECT_QASREJ_BUSFREE; 468597883Sgibbs /* FALLTHROUGH */ 468697883Sgibbs case MSG_TERM_IO_PROC: 468797883Sgibbs default: 468897883Sgibbs reject = TRUE; 468997883Sgibbs break; 469097883Sgibbs } 469197883Sgibbs 469297883Sgibbs if (reject) { 469397883Sgibbs /* 469497883Sgibbs * Setup to reject the message. 469597883Sgibbs */ 469697883Sgibbs ahd->msgout_index = 0; 469797883Sgibbs ahd->msgout_len = 1; 469897883Sgibbs ahd->msgout_buf[0] = MSG_MESSAGE_REJECT; 469997883Sgibbs done = MSGLOOP_MSGCOMPLETE; 470097883Sgibbs response = TRUE; 470197883Sgibbs } 470297883Sgibbs 470397883Sgibbs if (done != MSGLOOP_IN_PROG && !response) 470497883Sgibbs /* Clear the outgoing message buffer */ 470597883Sgibbs ahd->msgout_len = 0; 470697883Sgibbs 470797883Sgibbs return (done); 470897883Sgibbs} 470997883Sgibbs 471097883Sgibbs/* 471197883Sgibbs * Process a message reject message. 471297883Sgibbs */ 471397883Sgibbsstatic int 471497883Sgibbsahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) 471597883Sgibbs{ 471697883Sgibbs /* 471797883Sgibbs * What we care about here is if we had an 471897883Sgibbs * outstanding SDTR or WDTR message for this 471997883Sgibbs * target. If we did, this is a signal that 472097883Sgibbs * the target is refusing negotiation. 472197883Sgibbs */ 472297883Sgibbs struct scb *scb; 472397883Sgibbs struct ahd_initiator_tinfo *tinfo; 472497883Sgibbs struct ahd_tmode_tstate *tstate; 472597883Sgibbs u_int scb_index; 472697883Sgibbs u_int last_msg; 472797883Sgibbs int response = 0; 472897883Sgibbs 472997883Sgibbs scb_index = ahd_get_scbptr(ahd); 473097883Sgibbs scb = ahd_lookup_scb(ahd, scb_index); 473197883Sgibbs tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, 473297883Sgibbs devinfo->our_scsiid, 473397883Sgibbs devinfo->target, &tstate); 473497883Sgibbs /* Might be necessary */ 473597883Sgibbs last_msg = ahd_inb(ahd, LAST_MSG); 473697883Sgibbs 473797883Sgibbs if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, /*full*/FALSE)) { 4738107441Sscottl if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, /*full*/TRUE) 4739107441Sscottl && tinfo->goal.period <= AHD_SYNCRATE_PACED) { 4740107441Sscottl /* 4741107441Sscottl * Target may not like our SPI-4 PPR Options. 4742107441Sscottl * Attempt to negotiate 80MHz which will turn 4743107441Sscottl * off these options. 4744107441Sscottl */ 4745107441Sscottl if (bootverbose) { 4746107441Sscottl printf("(%s:%c:%d:%d): PPR Rejected. " 4747107441Sscottl "Trying simple U160 PPR\n", 4748107441Sscottl ahd_name(ahd), devinfo->channel, 4749107441Sscottl devinfo->target, devinfo->lun); 4750107441Sscottl } 4751107441Sscottl tinfo->goal.period = AHD_SYNCRATE_DT; 4752107441Sscottl tinfo->goal.ppr_options &= MSG_EXT_PPR_IU_REQ 4753107441Sscottl | MSG_EXT_PPR_QAS_REQ 4754107441Sscottl | MSG_EXT_PPR_DT_REQ; 4755107441Sscottl } else { 4756107441Sscottl /* 4757107441Sscottl * Target does not support the PPR message. 4758107441Sscottl * Attempt to negotiate SPI-2 style. 4759107441Sscottl */ 4760107441Sscottl if (bootverbose) { 4761107441Sscottl printf("(%s:%c:%d:%d): PPR Rejected. " 4762107441Sscottl "Trying WDTR/SDTR\n", 4763107441Sscottl ahd_name(ahd), devinfo->channel, 4764107441Sscottl devinfo->target, devinfo->lun); 4765107441Sscottl } 4766107441Sscottl tinfo->goal.ppr_options = 0; 4767107441Sscottl tinfo->curr.transport_version = 2; 4768107441Sscottl tinfo->goal.transport_version = 2; 476997883Sgibbs } 477097883Sgibbs ahd->msgout_index = 0; 477197883Sgibbs ahd->msgout_len = 0; 477297883Sgibbs ahd_build_transfer_msg(ahd, devinfo); 477397883Sgibbs ahd->msgout_index = 0; 477497883Sgibbs response = 1; 477597883Sgibbs } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, /*full*/FALSE)) { 477697883Sgibbs 477797883Sgibbs /* note 8bit xfers */ 477897883Sgibbs printf("(%s:%c:%d:%d): refuses WIDE negotiation. Using " 477997883Sgibbs "8bit transfers\n", ahd_name(ahd), 478097883Sgibbs devinfo->channel, devinfo->target, devinfo->lun); 478197883Sgibbs ahd_set_width(ahd, devinfo, MSG_EXT_WDTR_BUS_8_BIT, 478297883Sgibbs AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, 478397883Sgibbs /*paused*/TRUE); 478497883Sgibbs /* 478597883Sgibbs * No need to clear the sync rate. If the target 478697883Sgibbs * did not accept the command, our syncrate is 478797883Sgibbs * unaffected. If the target started the negotiation, 478897883Sgibbs * but rejected our response, we already cleared the 478997883Sgibbs * sync rate before sending our WDTR. 479097883Sgibbs */ 4791109603Sgibbs if (tinfo->goal.offset != tinfo->curr.offset) { 479297883Sgibbs 479397883Sgibbs /* Start the sync negotiation */ 479497883Sgibbs ahd->msgout_index = 0; 479597883Sgibbs ahd->msgout_len = 0; 479697883Sgibbs ahd_build_transfer_msg(ahd, devinfo); 479797883Sgibbs ahd->msgout_index = 0; 479897883Sgibbs response = 1; 479997883Sgibbs } 480097883Sgibbs } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, /*full*/FALSE)) { 480197883Sgibbs /* note asynch xfers and clear flag */ 480297883Sgibbs ahd_set_syncrate(ahd, devinfo, /*period*/0, 480397883Sgibbs /*offset*/0, /*ppr_options*/0, 480497883Sgibbs AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, 480597883Sgibbs /*paused*/TRUE); 480697883Sgibbs printf("(%s:%c:%d:%d): refuses synchronous negotiation. " 480797883Sgibbs "Using asynchronous transfers\n", 480897883Sgibbs ahd_name(ahd), devinfo->channel, 480997883Sgibbs devinfo->target, devinfo->lun); 481097883Sgibbs } else if ((scb->hscb->control & MSG_SIMPLE_TASK) != 0) { 481197883Sgibbs int tag_type; 481297883Sgibbs int mask; 481397883Sgibbs 481497883Sgibbs tag_type = (scb->hscb->control & MSG_SIMPLE_TASK); 481597883Sgibbs 481697883Sgibbs if (tag_type == MSG_SIMPLE_TASK) { 481797883Sgibbs printf("(%s:%c:%d:%d): refuses tagged commands. " 481897883Sgibbs "Performing non-tagged I/O\n", ahd_name(ahd), 481997883Sgibbs devinfo->channel, devinfo->target, devinfo->lun); 482097883Sgibbs ahd_set_tags(ahd, devinfo, AHD_QUEUE_NONE); 482197883Sgibbs mask = ~0x23; 482297883Sgibbs } else { 482397883Sgibbs printf("(%s:%c:%d:%d): refuses %s tagged commands. " 482497883Sgibbs "Performing simple queue tagged I/O only\n", 482597883Sgibbs ahd_name(ahd), devinfo->channel, devinfo->target, 482697883Sgibbs devinfo->lun, tag_type == MSG_ORDERED_TASK 482797883Sgibbs ? "ordered" : "head of queue"); 482897883Sgibbs ahd_set_tags(ahd, devinfo, AHD_QUEUE_BASIC); 482997883Sgibbs mask = ~0x03; 483097883Sgibbs } 483197883Sgibbs 483297883Sgibbs /* 483397883Sgibbs * Resend the identify for this CCB as the target 483497883Sgibbs * may believe that the selection is invalid otherwise. 483597883Sgibbs */ 483697883Sgibbs ahd_outb(ahd, SCB_CONTROL, 483797883Sgibbs ahd_inb_scbram(ahd, SCB_CONTROL) & mask); 483897883Sgibbs scb->hscb->control &= mask; 4839123579Sgibbs aic_set_transaction_tag(scb, /*enabled*/FALSE, 484097883Sgibbs /*type*/MSG_SIMPLE_TASK); 484197883Sgibbs ahd_outb(ahd, MSG_OUT, MSG_IDENTIFYFLAG); 484297883Sgibbs ahd_assert_atn(ahd); 484397883Sgibbs ahd_busy_tcl(ahd, BUILD_TCL(scb->hscb->scsiid, devinfo->lun), 484497883Sgibbs SCB_GET_TAG(scb)); 484597883Sgibbs 484697883Sgibbs /* 484797883Sgibbs * Requeue all tagged commands for this target 484897883Sgibbs * currently in our posession so they can be 484997883Sgibbs * converted to untagged commands. 485097883Sgibbs */ 485197883Sgibbs ahd_search_qinfifo(ahd, SCB_GET_TARGET(ahd, scb), 485297883Sgibbs SCB_GET_CHANNEL(ahd, scb), 485397883Sgibbs SCB_GET_LUN(scb), /*tag*/SCB_LIST_NULL, 485497883Sgibbs ROLE_INITIATOR, CAM_REQUEUE_REQ, 485597883Sgibbs SEARCH_COMPLETE); 4856109588Sgibbs } else if (ahd_sent_msg(ahd, AHDMSG_1B, MSG_IDENTIFYFLAG, TRUE)) { 4857109588Sgibbs /* 4858109588Sgibbs * Most likely the device believes that we had 4859109588Sgibbs * previously negotiated packetized. 4860109588Sgibbs */ 4861109588Sgibbs ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE 4862109588Sgibbs | MSG_FLAG_IU_REQ_CHANGED; 4863109588Sgibbs 4864109588Sgibbs ahd_force_renegotiation(ahd, devinfo); 4865109588Sgibbs ahd->msgout_index = 0; 4866109588Sgibbs ahd->msgout_len = 0; 4867109588Sgibbs ahd_build_transfer_msg(ahd, devinfo); 4868109588Sgibbs ahd->msgout_index = 0; 4869109588Sgibbs response = 1; 487097883Sgibbs } else { 487197883Sgibbs /* 487297883Sgibbs * Otherwise, we ignore it. 487397883Sgibbs */ 487497883Sgibbs printf("%s:%c:%d: Message reject for %x -- ignored\n", 487597883Sgibbs ahd_name(ahd), devinfo->channel, devinfo->target, 487697883Sgibbs last_msg); 487797883Sgibbs } 487897883Sgibbs return (response); 487997883Sgibbs} 488097883Sgibbs 488197883Sgibbs/* 488297883Sgibbs * Process an ingnore wide residue message. 488397883Sgibbs */ 488497883Sgibbsstatic void 488597883Sgibbsahd_handle_ign_wide_residue(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) 488697883Sgibbs{ 488797883Sgibbs u_int scb_index; 488897883Sgibbs struct scb *scb; 488997883Sgibbs 489097883Sgibbs scb_index = ahd_get_scbptr(ahd); 489197883Sgibbs scb = ahd_lookup_scb(ahd, scb_index); 489297883Sgibbs /* 489397883Sgibbs * XXX Actually check data direction in the sequencer? 489497883Sgibbs * Perhaps add datadir to some spare bits in the hscb? 489597883Sgibbs */ 489697883Sgibbs if ((ahd_inb(ahd, SEQ_FLAGS) & DPHASE) == 0 4897123579Sgibbs || aic_get_transfer_dir(scb) != CAM_DIR_IN) { 489897883Sgibbs /* 489997883Sgibbs * Ignore the message if we haven't 490097883Sgibbs * seen an appropriate data phase yet. 490197883Sgibbs */ 490297883Sgibbs } else { 490397883Sgibbs /* 490497883Sgibbs * If the residual occurred on the last 490597883Sgibbs * transfer and the transfer request was 490697883Sgibbs * expected to end on an odd count, do 490797883Sgibbs * nothing. Otherwise, subtract a byte 490897883Sgibbs * and update the residual count accordingly. 490997883Sgibbs */ 491097883Sgibbs uint32_t sgptr; 491197883Sgibbs 491297883Sgibbs sgptr = ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR); 491397883Sgibbs if ((sgptr & SG_LIST_NULL) != 0 4914116940Sgibbs && (ahd_inb_scbram(ahd, SCB_TASK_ATTRIBUTE) 4915116940Sgibbs & SCB_XFERLEN_ODD) != 0) { 491697883Sgibbs /* 491797883Sgibbs * If the residual occurred on the last 491897883Sgibbs * transfer and the transfer request was 491997883Sgibbs * expected to end on an odd count, do 492097883Sgibbs * nothing. 492197883Sgibbs */ 492297883Sgibbs } else { 492397883Sgibbs uint32_t data_cnt; 492497883Sgibbs uint64_t data_addr; 492597883Sgibbs uint32_t sglen; 492697883Sgibbs 492797883Sgibbs /* Pull in the rest of the sgptr */ 4928115335Sgibbs sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR); 4929115335Sgibbs data_cnt = ahd_inl_scbram(ahd, SCB_RESIDUAL_DATACNT); 4930115335Sgibbs if ((sgptr & SG_LIST_NULL) != 0) { 4931115335Sgibbs /* 4932115335Sgibbs * The residual data count is not updated 4933115335Sgibbs * for the command run to completion case. 4934115335Sgibbs * Explicitly zero the count. 4935115335Sgibbs */ 4936115335Sgibbs data_cnt &= ~AHD_SG_LEN_MASK; 4937115335Sgibbs } 4938115335Sgibbs data_addr = ahd_inq(ahd, SHADDR); 493997883Sgibbs data_cnt += 1; 494097883Sgibbs data_addr -= 1; 4941115335Sgibbs sgptr &= SG_PTR_MASK; 494297883Sgibbs if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 494397883Sgibbs struct ahd_dma64_seg *sg; 494497883Sgibbs 494597883Sgibbs sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); 494697883Sgibbs 494797883Sgibbs /* 494897883Sgibbs * The residual sg ptr points to the next S/G 494997883Sgibbs * to load so we must go back one. 495097883Sgibbs */ 495197883Sgibbs sg--; 4952123579Sgibbs sglen = aic_le32toh(sg->len) & AHD_SG_LEN_MASK; 495397883Sgibbs if (sg != scb->sg_list 495497883Sgibbs && sglen < (data_cnt & AHD_SG_LEN_MASK)) { 495597883Sgibbs 495697883Sgibbs sg--; 4957123579Sgibbs sglen = aic_le32toh(sg->len); 495897883Sgibbs /* 495997883Sgibbs * Preserve High Address and SG_LIST 496097883Sgibbs * bits while setting the count to 1. 496197883Sgibbs */ 496297883Sgibbs data_cnt = 1|(sglen&(~AHD_SG_LEN_MASK)); 4963123579Sgibbs data_addr = aic_le64toh(sg->addr) 496497883Sgibbs + (sglen & AHD_SG_LEN_MASK) 496597883Sgibbs - 1; 496697883Sgibbs 496797883Sgibbs /* 496897883Sgibbs * Increment sg so it points to the 496997883Sgibbs * "next" sg. 497097883Sgibbs */ 497197883Sgibbs sg++; 497297883Sgibbs sgptr = ahd_sg_virt_to_bus(ahd, scb, 497397883Sgibbs sg); 497497883Sgibbs } 497597883Sgibbs } else { 497697883Sgibbs struct ahd_dma_seg *sg; 497797883Sgibbs 497897883Sgibbs sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); 497997883Sgibbs 498097883Sgibbs /* 498197883Sgibbs * The residual sg ptr points to the next S/G 498297883Sgibbs * to load so we must go back one. 498397883Sgibbs */ 498497883Sgibbs sg--; 4985123579Sgibbs sglen = aic_le32toh(sg->len) & AHD_SG_LEN_MASK; 498697883Sgibbs if (sg != scb->sg_list 498797883Sgibbs && sglen < (data_cnt & AHD_SG_LEN_MASK)) { 498897883Sgibbs 498997883Sgibbs sg--; 4990123579Sgibbs sglen = aic_le32toh(sg->len); 499197883Sgibbs /* 499297883Sgibbs * Preserve High Address and SG_LIST 499397883Sgibbs * bits while setting the count to 1. 499497883Sgibbs */ 499597883Sgibbs data_cnt = 1|(sglen&(~AHD_SG_LEN_MASK)); 4996123579Sgibbs data_addr = aic_le32toh(sg->addr) 499797883Sgibbs + (sglen & AHD_SG_LEN_MASK) 499897883Sgibbs - 1; 499997883Sgibbs 500097883Sgibbs /* 500197883Sgibbs * Increment sg so it points to the 500297883Sgibbs * "next" sg. 500397883Sgibbs */ 500497883Sgibbs sg++; 500597883Sgibbs sgptr = ahd_sg_virt_to_bus(ahd, scb, 500697883Sgibbs sg); 500797883Sgibbs } 500897883Sgibbs } 5009115335Sgibbs /* 5010115335Sgibbs * Toggle the "oddness" of the transfer length 5011115335Sgibbs * to handle this mid-transfer ignore wide 5012115335Sgibbs * residue. This ensures that the oddness is 5013115335Sgibbs * correct for subsequent data transfers. 5014115335Sgibbs */ 5015115335Sgibbs ahd_outb(ahd, SCB_TASK_ATTRIBUTE, 5016116940Sgibbs ahd_inb_scbram(ahd, SCB_TASK_ATTRIBUTE) 5017116940Sgibbs ^ SCB_XFERLEN_ODD); 501897883Sgibbs 5019115335Sgibbs ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr); 5020115335Sgibbs ahd_outl(ahd, SCB_RESIDUAL_DATACNT, data_cnt); 502197883Sgibbs /* 502297883Sgibbs * The FIFO's pointers will be updated if/when the 502397883Sgibbs * sequencer re-enters a data phase. 502497883Sgibbs */ 502597883Sgibbs } 502697883Sgibbs } 502797883Sgibbs} 502897883Sgibbs 502997883Sgibbs 503097883Sgibbs/* 503197883Sgibbs * Reinitialize the data pointers for the active transfer 503297883Sgibbs * based on its current residual. 503397883Sgibbs */ 503497883Sgibbsstatic void 503597883Sgibbsahd_reinitialize_dataptrs(struct ahd_softc *ahd) 503697883Sgibbs{ 503797883Sgibbs struct scb *scb; 503897883Sgibbs ahd_mode_state saved_modes; 503997883Sgibbs u_int scb_index; 504097883Sgibbs u_int wait; 504197883Sgibbs uint32_t sgptr; 504297883Sgibbs uint32_t resid; 504397883Sgibbs uint64_t dataptr; 504497883Sgibbs 504597883Sgibbs AHD_ASSERT_MODES(ahd, AHD_MODE_DFF0_MSK|AHD_MODE_DFF1_MSK, 504697883Sgibbs AHD_MODE_DFF0_MSK|AHD_MODE_DFF1_MSK); 504797883Sgibbs 504897883Sgibbs scb_index = ahd_get_scbptr(ahd); 504997883Sgibbs scb = ahd_lookup_scb(ahd, scb_index); 505097883Sgibbs 505197883Sgibbs /* 505297883Sgibbs * Release and reacquire the FIFO so we 505397883Sgibbs * have a clean slate. 505497883Sgibbs */ 505597883Sgibbs ahd_outb(ahd, DFFSXFRCTL, CLRCHN); 505697883Sgibbs wait = 1000; 5057116935Sgibbs while (--wait && !(ahd_inb(ahd, MDFFSTAT) & FIFOFREE)) 5058123579Sgibbs aic_delay(100); 505997883Sgibbs if (wait == 0) { 506097883Sgibbs ahd_print_path(ahd, scb); 506197883Sgibbs printf("ahd_reinitialize_dataptrs: Forcing FIFO free.\n"); 506297883Sgibbs ahd_outb(ahd, DFFSXFRCTL, RSTCHN|CLRSHCNT); 506397883Sgibbs } 506497883Sgibbs saved_modes = ahd_save_modes(ahd); 506597883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 506697883Sgibbs ahd_outb(ahd, DFFSTAT, 5067107441Sscottl ahd_inb(ahd, DFFSTAT) 5068107441Sscottl | (saved_modes == 0x11 ? CURRFIFO_1 : CURRFIFO_0)); 506997883Sgibbs 507097883Sgibbs /* 507197883Sgibbs * Determine initial values for data_addr and data_cnt 507297883Sgibbs * for resuming the data phase. 507397883Sgibbs */ 5074123579Sgibbs sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR); 507597883Sgibbs sgptr &= SG_PTR_MASK; 507697883Sgibbs 507797883Sgibbs resid = (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT + 2) << 16) 507897883Sgibbs | (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT + 1) << 8) 507997883Sgibbs | ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT); 508097883Sgibbs 508197883Sgibbs if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 508297883Sgibbs struct ahd_dma64_seg *sg; 508397883Sgibbs 508497883Sgibbs sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); 508597883Sgibbs 508697883Sgibbs /* The residual sg_ptr always points to the next sg */ 508797883Sgibbs sg--; 508897883Sgibbs 5089123579Sgibbs dataptr = aic_le64toh(sg->addr) 5090123579Sgibbs + (aic_le32toh(sg->len) & AHD_SG_LEN_MASK) 509197883Sgibbs - resid; 5092123579Sgibbs ahd_outl(ahd, HADDR + 4, dataptr >> 32); 509397883Sgibbs } else { 509497883Sgibbs struct ahd_dma_seg *sg; 509597883Sgibbs 509697883Sgibbs sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); 509797883Sgibbs 509897883Sgibbs /* The residual sg_ptr always points to the next sg */ 509997883Sgibbs sg--; 510097883Sgibbs 5101123579Sgibbs dataptr = aic_le32toh(sg->addr) 5102123579Sgibbs + (aic_le32toh(sg->len) & AHD_SG_LEN_MASK) 510397883Sgibbs - resid; 510497883Sgibbs ahd_outb(ahd, HADDR + 4, 5105123579Sgibbs (aic_le32toh(sg->len) & ~AHD_SG_LEN_MASK) >> 24); 510697883Sgibbs } 5107123579Sgibbs ahd_outl(ahd, HADDR, dataptr); 510897883Sgibbs ahd_outb(ahd, HCNT + 2, resid >> 16); 510997883Sgibbs ahd_outb(ahd, HCNT + 1, resid >> 8); 511097883Sgibbs ahd_outb(ahd, HCNT, resid); 511197883Sgibbs} 511297883Sgibbs 511397883Sgibbs/* 511497883Sgibbs * Handle the effects of issuing a bus device reset message. 511597883Sgibbs */ 511697883Sgibbsstatic void 511797883Sgibbsahd_handle_devreset(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 5118109588Sgibbs u_int lun, cam_status status, char *message, 5119109588Sgibbs int verbose_level) 512097883Sgibbs{ 512197883Sgibbs#ifdef AHD_TARGET_MODE 512297883Sgibbs struct ahd_tmode_tstate* tstate; 512397883Sgibbs#endif 512497883Sgibbs int found; 512597883Sgibbs 512697883Sgibbs found = ahd_abort_scbs(ahd, devinfo->target, devinfo->channel, 5127109588Sgibbs lun, SCB_LIST_NULL, devinfo->role, 512897883Sgibbs status); 512997883Sgibbs 513097883Sgibbs#ifdef AHD_TARGET_MODE 513197883Sgibbs /* 513297883Sgibbs * Send an immediate notify ccb to all target mord peripheral 513397883Sgibbs * drivers affected by this action. 513497883Sgibbs */ 513597883Sgibbs tstate = ahd->enabled_targets[devinfo->our_scsiid]; 513697883Sgibbs if (tstate != NULL) { 5137109588Sgibbs u_int cur_lun; 5138109588Sgibbs u_int max_lun; 5139109588Sgibbs 5140109588Sgibbs if (lun != CAM_LUN_WILDCARD) { 5141109588Sgibbs cur_lun = 0; 5142109588Sgibbs max_lun = AHD_NUM_LUNS - 1; 5143109588Sgibbs } else { 5144109588Sgibbs cur_lun = lun; 5145109588Sgibbs max_lun = lun; 5146109588Sgibbs } 5147109588Sgibbs for (cur_lun <= max_lun; cur_lun++) { 514897883Sgibbs struct ahd_tmode_lstate* lstate; 514997883Sgibbs 5150109588Sgibbs lstate = tstate->enabled_luns[cur_lun]; 515197883Sgibbs if (lstate == NULL) 515297883Sgibbs continue; 515397883Sgibbs 515497883Sgibbs ahd_queue_lstate_event(ahd, lstate, devinfo->our_scsiid, 515597883Sgibbs MSG_BUS_DEV_RESET, /*arg*/0); 515697883Sgibbs ahd_send_lstate_events(ahd, lstate); 515797883Sgibbs } 515897883Sgibbs } 515997883Sgibbs#endif 516097883Sgibbs 516197883Sgibbs /* 516297883Sgibbs * Go back to async/narrow transfers and renegotiate. 516397883Sgibbs */ 516497883Sgibbs ahd_set_width(ahd, devinfo, MSG_EXT_WDTR_BUS_8_BIT, 516597883Sgibbs AHD_TRANS_CUR, /*paused*/TRUE); 516697883Sgibbs ahd_set_syncrate(ahd, devinfo, /*period*/0, /*offset*/0, 5167129134Sgibbs /*ppr_options*/0, AHD_TRANS_CUR, 5168129134Sgibbs /*paused*/TRUE); 516997883Sgibbs 5170129134Sgibbs if (status != CAM_SEL_TIMEOUT) 5171129134Sgibbs ahd_send_async(ahd, devinfo->channel, devinfo->target, 5172129134Sgibbs lun, AC_SENT_BDR, NULL); 517397883Sgibbs 517497883Sgibbs if (message != NULL 5175199260Sattilio && (verbose_level <= bootverbose)) { 5176199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 517797883Sgibbs printf("%s: %s on %c:%d. %d SCBs aborted\n", ahd_name(ahd), 517897883Sgibbs message, devinfo->channel, devinfo->target, found); 5179199260Sattilio } 518097883Sgibbs} 518197883Sgibbs 518297883Sgibbs#ifdef AHD_TARGET_MODE 518397883Sgibbsstatic void 518497883Sgibbsahd_setup_target_msgin(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 518597883Sgibbs struct scb *scb) 518697883Sgibbs{ 518797883Sgibbs 518897883Sgibbs /* 518997883Sgibbs * To facilitate adding multiple messages together, 519097883Sgibbs * each routine should increment the index and len 519197883Sgibbs * variables instead of setting them explicitly. 519297883Sgibbs */ 519397883Sgibbs ahd->msgout_index = 0; 519497883Sgibbs ahd->msgout_len = 0; 519597883Sgibbs 519697883Sgibbs if (scb != NULL && (scb->flags & SCB_AUTO_NEGOTIATE) != 0) 519797883Sgibbs ahd_build_transfer_msg(ahd, devinfo); 519897883Sgibbs else 519997883Sgibbs panic("ahd_intr: AWAITING target message with no message"); 520097883Sgibbs 520197883Sgibbs ahd->msgout_index = 0; 520297883Sgibbs ahd->msg_type = MSG_TYPE_TARGET_MSGIN; 520397883Sgibbs} 520497883Sgibbs#endif 520597883Sgibbs/**************************** Initialization **********************************/ 5206106803Sscottlstatic u_int 520797883Sgibbsahd_sglist_size(struct ahd_softc *ahd) 520897883Sgibbs{ 520997883Sgibbs bus_size_t list_size; 521097883Sgibbs 521197883Sgibbs list_size = sizeof(struct ahd_dma_seg) * AHD_NSEG; 521297883Sgibbs if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) 521397883Sgibbs list_size = sizeof(struct ahd_dma64_seg) * AHD_NSEG; 521497883Sgibbs return (list_size); 521597883Sgibbs} 521697883Sgibbs 521797883Sgibbs/* 521897883Sgibbs * Calculate the optimum S/G List allocation size. S/G elements used 521997883Sgibbs * for a given transaction must be physically contiguous. Assume the 522097883Sgibbs * OS will allocate full pages to us, so it doesn't make sense to request 522197883Sgibbs * less than a page. 522297883Sgibbs */ 5223106803Sscottlstatic u_int 522497883Sgibbsahd_sglist_allocsize(struct ahd_softc *ahd) 522597883Sgibbs{ 522697883Sgibbs bus_size_t sg_list_increment; 522797883Sgibbs bus_size_t sg_list_size; 522897883Sgibbs bus_size_t max_list_size; 522997883Sgibbs bus_size_t best_list_size; 523097883Sgibbs 523197883Sgibbs /* Start out with the minimum required for AHD_NSEG. */ 523297883Sgibbs sg_list_increment = ahd_sglist_size(ahd); 523397883Sgibbs sg_list_size = sg_list_increment; 523497883Sgibbs 523597883Sgibbs /* Get us as close as possible to a page in size. */ 523697883Sgibbs while ((sg_list_size + sg_list_increment) <= PAGE_SIZE) 523797883Sgibbs sg_list_size += sg_list_increment; 523897883Sgibbs 523997883Sgibbs /* 524097883Sgibbs * Try to reduce the amount of wastage by allocating 524197883Sgibbs * multiple pages. 524297883Sgibbs */ 524397883Sgibbs best_list_size = sg_list_size; 524497883Sgibbs max_list_size = roundup(sg_list_increment, PAGE_SIZE); 524597883Sgibbs if (max_list_size < 4 * PAGE_SIZE) 524697883Sgibbs max_list_size = 4 * PAGE_SIZE; 524797883Sgibbs if (max_list_size > (AHD_SCB_MAX_ALLOC * sg_list_increment)) 524897883Sgibbs max_list_size = (AHD_SCB_MAX_ALLOC * sg_list_increment); 524997883Sgibbs while ((sg_list_size + sg_list_increment) <= max_list_size 525097883Sgibbs && (sg_list_size % PAGE_SIZE) != 0) { 525197883Sgibbs bus_size_t new_mod; 525297883Sgibbs bus_size_t best_mod; 525397883Sgibbs 525497883Sgibbs sg_list_size += sg_list_increment; 525597883Sgibbs new_mod = sg_list_size % PAGE_SIZE; 525697883Sgibbs best_mod = best_list_size % PAGE_SIZE; 525797883Sgibbs if (new_mod > best_mod || new_mod == 0) { 525897883Sgibbs best_list_size = sg_list_size; 525997883Sgibbs } 526097883Sgibbs } 526197883Sgibbs return (best_list_size); 526297883Sgibbs} 526397883Sgibbs 526497883Sgibbs/* 526597883Sgibbs * Allocate a controller structure for a new device 526697883Sgibbs * and perform initial initializion. 526797883Sgibbs */ 526897883Sgibbsstruct ahd_softc * 526997883Sgibbsahd_alloc(void *platform_arg, char *name) 527097883Sgibbs{ 527197883Sgibbs struct ahd_softc *ahd; 527297883Sgibbs 527397883Sgibbs#ifndef __FreeBSD__ 527497883Sgibbs ahd = malloc(sizeof(*ahd), M_DEVBUF, M_NOWAIT); 527597883Sgibbs if (!ahd) { 527697883Sgibbs printf("aic7xxx: cannot malloc softc!\n"); 527797883Sgibbs free(name, M_DEVBUF); 527897883Sgibbs return NULL; 527997883Sgibbs } 528097883Sgibbs#else 528197883Sgibbs ahd = device_get_softc((device_t)platform_arg); 528297883Sgibbs#endif 528397883Sgibbs memset(ahd, 0, sizeof(*ahd)); 528497883Sgibbs ahd->seep_config = malloc(sizeof(*ahd->seep_config), 528597883Sgibbs M_DEVBUF, M_NOWAIT); 528697883Sgibbs if (ahd->seep_config == NULL) { 528797883Sgibbs#ifndef __FreeBSD__ 528897883Sgibbs free(ahd, M_DEVBUF); 528997883Sgibbs#endif 529097883Sgibbs free(name, M_DEVBUF); 529197883Sgibbs return (NULL); 529297883Sgibbs } 529397883Sgibbs LIST_INIT(&ahd->pending_scbs); 5294141978Sgibbs LIST_INIT(&ahd->timedout_scbs); 529597883Sgibbs /* We don't know our unit number until the OSM sets it */ 529697883Sgibbs ahd->name = name; 529797883Sgibbs ahd->unit = -1; 529897883Sgibbs ahd->description = NULL; 529997883Sgibbs ahd->bus_description = NULL; 530097883Sgibbs ahd->channel = 'A'; 530197883Sgibbs ahd->chip = AHD_NONE; 530297883Sgibbs ahd->features = AHD_FENONE; 530397883Sgibbs ahd->bugs = AHD_BUGNONE; 530497883Sgibbs ahd->flags = AHD_SPCHK_ENB_A|AHD_RESET_BUS_A|AHD_TERM_ENB_A 530597883Sgibbs | AHD_EXTENDED_TRANS_A|AHD_STPWLEVEL_A; 5306123579Sgibbs aic_timer_init(&ahd->reset_timer); 5307123579Sgibbs aic_timer_init(&ahd->stat_timer); 5308115329Sgibbs ahd->int_coalescing_timer = AHD_INT_COALESCING_TIMER_DEFAULT; 5309115329Sgibbs ahd->int_coalescing_maxcmds = AHD_INT_COALESCING_MAXCMDS_DEFAULT; 5310115329Sgibbs ahd->int_coalescing_mincmds = AHD_INT_COALESCING_MINCMDS_DEFAULT; 5311115329Sgibbs ahd->int_coalescing_threshold = AHD_INT_COALESCING_THRESHOLD_DEFAULT; 5312115329Sgibbs ahd->int_coalescing_stop_threshold = 5313115329Sgibbs AHD_INT_COALESCING_STOP_THRESHOLD_DEFAULT; 531497883Sgibbs 531597883Sgibbs if (ahd_platform_alloc(ahd, platform_arg) != 0) { 531697883Sgibbs ahd_free(ahd); 531797883Sgibbs ahd = NULL; 531897883Sgibbs } 5319168807Sscottl ahd_lockinit(ahd); 5320102679Sgibbs#ifdef AHD_DEBUG 5321102679Sgibbs if ((ahd_debug & AHD_SHOW_MEMORY) != 0) { 5322106803Sscottl printf("%s: scb size = 0x%x, hscb size = 0x%x\n", 5323106803Sscottl ahd_name(ahd), (u_int)sizeof(struct scb), 5324106803Sscottl (u_int)sizeof(struct hardware_scb)); 5325102679Sgibbs } 5326102679Sgibbs#endif 532797883Sgibbs return (ahd); 532897883Sgibbs} 532997883Sgibbs 533097883Sgibbsint 533197883Sgibbsahd_softc_init(struct ahd_softc *ahd) 533297883Sgibbs{ 533397883Sgibbs 533497883Sgibbs ahd->unpause = 0; 533597883Sgibbs ahd->pause = PAUSE; 533697883Sgibbs return (0); 533797883Sgibbs} 533897883Sgibbs 533997883Sgibbsvoid 534097883Sgibbsahd_softc_insert(struct ahd_softc *ahd) 534197883Sgibbs{ 534297883Sgibbs struct ahd_softc *list_ahd; 534397883Sgibbs 5344123579Sgibbs#if AIC_PCI_CONFIG > 0 534597883Sgibbs /* 534697883Sgibbs * Second Function PCI devices need to inherit some 534797883Sgibbs * settings from function 0. 534897883Sgibbs */ 534997883Sgibbs if ((ahd->features & AHD_MULTI_FUNC) != 0) { 535097883Sgibbs TAILQ_FOREACH(list_ahd, &ahd_tailq, links) { 5351123579Sgibbs aic_dev_softc_t list_pci; 5352123579Sgibbs aic_dev_softc_t pci; 535397883Sgibbs 535497883Sgibbs list_pci = list_ahd->dev_softc; 535597883Sgibbs pci = ahd->dev_softc; 5356123579Sgibbs if (aic_get_pci_slot(list_pci) == aic_get_pci_slot(pci) 5357123579Sgibbs && aic_get_pci_bus(list_pci) == aic_get_pci_bus(pci)) { 535897883Sgibbs struct ahd_softc *master; 535997883Sgibbs struct ahd_softc *slave; 536097883Sgibbs 5361123579Sgibbs if (aic_get_pci_function(list_pci) == 0) { 536297883Sgibbs master = list_ahd; 536397883Sgibbs slave = ahd; 536497883Sgibbs } else { 536597883Sgibbs master = ahd; 536697883Sgibbs slave = list_ahd; 536797883Sgibbs } 536897883Sgibbs slave->flags &= ~AHD_BIOS_ENABLED; 536997883Sgibbs slave->flags |= 537097883Sgibbs master->flags & AHD_BIOS_ENABLED; 537197883Sgibbs break; 537297883Sgibbs } 537397883Sgibbs } 537497883Sgibbs } 537597883Sgibbs#endif 537697883Sgibbs 537797883Sgibbs /* 537897883Sgibbs * Insertion sort into our list of softcs. 537997883Sgibbs */ 538097883Sgibbs list_ahd = TAILQ_FIRST(&ahd_tailq); 538197883Sgibbs while (list_ahd != NULL 5382114623Sgibbs && ahd_softc_comp(ahd, list_ahd) <= 0) 538397883Sgibbs list_ahd = TAILQ_NEXT(list_ahd, links); 538497883Sgibbs if (list_ahd != NULL) 538597883Sgibbs TAILQ_INSERT_BEFORE(list_ahd, ahd, links); 538697883Sgibbs else 538797883Sgibbs TAILQ_INSERT_TAIL(&ahd_tailq, ahd, links); 538897883Sgibbs ahd->init_level++; 538997883Sgibbs} 539097883Sgibbs 539197883Sgibbsvoid 539297883Sgibbsahd_set_unit(struct ahd_softc *ahd, int unit) 539397883Sgibbs{ 539497883Sgibbs ahd->unit = unit; 539597883Sgibbs} 539697883Sgibbs 539797883Sgibbsvoid 539897883Sgibbsahd_set_name(struct ahd_softc *ahd, char *name) 539997883Sgibbs{ 540097883Sgibbs if (ahd->name != NULL) 540197883Sgibbs free(ahd->name, M_DEVBUF); 540297883Sgibbs ahd->name = name; 540397883Sgibbs} 540497883Sgibbs 540597883Sgibbsvoid 540697883Sgibbsahd_free(struct ahd_softc *ahd) 540797883Sgibbs{ 540897883Sgibbs int i; 540997883Sgibbs 5410123579Sgibbs ahd_terminate_recovery_thread(ahd); 541197883Sgibbs switch (ahd->init_level) { 541297883Sgibbs default: 541397883Sgibbs case 5: 541497883Sgibbs ahd_shutdown(ahd); 541597883Sgibbs /* FALLTHROUGH */ 541697883Sgibbs case 4: 5417123579Sgibbs aic_dmamap_unload(ahd, ahd->shared_data_dmat, 5418123579Sgibbs ahd->shared_data_map.dmamap); 541997883Sgibbs /* FALLTHROUGH */ 542097883Sgibbs case 3: 5421123579Sgibbs aic_dmamem_free(ahd, ahd->shared_data_dmat, ahd->qoutfifo, 5422123579Sgibbs ahd->shared_data_map.dmamap); 5423123579Sgibbs aic_dmamap_destroy(ahd, ahd->shared_data_dmat, 5424123579Sgibbs ahd->shared_data_map.dmamap); 542597883Sgibbs /* FALLTHROUGH */ 542697883Sgibbs case 2: 5427123579Sgibbs aic_dma_tag_destroy(ahd, ahd->shared_data_dmat); 542897883Sgibbs case 1: 542997883Sgibbs#ifndef __linux__ 5430123579Sgibbs aic_dma_tag_destroy(ahd, ahd->buffer_dmat); 543197883Sgibbs#endif 543297883Sgibbs break; 543397883Sgibbs case 0: 543497883Sgibbs break; 543597883Sgibbs } 543697883Sgibbs 543797883Sgibbs#ifndef __linux__ 5438123579Sgibbs aic_dma_tag_destroy(ahd, ahd->parent_dmat); 543997883Sgibbs#endif 544097883Sgibbs ahd_platform_free(ahd); 5441114623Sgibbs ahd_fini_scbdata(ahd); 544297883Sgibbs for (i = 0; i < AHD_NUM_TARGETS; i++) { 544397883Sgibbs struct ahd_tmode_tstate *tstate; 544497883Sgibbs 544597883Sgibbs tstate = ahd->enabled_targets[i]; 544697883Sgibbs if (tstate != NULL) { 5447153072Sru#ifdef AHD_TARGET_MODE 544897883Sgibbs int j; 544997883Sgibbs 545097883Sgibbs for (j = 0; j < AHD_NUM_LUNS; j++) { 545197883Sgibbs struct ahd_tmode_lstate *lstate; 545297883Sgibbs 545397883Sgibbs lstate = tstate->enabled_luns[j]; 545497883Sgibbs if (lstate != NULL) { 545597883Sgibbs xpt_free_path(lstate->path); 545697883Sgibbs free(lstate, M_DEVBUF); 545797883Sgibbs } 545897883Sgibbs } 545997883Sgibbs#endif 546097883Sgibbs free(tstate, M_DEVBUF); 546197883Sgibbs } 546297883Sgibbs } 5463153072Sru#ifdef AHD_TARGET_MODE 546497883Sgibbs if (ahd->black_hole != NULL) { 546597883Sgibbs xpt_free_path(ahd->black_hole->path); 546697883Sgibbs free(ahd->black_hole, M_DEVBUF); 546797883Sgibbs } 546897883Sgibbs#endif 546997883Sgibbs if (ahd->name != NULL) 547097883Sgibbs free(ahd->name, M_DEVBUF); 547197883Sgibbs if (ahd->seep_config != NULL) 547297883Sgibbs free(ahd->seep_config, M_DEVBUF); 5473107441Sscottl if (ahd->saved_stack != NULL) 5474107441Sscottl free(ahd->saved_stack, M_DEVBUF); 547597883Sgibbs#ifndef __FreeBSD__ 547697883Sgibbs free(ahd, M_DEVBUF); 547797883Sgibbs#endif 547897883Sgibbs return; 547997883Sgibbs} 548097883Sgibbs 548197883Sgibbsvoid 548297883Sgibbsahd_shutdown(void *arg) 548397883Sgibbs{ 548497883Sgibbs struct ahd_softc *ahd; 548597883Sgibbs 548697883Sgibbs ahd = (struct ahd_softc *)arg; 548797883Sgibbs 5488109588Sgibbs /* 5489109588Sgibbs * Stop periodic timer callbacks. 5490109588Sgibbs */ 5491123579Sgibbs aic_timer_stop(&ahd->reset_timer); 5492123579Sgibbs aic_timer_stop(&ahd->stat_timer); 5493109588Sgibbs 549497883Sgibbs /* This will reset most registers to 0, but not all */ 5495115917Sgibbs ahd_reset(ahd, /*reinit*/FALSE); 549697883Sgibbs} 549797883Sgibbs 549897883Sgibbs/* 549997883Sgibbs * Reset the controller and record some information about it 5500115917Sgibbs * that is only available just after a reset. If "reinit" is 5501115917Sgibbs * non-zero, this reset occured after initial configuration 5502115917Sgibbs * and the caller requests that the chip be fully reinitialized 5503115917Sgibbs * to a runable state. Chip interrupts are *not* enabled after 5504115917Sgibbs * a reinitialization. The caller must enable interrupts via 5505115917Sgibbs * ahd_intr_enable(). 550697883Sgibbs */ 550797883Sgibbsint 5508115917Sgibbsahd_reset(struct ahd_softc *ahd, int reinit) 550997883Sgibbs{ 551097883Sgibbs u_int sxfrctl1; 551197883Sgibbs int wait; 551297883Sgibbs uint32_t cmd; 551397883Sgibbs 551497883Sgibbs /* 551597883Sgibbs * Preserve the value of the SXFRCTL1 register for all channels. 551697883Sgibbs * It contains settings that affect termination and we don't want 551797883Sgibbs * to disturb the integrity of the bus. 551897883Sgibbs */ 551997883Sgibbs ahd_pause(ahd); 5520111954Sgibbs ahd_update_modes(ahd); 5521111653Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 552297883Sgibbs sxfrctl1 = ahd_inb(ahd, SXFRCTL1); 552397883Sgibbs 5524123579Sgibbs cmd = aic_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2); 552597883Sgibbs if ((ahd->bugs & AHD_PCIX_CHIPRST_BUG) != 0) { 552697883Sgibbs uint32_t mod_cmd; 552797883Sgibbs 552897883Sgibbs /* 552997883Sgibbs * A4 Razor #632 553097883Sgibbs * During the assertion of CHIPRST, the chip 553197883Sgibbs * does not disable its parity logic prior to 553297883Sgibbs * the start of the reset. This may cause a 553397883Sgibbs * parity error to be detected and thus a 553497883Sgibbs * spurious SERR or PERR assertion. Disble 553597883Sgibbs * PERR and SERR responses during the CHIPRST. 553697883Sgibbs */ 553797883Sgibbs mod_cmd = cmd & ~(PCIM_CMD_PERRESPEN|PCIM_CMD_SERRESPEN); 5538123579Sgibbs aic_pci_write_config(ahd->dev_softc, PCIR_COMMAND, 553997883Sgibbs mod_cmd, /*bytes*/2); 554097883Sgibbs } 554197883Sgibbs ahd_outb(ahd, HCNTRL, CHIPRST | ahd->pause); 554297883Sgibbs 554397883Sgibbs /* 554497883Sgibbs * Ensure that the reset has finished. We delay 1000us 554597883Sgibbs * prior to reading the register to make sure the chip 554697883Sgibbs * has sufficiently completed its reset to handle register 554797883Sgibbs * accesses. 554897883Sgibbs */ 554997883Sgibbs wait = 1000; 555097883Sgibbs do { 5551123579Sgibbs aic_delay(1000); 555297883Sgibbs } while (--wait && !(ahd_inb(ahd, HCNTRL) & CHIPRSTACK)); 555397883Sgibbs 555497883Sgibbs if (wait == 0) { 555597883Sgibbs printf("%s: WARNING - Failed chip reset! " 555697883Sgibbs "Trying to initialize anyway.\n", ahd_name(ahd)); 5557199260Sattilio AHD_FATAL_ERROR(ahd); 555897883Sgibbs } 555997883Sgibbs ahd_outb(ahd, HCNTRL, ahd->pause); 556097883Sgibbs 556197883Sgibbs if ((ahd->bugs & AHD_PCIX_CHIPRST_BUG) != 0) { 556297883Sgibbs /* 556397883Sgibbs * Clear any latched PCI error status and restore 556497883Sgibbs * previous SERR and PERR response enables. 556597883Sgibbs */ 5566123579Sgibbs aic_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1, 556797883Sgibbs 0xFF, /*bytes*/1); 5568123579Sgibbs aic_pci_write_config(ahd->dev_softc, PCIR_COMMAND, 556997883Sgibbs cmd, /*bytes*/2); 557097883Sgibbs } 5571111653Sgibbs 5572111653Sgibbs /* 5573111653Sgibbs * Mode should be SCSI after a chip reset, but lets 5574111954Sgibbs * set it just to be safe. We touch the MODE_PTR 5575111954Sgibbs * register directly so as to bypass the lazy update 5576111954Sgibbs * code in ahd_set_modes(). 5577111653Sgibbs */ 557897883Sgibbs ahd_known_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 5579111954Sgibbs ahd_outb(ahd, MODE_PTR, 5580111954Sgibbs ahd_build_mode_state(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI)); 558197883Sgibbs 558297883Sgibbs /* 558397883Sgibbs * Restore SXFRCTL1. 558497883Sgibbs * 558597883Sgibbs * We must always initialize STPWEN to 1 before we 558697883Sgibbs * restore the saved values. STPWEN is initialized 558797883Sgibbs * to a tri-state condition which can only be cleared 558897883Sgibbs * by turning it on. 558997883Sgibbs */ 559097883Sgibbs ahd_outb(ahd, SXFRCTL1, sxfrctl1|STPWEN); 559197883Sgibbs ahd_outb(ahd, SXFRCTL1, sxfrctl1); 559297883Sgibbs 5593111653Sgibbs /* Determine chip configuration */ 5594111653Sgibbs ahd->features &= ~AHD_WIDE; 5595111653Sgibbs if ((ahd_inb(ahd, SBLKCTL) & SELWIDE) != 0) 5596111653Sgibbs ahd->features |= AHD_WIDE; 5597111653Sgibbs 559897883Sgibbs /* 559997883Sgibbs * If a recovery action has forced a chip reset, 5600111653Sgibbs * re-initialize the chip to our liking. 560197883Sgibbs */ 5602115917Sgibbs if (reinit != 0) 560397883Sgibbs ahd_chip_init(ahd); 560497883Sgibbs 560597883Sgibbs return (0); 560697883Sgibbs} 560797883Sgibbs 560897883Sgibbs/* 560997883Sgibbs * Determine the number of SCBs available on the controller 561097883Sgibbs */ 561197883Sgibbsint 561297883Sgibbsahd_probe_scbs(struct ahd_softc *ahd) { 561397883Sgibbs int i; 561497883Sgibbs 561597883Sgibbs AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 561697883Sgibbs ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 561797883Sgibbs for (i = 0; i < AHD_SCB_MAX; i++) { 561897883Sgibbs int j; 561997883Sgibbs 562097883Sgibbs ahd_set_scbptr(ahd, i); 562197883Sgibbs ahd_outw(ahd, SCB_BASE, i); 562297883Sgibbs for (j = 2; j < 64; j++) 562397883Sgibbs ahd_outb(ahd, SCB_BASE+j, 0); 562497883Sgibbs /* Start out life as unallocated (needing an abort) */ 562597883Sgibbs ahd_outb(ahd, SCB_CONTROL, MK_MESSAGE); 562697883Sgibbs if (ahd_inw_scbram(ahd, SCB_BASE) != i) 562797883Sgibbs break; 562897883Sgibbs ahd_set_scbptr(ahd, 0); 562997883Sgibbs if (ahd_inw_scbram(ahd, SCB_BASE) != 0) 563097883Sgibbs break; 563197883Sgibbs } 563297883Sgibbs return (i); 563397883Sgibbs} 563497883Sgibbs 563597883Sgibbsstatic void 563697883Sgibbsahd_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 563797883Sgibbs{ 563897883Sgibbs bus_addr_t *baddr; 563997883Sgibbs 564097883Sgibbs baddr = (bus_addr_t *)arg; 564197883Sgibbs *baddr = segs->ds_addr; 564297883Sgibbs} 564397883Sgibbs 564497883Sgibbsstatic void 564597883Sgibbsahd_initialize_hscbs(struct ahd_softc *ahd) 564697883Sgibbs{ 564797883Sgibbs int i; 564897883Sgibbs 564997883Sgibbs for (i = 0; i < ahd->scb_data.maxhscbs; i++) { 565097883Sgibbs ahd_set_scbptr(ahd, i); 565197883Sgibbs 565297883Sgibbs /* Clear the control byte. */ 565397883Sgibbs ahd_outb(ahd, SCB_CONTROL, 0); 565497883Sgibbs 565597883Sgibbs /* Set the next pointer */ 565697883Sgibbs ahd_outw(ahd, SCB_NEXT, SCB_LIST_NULL); 565797883Sgibbs } 565897883Sgibbs} 565997883Sgibbs 566097883Sgibbsstatic int 566197883Sgibbsahd_init_scbdata(struct ahd_softc *ahd) 566297883Sgibbs{ 5663102679Sgibbs struct scb_data *scb_data; 5664102679Sgibbs int i; 566597883Sgibbs 566697883Sgibbs scb_data = &ahd->scb_data; 5667102679Sgibbs TAILQ_INIT(&scb_data->free_scbs); 5668102679Sgibbs for (i = 0; i < AHD_NUM_TARGETS * AHD_NUM_LUNS_NONPKT; i++) 5669102679Sgibbs LIST_INIT(&scb_data->free_scb_lists[i]); 5670102679Sgibbs LIST_INIT(&scb_data->any_dev_free_scb_list); 567197883Sgibbs SLIST_INIT(&scb_data->hscb_maps); 567297883Sgibbs SLIST_INIT(&scb_data->sg_maps); 567397883Sgibbs SLIST_INIT(&scb_data->sense_maps); 567497883Sgibbs 567597883Sgibbs /* Determine the number of hardware SCBs and initialize them */ 567697883Sgibbs scb_data->maxhscbs = ahd_probe_scbs(ahd); 567797883Sgibbs if (scb_data->maxhscbs == 0) { 567897883Sgibbs printf("%s: No SCB space found\n", ahd_name(ahd)); 5679199260Sattilio AHD_FATAL_ERROR(ahd); 568097883Sgibbs return (ENXIO); 568197883Sgibbs } 568297883Sgibbs 568397883Sgibbs ahd_initialize_hscbs(ahd); 568497883Sgibbs 568597883Sgibbs /* 568697883Sgibbs * Create our DMA tags. These tags define the kinds of device 568797883Sgibbs * accessible memory allocations and memory mappings we will 568897883Sgibbs * need to perform during normal operation. 568997883Sgibbs * 569097883Sgibbs * Unless we need to further restrict the allocation, we rely 569197883Sgibbs * on the restrictions of the parent dmat, hence the common 569297883Sgibbs * use of MAXADDR and MAXSIZE. 569397883Sgibbs */ 569497883Sgibbs 569597883Sgibbs /* DMA tag for our hardware scb structures */ 5696123579Sgibbs if (aic_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, 569797883Sgibbs /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, 569897883Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 569997883Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 570097883Sgibbs /*filter*/NULL, /*filterarg*/NULL, 570197883Sgibbs PAGE_SIZE, /*nsegments*/1, 570297883Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 570397883Sgibbs /*flags*/0, &scb_data->hscb_dmat) != 0) { 570497883Sgibbs goto error_exit; 570597883Sgibbs } 570697883Sgibbs 570797883Sgibbs scb_data->init_level++; 570897883Sgibbs 570997883Sgibbs /* DMA tag for our S/G structures. */ 5710123579Sgibbs if (aic_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/8, 571197883Sgibbs /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, 571297883Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 571397883Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 571497883Sgibbs /*filter*/NULL, /*filterarg*/NULL, 571597883Sgibbs ahd_sglist_allocsize(ahd), /*nsegments*/1, 571697883Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 571797883Sgibbs /*flags*/0, &scb_data->sg_dmat) != 0) { 571897883Sgibbs goto error_exit; 571997883Sgibbs } 572097883Sgibbs#ifdef AHD_DEBUG 572197883Sgibbs if ((ahd_debug & AHD_SHOW_MEMORY) != 0) 572297883Sgibbs printf("%s: ahd_sglist_allocsize = 0x%x\n", ahd_name(ahd), 572397883Sgibbs ahd_sglist_allocsize(ahd)); 572497883Sgibbs#endif 572597883Sgibbs 572697883Sgibbs scb_data->init_level++; 572797883Sgibbs 572897883Sgibbs /* DMA tag for our sense buffers. We allocate in page sized chunks */ 5729123579Sgibbs if (aic_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, 573097883Sgibbs /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, 573197883Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 573297883Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 573397883Sgibbs /*filter*/NULL, /*filterarg*/NULL, 573497883Sgibbs PAGE_SIZE, /*nsegments*/1, 573597883Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 573697883Sgibbs /*flags*/0, &scb_data->sense_dmat) != 0) { 573797883Sgibbs goto error_exit; 573897883Sgibbs } 573997883Sgibbs 574097883Sgibbs scb_data->init_level++; 574197883Sgibbs 574297883Sgibbs /* Perform initial CCB allocation */ 5743168873Sscottl while (ahd_alloc_scbs(ahd) != 0) 5744168873Sscottl ; 574597883Sgibbs 574697883Sgibbs if (scb_data->numscbs == 0) { 574797883Sgibbs printf("%s: ahd_init_scbdata - " 574897883Sgibbs "Unable to allocate initial scbs\n", 574997883Sgibbs ahd_name(ahd)); 575097883Sgibbs goto error_exit; 575197883Sgibbs } 575297883Sgibbs 575397883Sgibbs /* 575497883Sgibbs * Note that we were successfull 575597883Sgibbs */ 575697883Sgibbs return (0); 575797883Sgibbs 575897883Sgibbserror_exit: 575997883Sgibbs 576097883Sgibbs return (ENOMEM); 576197883Sgibbs} 576297883Sgibbs 5763102679Sgibbsstatic struct scb * 5764102679Sgibbsahd_find_scb_by_tag(struct ahd_softc *ahd, u_int tag) 5765102679Sgibbs{ 5766102679Sgibbs struct scb *scb; 5767102679Sgibbs 5768102679Sgibbs /* 5769102679Sgibbs * Look on the pending list. 5770102679Sgibbs */ 5771102679Sgibbs LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) { 5772102679Sgibbs if (SCB_GET_TAG(scb) == tag) 5773102679Sgibbs return (scb); 5774102679Sgibbs } 5775102679Sgibbs 5776102679Sgibbs /* 5777102679Sgibbs * Then on all of the collision free lists. 5778102679Sgibbs */ 5779102679Sgibbs TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) { 5780102679Sgibbs struct scb *list_scb; 5781102679Sgibbs 5782102679Sgibbs list_scb = scb; 5783102679Sgibbs do { 5784102679Sgibbs if (SCB_GET_TAG(list_scb) == tag) 5785102679Sgibbs return (list_scb); 5786102679Sgibbs list_scb = LIST_NEXT(list_scb, collision_links); 5787102679Sgibbs } while (list_scb); 5788102679Sgibbs } 5789102679Sgibbs 5790102679Sgibbs /* 5791102679Sgibbs * And finally on the generic free list. 5792102679Sgibbs */ 5793102679Sgibbs LIST_FOREACH(scb, &ahd->scb_data.any_dev_free_scb_list, links.le) { 5794102679Sgibbs if (SCB_GET_TAG(scb) == tag) 5795102679Sgibbs return (scb); 5796102679Sgibbs } 5797102679Sgibbs 5798102679Sgibbs return (NULL); 5799102679Sgibbs} 5800102679Sgibbs 580197883Sgibbsstatic void 580297883Sgibbsahd_fini_scbdata(struct ahd_softc *ahd) 580397883Sgibbs{ 580497883Sgibbs struct scb_data *scb_data; 580597883Sgibbs 580697883Sgibbs scb_data = &ahd->scb_data; 580797883Sgibbs if (scb_data == NULL) 580897883Sgibbs return; 580997883Sgibbs 581097883Sgibbs switch (scb_data->init_level) { 581197883Sgibbs default: 581297883Sgibbs case 7: 581397883Sgibbs { 581497883Sgibbs struct map_node *sns_map; 581597883Sgibbs 581697883Sgibbs while ((sns_map = SLIST_FIRST(&scb_data->sense_maps)) != NULL) { 581797883Sgibbs SLIST_REMOVE_HEAD(&scb_data->sense_maps, links); 5818123579Sgibbs aic_dmamap_unload(ahd, scb_data->sense_dmat, 581997883Sgibbs sns_map->dmamap); 5820123579Sgibbs aic_dmamem_free(ahd, scb_data->sense_dmat, 582197883Sgibbs sns_map->vaddr, sns_map->dmamap); 582297883Sgibbs free(sns_map, M_DEVBUF); 582397883Sgibbs } 5824123579Sgibbs aic_dma_tag_destroy(ahd, scb_data->sense_dmat); 582597883Sgibbs /* FALLTHROUGH */ 582697883Sgibbs } 582797883Sgibbs case 6: 582897883Sgibbs { 582997883Sgibbs struct map_node *sg_map; 583097883Sgibbs 583197883Sgibbs while ((sg_map = SLIST_FIRST(&scb_data->sg_maps)) != NULL) { 583297883Sgibbs SLIST_REMOVE_HEAD(&scb_data->sg_maps, links); 5833123579Sgibbs aic_dmamap_unload(ahd, scb_data->sg_dmat, 583497883Sgibbs sg_map->dmamap); 5835123579Sgibbs aic_dmamem_free(ahd, scb_data->sg_dmat, 583697883Sgibbs sg_map->vaddr, sg_map->dmamap); 583797883Sgibbs free(sg_map, M_DEVBUF); 583897883Sgibbs } 5839123579Sgibbs aic_dma_tag_destroy(ahd, scb_data->sg_dmat); 584097883Sgibbs /* FALLTHROUGH */ 584197883Sgibbs } 584297883Sgibbs case 5: 584397883Sgibbs { 584497883Sgibbs struct map_node *hscb_map; 584597883Sgibbs 584697883Sgibbs while ((hscb_map = SLIST_FIRST(&scb_data->hscb_maps)) != NULL) { 584797883Sgibbs SLIST_REMOVE_HEAD(&scb_data->hscb_maps, links); 5848123579Sgibbs aic_dmamap_unload(ahd, scb_data->hscb_dmat, 584997883Sgibbs hscb_map->dmamap); 5850123579Sgibbs aic_dmamem_free(ahd, scb_data->hscb_dmat, 585197883Sgibbs hscb_map->vaddr, hscb_map->dmamap); 585297883Sgibbs free(hscb_map, M_DEVBUF); 585397883Sgibbs } 5854123579Sgibbs aic_dma_tag_destroy(ahd, scb_data->hscb_dmat); 585597883Sgibbs /* FALLTHROUGH */ 585697883Sgibbs } 585797883Sgibbs case 4: 585897883Sgibbs case 3: 585997883Sgibbs case 2: 586097883Sgibbs case 1: 586197883Sgibbs case 0: 586297883Sgibbs break; 586397883Sgibbs } 586497883Sgibbs} 586597883Sgibbs 586697883Sgibbs/* 586797883Sgibbs * DSP filter Bypass must be enabled until the first selection 586897883Sgibbs * after a change in bus mode (Razor #491 and #493). 586997883Sgibbs */ 587097883Sgibbsstatic void 587197883Sgibbsahd_setup_iocell_workaround(struct ahd_softc *ahd) 587297883Sgibbs{ 587397883Sgibbs ahd_mode_state saved_modes; 587497883Sgibbs 587597883Sgibbs saved_modes = ahd_save_modes(ahd); 587697883Sgibbs ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 587797883Sgibbs ahd_outb(ahd, DSPDATACTL, ahd_inb(ahd, DSPDATACTL) 587897883Sgibbs | BYPASSENAB | RCVROFFSTDIS | XMITOFFSTDIS); 587997883Sgibbs ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) | (ENSELDO|ENSELDI)); 5880104023Sgibbs#ifdef AHD_DEBUG 5881104023Sgibbs if ((ahd_debug & AHD_SHOW_MISC) != 0) 5882104023Sgibbs printf("%s: Setting up iocell workaround\n", ahd_name(ahd)); 5883104023Sgibbs#endif 588497883Sgibbs ahd_restore_modes(ahd, saved_modes); 5885116938Sgibbs ahd->flags &= ~AHD_HAD_FIRST_SEL; 588697883Sgibbs} 588797883Sgibbs 588897883Sgibbsstatic void 588997883Sgibbsahd_iocell_first_selection(struct ahd_softc *ahd) 589097883Sgibbs{ 589197883Sgibbs ahd_mode_state saved_modes; 589297883Sgibbs u_int sblkctl; 589397883Sgibbs 5894116938Sgibbs if ((ahd->flags & AHD_HAD_FIRST_SEL) != 0) 5895116938Sgibbs return; 589697883Sgibbs saved_modes = ahd_save_modes(ahd); 589797883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 589897883Sgibbs sblkctl = ahd_inb(ahd, SBLKCTL); 589997883Sgibbs ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 5900104023Sgibbs#ifdef AHD_DEBUG 5901104023Sgibbs if ((ahd_debug & AHD_SHOW_MISC) != 0) 5902104023Sgibbs printf("%s: iocell first selection\n", ahd_name(ahd)); 5903104023Sgibbs#endif 590497883Sgibbs if ((sblkctl & ENAB40) != 0) { 590597883Sgibbs ahd_outb(ahd, DSPDATACTL, 590697883Sgibbs ahd_inb(ahd, DSPDATACTL) & ~BYPASSENAB); 5907104023Sgibbs#ifdef AHD_DEBUG 5908104023Sgibbs if ((ahd_debug & AHD_SHOW_MISC) != 0) 5909104023Sgibbs printf("%s: BYPASS now disabled\n", ahd_name(ahd)); 5910104023Sgibbs#endif 591197883Sgibbs } 591297883Sgibbs ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) & ~(ENSELDO|ENSELDI)); 591397883Sgibbs ahd_outb(ahd, CLRINT, CLRSCSIINT); 591497883Sgibbs ahd_restore_modes(ahd, saved_modes); 5915116938Sgibbs ahd->flags |= AHD_HAD_FIRST_SEL; 591697883Sgibbs} 591797883Sgibbs 5918102679Sgibbs/*************************** SCB Management ***********************************/ 5919102679Sgibbsstatic void 5920102679Sgibbsahd_add_col_list(struct ahd_softc *ahd, struct scb *scb, u_int col_idx) 5921102679Sgibbs{ 5922102679Sgibbs struct scb_list *free_list; 5923102679Sgibbs struct scb_tailq *free_tailq; 5924102679Sgibbs struct scb *first_scb; 5925102679Sgibbs 5926102679Sgibbs scb->flags |= SCB_ON_COL_LIST; 5927102679Sgibbs AHD_SET_SCB_COL_IDX(scb, col_idx); 5928102679Sgibbs free_list = &ahd->scb_data.free_scb_lists[col_idx]; 5929102679Sgibbs free_tailq = &ahd->scb_data.free_scbs; 5930102679Sgibbs first_scb = LIST_FIRST(free_list); 5931102679Sgibbs if (first_scb != NULL) { 5932102679Sgibbs LIST_INSERT_AFTER(first_scb, scb, collision_links); 5933102679Sgibbs } else { 5934102679Sgibbs LIST_INSERT_HEAD(free_list, scb, collision_links); 5935102679Sgibbs TAILQ_INSERT_TAIL(free_tailq, scb, links.tqe); 5936102679Sgibbs } 5937102679Sgibbs} 5938102679Sgibbs 5939102679Sgibbsstatic void 5940102679Sgibbsahd_rem_col_list(struct ahd_softc *ahd, struct scb *scb) 5941102679Sgibbs{ 5942102679Sgibbs struct scb_list *free_list; 5943102679Sgibbs struct scb_tailq *free_tailq; 5944102679Sgibbs struct scb *first_scb; 5945102679Sgibbs u_int col_idx; 5946102679Sgibbs 5947102679Sgibbs scb->flags &= ~SCB_ON_COL_LIST; 5948102679Sgibbs col_idx = AHD_GET_SCB_COL_IDX(ahd, scb); 5949102679Sgibbs free_list = &ahd->scb_data.free_scb_lists[col_idx]; 5950102679Sgibbs free_tailq = &ahd->scb_data.free_scbs; 5951102679Sgibbs first_scb = LIST_FIRST(free_list); 5952102679Sgibbs if (first_scb == scb) { 5953102679Sgibbs struct scb *next_scb; 5954102679Sgibbs 5955102679Sgibbs /* 5956102679Sgibbs * Maintain order in the collision free 5957102679Sgibbs * lists for fairness if this device has 5958102679Sgibbs * other colliding tags active. 5959102679Sgibbs */ 5960102679Sgibbs next_scb = LIST_NEXT(scb, collision_links); 5961102679Sgibbs if (next_scb != NULL) { 5962102679Sgibbs TAILQ_INSERT_AFTER(free_tailq, scb, 5963102679Sgibbs next_scb, links.tqe); 5964102679Sgibbs } 5965102679Sgibbs TAILQ_REMOVE(free_tailq, scb, links.tqe); 5966102679Sgibbs } 5967102679Sgibbs LIST_REMOVE(scb, collision_links); 5968102679Sgibbs} 5969102679Sgibbs 5970102679Sgibbs/* 5971102679Sgibbs * Get a free scb. If there are none, see if we can allocate a new SCB. 5972102679Sgibbs */ 5973102679Sgibbsstruct scb * 5974102679Sgibbsahd_get_scb(struct ahd_softc *ahd, u_int col_idx) 5975102679Sgibbs{ 5976102679Sgibbs struct scb *scb; 5977102679Sgibbs int tries; 5978102679Sgibbs 5979102679Sgibbs tries = 0; 5980102679Sgibbslook_again: 5981102679Sgibbs TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) { 5982102679Sgibbs if (AHD_GET_SCB_COL_IDX(ahd, scb) != col_idx) { 5983102679Sgibbs ahd_rem_col_list(ahd, scb); 5984102679Sgibbs goto found; 5985102679Sgibbs } 5986102679Sgibbs } 5987102679Sgibbs if ((scb = LIST_FIRST(&ahd->scb_data.any_dev_free_scb_list)) == NULL) { 5988102679Sgibbs 5989102679Sgibbs if (tries++ != 0) 5990102679Sgibbs return (NULL); 5991168873Sscottl if (ahd_alloc_scbs(ahd) == 0) 5992168873Sscottl return (NULL); 5993102679Sgibbs goto look_again; 5994102679Sgibbs } 5995102679Sgibbs LIST_REMOVE(scb, links.le); 5996102679Sgibbs if (col_idx != AHD_NEVER_COL_IDX 5997102679Sgibbs && (scb->col_scb != NULL) 5998102679Sgibbs && (scb->col_scb->flags & SCB_ACTIVE) == 0) { 5999102679Sgibbs LIST_REMOVE(scb->col_scb, links.le); 6000102679Sgibbs ahd_add_col_list(ahd, scb->col_scb, col_idx); 6001102679Sgibbs } 6002102679Sgibbsfound: 6003102679Sgibbs scb->flags |= SCB_ACTIVE; 6004102679Sgibbs return (scb); 6005102679Sgibbs} 6006102679Sgibbs 6007102679Sgibbs/* 6008102679Sgibbs * Return an SCB resource to the free list. 6009102679Sgibbs */ 601097883Sgibbsvoid 6011102679Sgibbsahd_free_scb(struct ahd_softc *ahd, struct scb *scb) 6012102679Sgibbs{ 6013102679Sgibbs 6014102679Sgibbs /* Clean up for the next user */ 6015102679Sgibbs scb->flags = SCB_FLAG_NONE; 6016102679Sgibbs scb->hscb->control = 0; 6017114623Sgibbs ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = NULL; 6018102679Sgibbs 6019102679Sgibbs if (scb->col_scb == NULL) { 6020102679Sgibbs 6021102679Sgibbs /* 6022102679Sgibbs * No collision possible. Just free normally. 6023102679Sgibbs */ 6024102679Sgibbs LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list, 6025102679Sgibbs scb, links.le); 6026102679Sgibbs } else if ((scb->col_scb->flags & SCB_ON_COL_LIST) != 0) { 6027102679Sgibbs 6028102679Sgibbs /* 6029102679Sgibbs * The SCB we might have collided with is on 6030102679Sgibbs * a free collision list. Put both SCBs on 6031102679Sgibbs * the generic list. 6032102679Sgibbs */ 6033102679Sgibbs ahd_rem_col_list(ahd, scb->col_scb); 6034102679Sgibbs LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list, 6035102679Sgibbs scb, links.le); 6036102679Sgibbs LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list, 6037102679Sgibbs scb->col_scb, links.le); 6038102679Sgibbs } else if ((scb->col_scb->flags 6039102679Sgibbs & (SCB_PACKETIZED|SCB_ACTIVE)) == SCB_ACTIVE 6040102679Sgibbs && (scb->col_scb->hscb->control & TAG_ENB) != 0) { 6041102679Sgibbs 6042102679Sgibbs /* 6043102679Sgibbs * The SCB we might collide with on the next allocation 6044102679Sgibbs * is still active in a non-packetized, tagged, context. 6045102679Sgibbs * Put us on the SCB collision list. 6046102679Sgibbs */ 6047102679Sgibbs ahd_add_col_list(ahd, scb, 6048102679Sgibbs AHD_GET_SCB_COL_IDX(ahd, scb->col_scb)); 6049102679Sgibbs } else { 6050102679Sgibbs /* 6051102679Sgibbs * The SCB we might collide with on the next allocation 6052102679Sgibbs * is either active in a packetized context, or free. 6053102679Sgibbs * Since we can't collide, put this SCB on the generic 6054102679Sgibbs * free list. 6055102679Sgibbs */ 6056102679Sgibbs LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list, 6057102679Sgibbs scb, links.le); 6058102679Sgibbs } 6059102679Sgibbs 6060123579Sgibbs aic_platform_scb_free(ahd, scb); 6061102679Sgibbs} 6062102679Sgibbs 6063168873Sscottlint 606497883Sgibbsahd_alloc_scbs(struct ahd_softc *ahd) 606597883Sgibbs{ 606697883Sgibbs struct scb_data *scb_data; 606797883Sgibbs struct scb *next_scb; 606897883Sgibbs struct hardware_scb *hscb; 606997883Sgibbs struct map_node *hscb_map; 607097883Sgibbs struct map_node *sg_map; 607197883Sgibbs struct map_node *sense_map; 607297883Sgibbs uint8_t *segs; 607397883Sgibbs uint8_t *sense_data; 607497883Sgibbs bus_addr_t hscb_busaddr; 607597883Sgibbs bus_addr_t sg_busaddr; 607697883Sgibbs bus_addr_t sense_busaddr; 607797883Sgibbs int newcount; 607897883Sgibbs int i; 607997883Sgibbs 608097883Sgibbs scb_data = &ahd->scb_data; 608197883Sgibbs if (scb_data->numscbs >= AHD_SCB_MAX_ALLOC) 608297883Sgibbs /* Can't allocate any more */ 6083168873Sscottl return (0); 608497883Sgibbs 608597883Sgibbs if (scb_data->scbs_left != 0) { 608697883Sgibbs int offset; 608797883Sgibbs 608897883Sgibbs offset = (PAGE_SIZE / sizeof(*hscb)) - scb_data->scbs_left; 608997883Sgibbs hscb_map = SLIST_FIRST(&scb_data->hscb_maps); 609097883Sgibbs hscb = &((struct hardware_scb *)hscb_map->vaddr)[offset]; 6091123579Sgibbs hscb_busaddr = hscb_map->busaddr + (offset * sizeof(*hscb)); 609297883Sgibbs } else { 609397883Sgibbs hscb_map = malloc(sizeof(*hscb_map), M_DEVBUF, M_NOWAIT); 609497883Sgibbs 609597883Sgibbs if (hscb_map == NULL) 6096168873Sscottl return (0); 609797883Sgibbs 609897883Sgibbs /* Allocate the next batch of hardware SCBs */ 6099123579Sgibbs if (aic_dmamem_alloc(ahd, scb_data->hscb_dmat, 610097883Sgibbs (void **)&hscb_map->vaddr, 6101219577Smarius BUS_DMA_NOWAIT | BUS_DMA_COHERENT, 6102219577Smarius &hscb_map->dmamap) != 0) { 610397883Sgibbs free(hscb_map, M_DEVBUF); 6104168873Sscottl return (0); 610597883Sgibbs } 610697883Sgibbs 610797883Sgibbs SLIST_INSERT_HEAD(&scb_data->hscb_maps, hscb_map, links); 610897883Sgibbs 6109123579Sgibbs aic_dmamap_load(ahd, scb_data->hscb_dmat, hscb_map->dmamap, 611097883Sgibbs hscb_map->vaddr, PAGE_SIZE, ahd_dmamap_cb, 6111123579Sgibbs &hscb_map->busaddr, /*flags*/0); 611297883Sgibbs 611397883Sgibbs hscb = (struct hardware_scb *)hscb_map->vaddr; 6114123579Sgibbs hscb_busaddr = hscb_map->busaddr; 611597883Sgibbs scb_data->scbs_left = PAGE_SIZE / sizeof(*hscb); 611697883Sgibbs } 611797883Sgibbs 611897883Sgibbs if (scb_data->sgs_left != 0) { 611997883Sgibbs int offset; 612097883Sgibbs 6121114623Sgibbs offset = ((ahd_sglist_allocsize(ahd) / ahd_sglist_size(ahd)) 6122114623Sgibbs - scb_data->sgs_left) * ahd_sglist_size(ahd); 612397883Sgibbs sg_map = SLIST_FIRST(&scb_data->sg_maps); 612497883Sgibbs segs = sg_map->vaddr + offset; 6125123579Sgibbs sg_busaddr = sg_map->busaddr + offset; 612697883Sgibbs } else { 612797883Sgibbs sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); 612897883Sgibbs 612997883Sgibbs if (sg_map == NULL) 6130168873Sscottl return (0); 613197883Sgibbs 613297883Sgibbs /* Allocate the next batch of S/G lists */ 6133123579Sgibbs if (aic_dmamem_alloc(ahd, scb_data->sg_dmat, 613497883Sgibbs (void **)&sg_map->vaddr, 6135219577Smarius BUS_DMA_NOWAIT | BUS_DMA_COHERENT, 6136219577Smarius &sg_map->dmamap) != 0) { 613797883Sgibbs free(sg_map, M_DEVBUF); 6138168873Sscottl return (0); 613997883Sgibbs } 614097883Sgibbs 614197883Sgibbs SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links); 614297883Sgibbs 6143123579Sgibbs aic_dmamap_load(ahd, scb_data->sg_dmat, sg_map->dmamap, 614497883Sgibbs sg_map->vaddr, ahd_sglist_allocsize(ahd), 6145123579Sgibbs ahd_dmamap_cb, &sg_map->busaddr, /*flags*/0); 614697883Sgibbs 614797883Sgibbs segs = sg_map->vaddr; 6148123579Sgibbs sg_busaddr = sg_map->busaddr; 614997883Sgibbs scb_data->sgs_left = 615097883Sgibbs ahd_sglist_allocsize(ahd) / ahd_sglist_size(ahd); 615197883Sgibbs#ifdef AHD_DEBUG 615297883Sgibbs if (ahd_debug & AHD_SHOW_MEMORY) 615397883Sgibbs printf("Mapped SG data\n"); 615497883Sgibbs#endif 615597883Sgibbs } 615697883Sgibbs 615797883Sgibbs if (scb_data->sense_left != 0) { 615897883Sgibbs int offset; 615997883Sgibbs 616097883Sgibbs offset = PAGE_SIZE - (AHD_SENSE_BUFSIZE * scb_data->sense_left); 616197883Sgibbs sense_map = SLIST_FIRST(&scb_data->sense_maps); 616297883Sgibbs sense_data = sense_map->vaddr + offset; 6163123579Sgibbs sense_busaddr = sense_map->busaddr + offset; 616497883Sgibbs } else { 616597883Sgibbs sense_map = malloc(sizeof(*sense_map), M_DEVBUF, M_NOWAIT); 616697883Sgibbs 616797883Sgibbs if (sense_map == NULL) 6168168873Sscottl return (0); 616997883Sgibbs 617097883Sgibbs /* Allocate the next batch of sense buffers */ 6171123579Sgibbs if (aic_dmamem_alloc(ahd, scb_data->sense_dmat, 617297883Sgibbs (void **)&sense_map->vaddr, 617397883Sgibbs BUS_DMA_NOWAIT, &sense_map->dmamap) != 0) { 617497883Sgibbs free(sense_map, M_DEVBUF); 6175168873Sscottl return (0); 617697883Sgibbs } 617797883Sgibbs 617897883Sgibbs SLIST_INSERT_HEAD(&scb_data->sense_maps, sense_map, links); 617997883Sgibbs 6180123579Sgibbs aic_dmamap_load(ahd, scb_data->sense_dmat, sense_map->dmamap, 618197883Sgibbs sense_map->vaddr, PAGE_SIZE, ahd_dmamap_cb, 6182123579Sgibbs &sense_map->busaddr, /*flags*/0); 618397883Sgibbs 618497883Sgibbs sense_data = sense_map->vaddr; 6185123579Sgibbs sense_busaddr = sense_map->busaddr; 618697883Sgibbs scb_data->sense_left = PAGE_SIZE / AHD_SENSE_BUFSIZE; 618797883Sgibbs#ifdef AHD_DEBUG 618897883Sgibbs if (ahd_debug & AHD_SHOW_MEMORY) 618997883Sgibbs printf("Mapped sense data\n"); 619097883Sgibbs#endif 619197883Sgibbs } 619297883Sgibbs 619397883Sgibbs newcount = MIN(scb_data->sense_left, scb_data->scbs_left); 619497883Sgibbs newcount = MIN(newcount, scb_data->sgs_left); 619597883Sgibbs newcount = MIN(newcount, (AHD_SCB_MAX_ALLOC - scb_data->numscbs)); 619697883Sgibbs scb_data->sense_left -= newcount; 619797883Sgibbs scb_data->scbs_left -= newcount; 619897883Sgibbs scb_data->sgs_left -= newcount; 619997883Sgibbs for (i = 0; i < newcount; i++) { 6200125448Sgibbs struct scb_platform_data *pdata; 6201102679Sgibbs u_int col_tag; 620297883Sgibbs#ifndef __linux__ 620397883Sgibbs int error; 620497883Sgibbs#endif 6205125448Sgibbs 620697883Sgibbs next_scb = (struct scb *)malloc(sizeof(*next_scb), 620797883Sgibbs M_DEVBUF, M_NOWAIT); 620897883Sgibbs if (next_scb == NULL) 620997883Sgibbs break; 621097883Sgibbs 621197883Sgibbs pdata = (struct scb_platform_data *)malloc(sizeof(*pdata), 621297883Sgibbs M_DEVBUF, M_NOWAIT); 621397883Sgibbs if (pdata == NULL) { 621497883Sgibbs free(next_scb, M_DEVBUF); 621597883Sgibbs break; 621697883Sgibbs } 621797883Sgibbs next_scb->platform_data = pdata; 621897883Sgibbs next_scb->hscb_map = hscb_map; 621997883Sgibbs next_scb->sg_map = sg_map; 622097883Sgibbs next_scb->sense_map = sense_map; 622197883Sgibbs next_scb->sg_list = segs; 622297883Sgibbs next_scb->sense_data = sense_data; 622397883Sgibbs next_scb->sense_busaddr = sense_busaddr; 6224115331Sgibbs memset(hscb, 0, sizeof(*hscb)); 622597883Sgibbs next_scb->hscb = hscb; 6226123579Sgibbs hscb->hscb_busaddr = aic_htole32(hscb_busaddr); 622797883Sgibbs 622897883Sgibbs /* 622997883Sgibbs * The sequencer always starts with the second entry. 623097883Sgibbs * The first entry is embedded in the scb. 623197883Sgibbs */ 623297883Sgibbs next_scb->sg_list_busaddr = sg_busaddr; 623397883Sgibbs if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) 623497883Sgibbs next_scb->sg_list_busaddr 623597883Sgibbs += sizeof(struct ahd_dma64_seg); 623697883Sgibbs else 623797883Sgibbs next_scb->sg_list_busaddr += sizeof(struct ahd_dma_seg); 623897883Sgibbs next_scb->ahd_softc = ahd; 6239102679Sgibbs next_scb->flags = SCB_FLAG_NONE; 624097883Sgibbs#ifndef __linux__ 6241123579Sgibbs error = aic_dmamap_create(ahd, ahd->buffer_dmat, /*flags*/0, 624297883Sgibbs &next_scb->dmamap); 624397883Sgibbs if (error != 0) { 624497883Sgibbs free(next_scb, M_DEVBUF); 624597883Sgibbs free(pdata, M_DEVBUF); 624697883Sgibbs break; 624797883Sgibbs } 624897883Sgibbs#endif 6249123579Sgibbs next_scb->hscb->tag = aic_htole16(scb_data->numscbs); 6250102679Sgibbs col_tag = scb_data->numscbs ^ 0x100; 6251102679Sgibbs next_scb->col_scb = ahd_find_scb_by_tag(ahd, col_tag); 6252102679Sgibbs if (next_scb->col_scb != NULL) 6253102679Sgibbs next_scb->col_scb->col_scb = next_scb; 6254168807Sscottl aic_timer_init(&next_scb->io_timer); 6255102679Sgibbs ahd_free_scb(ahd, next_scb); 625697883Sgibbs hscb++; 625797883Sgibbs hscb_busaddr += sizeof(*hscb); 625897883Sgibbs segs += ahd_sglist_size(ahd); 625997883Sgibbs sg_busaddr += ahd_sglist_size(ahd); 626097883Sgibbs sense_data += AHD_SENSE_BUFSIZE; 626197883Sgibbs sense_busaddr += AHD_SENSE_BUFSIZE; 626297883Sgibbs scb_data->numscbs++; 626397883Sgibbs } 6264168873Sscottl return (i); 626597883Sgibbs} 626697883Sgibbs 626797883Sgibbsvoid 626897883Sgibbsahd_controller_info(struct ahd_softc *ahd, char *buf) 626997883Sgibbs{ 627097883Sgibbs const char *speed; 627197883Sgibbs const char *type; 627297883Sgibbs int len; 627397883Sgibbs 627497883Sgibbs len = sprintf(buf, "%s: ", ahd_chip_names[ahd->chip & AHD_CHIPID_MASK]); 627597883Sgibbs buf += len; 627697883Sgibbs 627797883Sgibbs speed = "Ultra320 "; 627897883Sgibbs if ((ahd->features & AHD_WIDE) != 0) { 6279102679Sgibbs type = "Wide "; 628097883Sgibbs } else { 6281102679Sgibbs type = "Single "; 628297883Sgibbs } 628397883Sgibbs len = sprintf(buf, "%s%sChannel %c, SCSI Id=%d, ", 628497883Sgibbs speed, type, ahd->channel, ahd->our_id); 628597883Sgibbs buf += len; 628697883Sgibbs 628797883Sgibbs sprintf(buf, "%s, %d SCBs", ahd->bus_description, 628897883Sgibbs ahd->scb_data.maxhscbs); 628997883Sgibbs} 629097883Sgibbs 629197883Sgibbsstatic const char *channel_strings[] = { 629297883Sgibbs "Primary Low", 629397883Sgibbs "Primary High", 629497883Sgibbs "Secondary Low", 629597883Sgibbs "Secondary High" 629697883Sgibbs}; 629797883Sgibbs 629897883Sgibbsstatic const char *termstat_strings[] = { 629997883Sgibbs "Terminated Correctly", 630097883Sgibbs "Over Terminated", 630197883Sgibbs "Under Terminated", 630297883Sgibbs "Not Configured" 630397883Sgibbs}; 630497883Sgibbs 630597883Sgibbs/* 630697883Sgibbs * Start the board, ready for normal operation 630797883Sgibbs */ 630897883Sgibbsint 630997883Sgibbsahd_init(struct ahd_softc *ahd) 631097883Sgibbs{ 6311102679Sgibbs uint8_t *next_vaddr; 6312102679Sgibbs bus_addr_t next_baddr; 6313102679Sgibbs size_t driver_data_size; 6314102679Sgibbs int i; 6315102679Sgibbs int error; 6316102679Sgibbs u_int warn_user; 6317102679Sgibbs uint8_t current_sensing; 6318102679Sgibbs uint8_t fstat; 631997883Sgibbs 632097883Sgibbs AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 632197883Sgibbs 6322107441Sscottl ahd->stack_size = ahd_probe_stack_size(ahd); 6323107441Sscottl ahd->saved_stack = malloc(ahd->stack_size * sizeof(uint16_t), 6324107441Sscottl M_DEVBUF, M_NOWAIT); 6325107441Sscottl if (ahd->saved_stack == NULL) 6326107441Sscottl return (ENOMEM); 6327107441Sscottl 632897883Sgibbs /* 632997883Sgibbs * Verify that the compiler hasn't over-agressively 633097883Sgibbs * padded important structures. 633197883Sgibbs */ 633297883Sgibbs if (sizeof(struct hardware_scb) != 64) 633397883Sgibbs panic("Hardware SCB size is incorrect"); 633497883Sgibbs 633597883Sgibbs#ifdef AHD_DEBUG 633697883Sgibbs if ((ahd_debug & AHD_DEBUG_SEQUENCER) != 0) 633797883Sgibbs ahd->flags |= AHD_SEQUENCER_DEBUG; 633897883Sgibbs#endif 633997883Sgibbs 634097883Sgibbs /* 634197883Sgibbs * Default to allowing initiator operations. 634297883Sgibbs */ 634397883Sgibbs ahd->flags |= AHD_INITIATORROLE; 634497883Sgibbs 634597883Sgibbs /* 634697883Sgibbs * Only allow target mode features if this unit has them enabled. 634797883Sgibbs */ 634897883Sgibbs if ((AHD_TMODE_ENABLE & (0x1 << ahd->unit)) == 0) 634997883Sgibbs ahd->features &= ~AHD_TARGETMODE; 635097883Sgibbs 635197883Sgibbs#ifndef __linux__ 635297883Sgibbs /* DMA tag for mapping buffers into device visible space. */ 6353123579Sgibbs if (aic_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, 635497883Sgibbs /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, 6355114623Sgibbs /*lowaddr*/ahd->flags & AHD_39BIT_ADDRESSING 6356114623Sgibbs ? (bus_addr_t)0x7FFFFFFFFFULL 6357114623Sgibbs : BUS_SPACE_MAXADDR_32BIT, 635897883Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 635997883Sgibbs /*filter*/NULL, /*filterarg*/NULL, 6360108479Sscottl /*maxsize*/(AHD_NSEG - 1) * PAGE_SIZE, 6361108479Sscottl /*nsegments*/AHD_NSEG, 636297883Sgibbs /*maxsegsz*/AHD_MAXTRANSFER_SIZE, 636397883Sgibbs /*flags*/BUS_DMA_ALLOCNOW, 636497883Sgibbs &ahd->buffer_dmat) != 0) { 636597883Sgibbs return (ENOMEM); 636697883Sgibbs } 636797883Sgibbs#endif 636897883Sgibbs 636997883Sgibbs ahd->init_level++; 637097883Sgibbs 637197883Sgibbs /* 637297883Sgibbs * DMA tag for our command fifos and other data in system memory 637397883Sgibbs * the card's sequencer must be able to access. For initiator 637497883Sgibbs * roles, we need to allocate space for the qoutfifo. When providing 637597883Sgibbs * for the target mode role, we must additionally provide space for 637697883Sgibbs * the incoming target command fifo. 637797883Sgibbs */ 6378129134Sgibbs driver_data_size = AHD_SCB_MAX * sizeof(*ahd->qoutfifo) 6379129134Sgibbs + sizeof(struct hardware_scb); 638097883Sgibbs if ((ahd->features & AHD_TARGETMODE) != 0) 638197883Sgibbs driver_data_size += AHD_TMODE_CMDS * sizeof(struct target_cmd); 638297883Sgibbs if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) 638397883Sgibbs driver_data_size += PKT_OVERRUN_BUFSIZE; 6384123579Sgibbs if (aic_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, 638597883Sgibbs /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, 638697883Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 638797883Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 638897883Sgibbs /*filter*/NULL, /*filterarg*/NULL, 638997883Sgibbs driver_data_size, 639097883Sgibbs /*nsegments*/1, 639197883Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 639297883Sgibbs /*flags*/0, &ahd->shared_data_dmat) != 0) { 639397883Sgibbs return (ENOMEM); 639497883Sgibbs } 639597883Sgibbs 639697883Sgibbs ahd->init_level++; 639797883Sgibbs 639897883Sgibbs /* Allocation of driver data */ 6399123579Sgibbs if (aic_dmamem_alloc(ahd, ahd->shared_data_dmat, 6400123579Sgibbs (void **)&ahd->shared_data_map.vaddr, 6401219577Smarius BUS_DMA_NOWAIT | BUS_DMA_COHERENT, 6402123579Sgibbs &ahd->shared_data_map.dmamap) != 0) { 640397883Sgibbs return (ENOMEM); 640497883Sgibbs } 640597883Sgibbs 640697883Sgibbs ahd->init_level++; 640797883Sgibbs 640897883Sgibbs /* And permanently map it in */ 6409123579Sgibbs aic_dmamap_load(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap, 6410123579Sgibbs ahd->shared_data_map.vaddr, driver_data_size, 6411123579Sgibbs ahd_dmamap_cb, &ahd->shared_data_map.busaddr, 6412123579Sgibbs /*flags*/0); 6413125448Sgibbs ahd->qoutfifo = (struct ahd_completion *)ahd->shared_data_map.vaddr; 6414102679Sgibbs next_vaddr = (uint8_t *)&ahd->qoutfifo[AHD_QOUT_SIZE]; 6415123579Sgibbs next_baddr = ahd->shared_data_map.busaddr 6416125448Sgibbs + AHD_QOUT_SIZE*sizeof(struct ahd_completion); 641797883Sgibbs if ((ahd->features & AHD_TARGETMODE) != 0) { 6418102679Sgibbs ahd->targetcmds = (struct target_cmd *)next_vaddr; 6419102679Sgibbs next_vaddr += AHD_TMODE_CMDS * sizeof(struct target_cmd); 6420102679Sgibbs next_baddr += AHD_TMODE_CMDS * sizeof(struct target_cmd); 642197883Sgibbs } 642297883Sgibbs 6423102679Sgibbs if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) { 6424102679Sgibbs ahd->overrun_buf = next_vaddr; 6425102679Sgibbs next_vaddr += PKT_OVERRUN_BUFSIZE; 6426102679Sgibbs next_baddr += PKT_OVERRUN_BUFSIZE; 6427102679Sgibbs } 642897883Sgibbs 6429129134Sgibbs /* 6430129134Sgibbs * We need one SCB to serve as the "next SCB". Since the 6431129134Sgibbs * tag identifier in this SCB will never be used, there is 6432129134Sgibbs * no point in using a valid HSCB tag from an SCB pulled from 6433129134Sgibbs * the standard free pool. So, we allocate this "sentinel" 6434129134Sgibbs * specially from the DMA safe memory chunk used for the QOUTFIFO. 6435129134Sgibbs */ 6436129134Sgibbs ahd->next_queued_hscb = (struct hardware_scb *)next_vaddr; 6437129134Sgibbs ahd->next_queued_hscb_map = &ahd->shared_data_map; 6438129134Sgibbs ahd->next_queued_hscb->hscb_busaddr = aic_htole32(next_baddr); 6439129134Sgibbs 644097883Sgibbs ahd->init_level++; 644197883Sgibbs 644297883Sgibbs /* Allocate SCB data now that buffer_dmat is initialized */ 644397883Sgibbs if (ahd_init_scbdata(ahd) != 0) 644497883Sgibbs return (ENOMEM); 644597883Sgibbs 644697883Sgibbs if ((ahd->flags & AHD_INITIATORROLE) == 0) 644797883Sgibbs ahd->flags &= ~AHD_RESET_BUS_A; 644897883Sgibbs 6449107441Sscottl /* 6450107441Sscottl * Before committing these settings to the chip, give 6451107441Sscottl * the OSM one last chance to modify our configuration. 6452107441Sscottl */ 6453107441Sscottl ahd_platform_init(ahd); 6454107441Sscottl 6455107441Sscottl /* Bring up the chip. */ 645697883Sgibbs ahd_chip_init(ahd); 645797883Sgibbs 645897883Sgibbs AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 645997883Sgibbs 646097883Sgibbs if ((ahd->flags & AHD_CURRENT_SENSING) == 0) 646197883Sgibbs goto init_done; 646297883Sgibbs 646397883Sgibbs /* 646497883Sgibbs * Verify termination based on current draw and 646597883Sgibbs * warn user if the bus is over/under terminated. 646697883Sgibbs */ 646797883Sgibbs error = ahd_write_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, 646897883Sgibbs CURSENSE_ENB); 646997883Sgibbs if (error != 0) { 647097883Sgibbs printf("%s: current sensing timeout 1\n", ahd_name(ahd)); 647197883Sgibbs goto init_done; 647297883Sgibbs } 647397883Sgibbs for (i = 20, fstat = FLX_FSTAT_BUSY; 647497883Sgibbs (fstat & FLX_FSTAT_BUSY) != 0 && i; i--) { 647597883Sgibbs error = ahd_read_flexport(ahd, FLXADDR_FLEXSTAT, &fstat); 647697883Sgibbs if (error != 0) { 647797883Sgibbs printf("%s: current sensing timeout 2\n", 647897883Sgibbs ahd_name(ahd)); 647997883Sgibbs goto init_done; 648097883Sgibbs } 648197883Sgibbs } 648297883Sgibbs if (i == 0) { 648397883Sgibbs printf("%s: Timedout during current-sensing test\n", 648497883Sgibbs ahd_name(ahd)); 648597883Sgibbs goto init_done; 648697883Sgibbs } 648797883Sgibbs 648897883Sgibbs /* Latch Current Sensing status. */ 648997883Sgibbs error = ahd_read_flexport(ahd, FLXADDR_CURRENT_STAT, ¤t_sensing); 649097883Sgibbs if (error != 0) { 649197883Sgibbs printf("%s: current sensing timeout 3\n", ahd_name(ahd)); 649297883Sgibbs goto init_done; 649397883Sgibbs } 649497883Sgibbs 649597883Sgibbs /* Diable current sensing. */ 649697883Sgibbs ahd_write_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, 0); 649797883Sgibbs 649897883Sgibbs#ifdef AHD_DEBUG 649997883Sgibbs if ((ahd_debug & AHD_SHOW_TERMCTL) != 0) { 650097883Sgibbs printf("%s: current_sensing == 0x%x\n", 650197883Sgibbs ahd_name(ahd), current_sensing); 650297883Sgibbs } 650397883Sgibbs#endif 650497883Sgibbs warn_user = 0; 650597883Sgibbs for (i = 0; i < 4; i++, current_sensing >>= FLX_CSTAT_SHIFT) { 650697883Sgibbs u_int term_stat; 650797883Sgibbs 650897883Sgibbs term_stat = (current_sensing & FLX_CSTAT_MASK); 650997883Sgibbs switch (term_stat) { 651097883Sgibbs case FLX_CSTAT_OVER: 651197883Sgibbs case FLX_CSTAT_UNDER: 651297883Sgibbs warn_user++; 651397883Sgibbs case FLX_CSTAT_INVALID: 651497883Sgibbs case FLX_CSTAT_OKAY: 651597883Sgibbs if (warn_user == 0 && bootverbose == 0) 651697883Sgibbs break; 651797883Sgibbs printf("%s: %s Channel %s\n", ahd_name(ahd), 651897883Sgibbs channel_strings[i], termstat_strings[term_stat]); 651997883Sgibbs break; 652097883Sgibbs } 652197883Sgibbs } 652297883Sgibbs if (warn_user) { 652397883Sgibbs printf("%s: WARNING. Termination is not configured correctly.\n" 652497883Sgibbs "%s: WARNING. SCSI bus operations may FAIL.\n", 652597883Sgibbs ahd_name(ahd), ahd_name(ahd)); 6526199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 652797883Sgibbs } 652897883Sgibbsinit_done: 652997883Sgibbs ahd_restart(ahd); 6530137870Sgibbs aic_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_MS, 6531109588Sgibbs ahd_stat_timer, ahd); 653297883Sgibbs return (0); 653397883Sgibbs} 653497883Sgibbs 653597883Sgibbs/* 653697883Sgibbs * (Re)initialize chip state after a chip reset. 653797883Sgibbs */ 653897883Sgibbsstatic void 653997883Sgibbsahd_chip_init(struct ahd_softc *ahd) 654097883Sgibbs{ 654197883Sgibbs uint32_t busaddr; 654297883Sgibbs u_int sxfrctl1; 654397883Sgibbs u_int scsiseq_template; 6544102679Sgibbs u_int wait; 654597883Sgibbs u_int i; 654697883Sgibbs u_int target; 654797883Sgibbs 654897883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 654997883Sgibbs /* 655097883Sgibbs * Take the LED out of diagnostic mode 655197883Sgibbs */ 655297883Sgibbs ahd_outb(ahd, SBLKCTL, ahd_inb(ahd, SBLKCTL) & ~(DIAGLEDEN|DIAGLEDON)); 655397883Sgibbs 6554109588Sgibbs /* 6555109588Sgibbs * Return HS_MAILBOX to its default value. 6556109588Sgibbs */ 6557109588Sgibbs ahd->hs_mailbox = 0; 6558109588Sgibbs ahd_outb(ahd, HS_MAILBOX, 0); 6559109588Sgibbs 656097883Sgibbs /* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1. */ 656197883Sgibbs ahd_outb(ahd, IOWNID, ahd->our_id); 656297883Sgibbs ahd_outb(ahd, TOWNID, ahd->our_id); 656397883Sgibbs sxfrctl1 = (ahd->flags & AHD_TERM_ENB_A) != 0 ? STPWEN : 0; 656497883Sgibbs sxfrctl1 |= (ahd->flags & AHD_SPCHK_ENB_A) != 0 ? ENSPCHK : 0; 656597883Sgibbs if ((ahd->bugs & AHD_LONG_SETIMO_BUG) 656697883Sgibbs && (ahd->seltime != STIMESEL_MIN)) { 656797883Sgibbs /* 656897883Sgibbs * The selection timer duration is twice as long 656997883Sgibbs * as it should be. Halve it by adding "1" to 657097883Sgibbs * the user specified setting. 657197883Sgibbs */ 657297883Sgibbs sxfrctl1 |= ahd->seltime + STIMESEL_BUG_ADJ; 657397883Sgibbs } else { 657497883Sgibbs sxfrctl1 |= ahd->seltime; 657597883Sgibbs } 657697883Sgibbs 657797883Sgibbs ahd_outb(ahd, SXFRCTL0, DFON); 657897883Sgibbs ahd_outb(ahd, SXFRCTL1, sxfrctl1|ahd->seltime|ENSTIMER|ACTNEGEN); 657997883Sgibbs ahd_outb(ahd, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); 658097883Sgibbs 6581102679Sgibbs /* 6582102679Sgibbs * Now that termination is set, wait for up 6583102679Sgibbs * to 500ms for our transceivers to settle. If 6584102679Sgibbs * the adapter does not have a cable attached, 6585114623Sgibbs * the transceivers may never settle, so don't 6586102679Sgibbs * complain if we fail here. 6587102679Sgibbs */ 6588102679Sgibbs for (wait = 10000; 6589102679Sgibbs (ahd_inb(ahd, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait; 6590102679Sgibbs wait--) 6591123579Sgibbs aic_delay(100); 6592102679Sgibbs 6593102679Sgibbs /* Clear any false bus resets due to the transceivers settling */ 6594102679Sgibbs ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI); 6595102679Sgibbs ahd_outb(ahd, CLRINT, CLRSCSIINT); 6596102679Sgibbs 659797883Sgibbs /* Initialize mode specific S/G state. */ 659897883Sgibbs for (i = 0; i < 2; i++) { 659997883Sgibbs ahd_set_modes(ahd, AHD_MODE_DFF0 + i, AHD_MODE_DFF0 + i); 660097883Sgibbs ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR); 660197883Sgibbs ahd_outb(ahd, SG_STATE, 0); 660297883Sgibbs ahd_outb(ahd, CLRSEQINTSRC, 0xFF); 660397883Sgibbs ahd_outb(ahd, SEQIMODE, 660497883Sgibbs ENSAVEPTRS|ENCFG4DATA|ENCFG4ISTAT 660597883Sgibbs |ENCFG4TSTAT|ENCFG4ICMD|ENCFG4TCMD); 660697883Sgibbs } 660797883Sgibbs 660897883Sgibbs ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 660997883Sgibbs ahd_outb(ahd, DSCOMMAND0, ahd_inb(ahd, DSCOMMAND0)|MPARCKEN|CACHETHEN); 661097883Sgibbs ahd_outb(ahd, DFF_THRSH, RD_DFTHRSH_75|WR_DFTHRSH_75); 661197883Sgibbs ahd_outb(ahd, SIMODE0, ENIOERR|ENOVERRUN); 661297883Sgibbs ahd_outb(ahd, SIMODE3, ENNTRAMPERR|ENOSRAMPERR); 6613104023Sgibbs if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) { 6614104023Sgibbs ahd_outb(ahd, OPTIONMODE, AUTOACKEN|AUTO_MSGOUT_DE); 6615104023Sgibbs } else { 6616104023Sgibbs ahd_outb(ahd, OPTIONMODE, AUTOACKEN|BUSFREEREV|AUTO_MSGOUT_DE); 6617104023Sgibbs } 6618111653Sgibbs ahd_outb(ahd, SCSCHKN, CURRFIFODEF|WIDERESEN|SHVALIDSTDIS); 661997883Sgibbs if ((ahd->chip & AHD_BUS_MASK) == AHD_PCIX) 662097883Sgibbs /* 662197883Sgibbs * Do not issue a target abort when a split completion 662297883Sgibbs * error occurs. Let our PCIX interrupt handler deal 662397883Sgibbs * with it instead. H2A4 Razor #625 662497883Sgibbs */ 662597883Sgibbs ahd_outb(ahd, PCIXCTL, ahd_inb(ahd, PCIXCTL) | SPLTSTADIS); 662697883Sgibbs 6627107441Sscottl if ((ahd->bugs & AHD_LQOOVERRUN_BUG) != 0) 6628107441Sscottl ahd_outb(ahd, LQOSCSCTL, LQONOCHKOVER); 6629107441Sscottl 663097883Sgibbs /* 663197883Sgibbs * Tweak IOCELL settings. 663297883Sgibbs */ 6633107441Sscottl if ((ahd->flags & AHD_HP_BOARD) != 0) { 663497883Sgibbs for (i = 0; i < NUMDSPS; i++) { 663597883Sgibbs ahd_outb(ahd, DSPSELECT, i); 6636107441Sscottl ahd_outb(ahd, WRTBIASCTL, WRTBIASCTL_HP_DEFAULT); 663797883Sgibbs } 6638104023Sgibbs#ifdef AHD_DEBUG 6639104023Sgibbs if ((ahd_debug & AHD_SHOW_MISC) != 0) 6640104023Sgibbs printf("%s: WRTBIASCTL now 0x%x\n", ahd_name(ahd), 6641107441Sscottl WRTBIASCTL_HP_DEFAULT); 6642104023Sgibbs#endif 664397883Sgibbs } 664497883Sgibbs ahd_setup_iocell_workaround(ahd); 664597883Sgibbs 664697883Sgibbs /* 664797883Sgibbs * Enable LQI Manager interrupts. 664897883Sgibbs */ 664997883Sgibbs ahd_outb(ahd, LQIMODE1, ENLQIPHASE_LQ|ENLQIPHASE_NLQ|ENLIQABORT 665097883Sgibbs | ENLQICRCI_LQ|ENLQICRCI_NLQ|ENLQIBADLQI 665197883Sgibbs | ENLQIOVERI_LQ|ENLQIOVERI_NLQ); 665297883Sgibbs ahd_outb(ahd, LQOMODE0, ENLQOATNLQ|ENLQOATNPKT|ENLQOTCRC); 665397883Sgibbs /* 6654133122Sgibbs * We choose to have the sequencer catch LQOPHCHGINPKT errors 6655133122Sgibbs * manually for the command phase at the start of a packetized 6656133122Sgibbs * selection case. ENLQOBUSFREE should be made redundant by 6657133122Sgibbs * the BUSFREE interrupt, but it seems that some LQOBUSFREE 6658133122Sgibbs * events fail to assert the BUSFREE interrupt so we must 6659133122Sgibbs * also enable LQOBUSFREE interrupts. 666097883Sgibbs */ 6661133122Sgibbs ahd_outb(ahd, LQOMODE1, ENLQOBUSFREE); 666297883Sgibbs 666397883Sgibbs /* 6664109588Sgibbs * Setup sequencer interrupt handlers. 666597883Sgibbs */ 666697883Sgibbs ahd_outw(ahd, INTVEC1_ADDR, ahd_resolve_seqaddr(ahd, LABEL_seq_isr)); 6667109588Sgibbs ahd_outw(ahd, INTVEC2_ADDR, ahd_resolve_seqaddr(ahd, LABEL_timer_isr)); 666897883Sgibbs 666997883Sgibbs /* 667097883Sgibbs * Setup SCB Offset registers. 667197883Sgibbs */ 6672102679Sgibbs if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0) { 6673102679Sgibbs ahd_outb(ahd, LUNPTR, offsetof(struct hardware_scb, 6674102679Sgibbs pkt_long_lun)); 6675102679Sgibbs } else { 6676102679Sgibbs ahd_outb(ahd, LUNPTR, offsetof(struct hardware_scb, lun)); 6677102679Sgibbs } 667897883Sgibbs ahd_outb(ahd, CMDLENPTR, offsetof(struct hardware_scb, cdb_len)); 6679104023Sgibbs ahd_outb(ahd, ATTRPTR, offsetof(struct hardware_scb, task_attribute)); 668097883Sgibbs ahd_outb(ahd, FLAGPTR, offsetof(struct hardware_scb, task_management)); 668197883Sgibbs ahd_outb(ahd, CMDPTR, offsetof(struct hardware_scb, 668297883Sgibbs shared_data.idata.cdb)); 668397883Sgibbs ahd_outb(ahd, QNEXTPTR, 668497883Sgibbs offsetof(struct hardware_scb, next_hscb_busaddr)); 668597883Sgibbs ahd_outb(ahd, ABRTBITPTR, MK_MESSAGE_BIT_OFFSET); 668697883Sgibbs ahd_outb(ahd, ABRTBYTEPTR, offsetof(struct hardware_scb, control)); 6687102679Sgibbs if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0) { 6688102679Sgibbs ahd_outb(ahd, LUNLEN, 6689102679Sgibbs sizeof(ahd->next_queued_hscb->pkt_long_lun) - 1); 6690102679Sgibbs } else { 6691115408Sscottl ahd_outb(ahd, LUNLEN, LUNLEN_SINGLE_LEVEL_LUN); 6692102679Sgibbs } 669397883Sgibbs ahd_outb(ahd, CDBLIMIT, SCB_CDB_LEN_PTR - 1); 669497883Sgibbs ahd_outb(ahd, MAXCMD, 0xFF); 669597883Sgibbs ahd_outb(ahd, SCBAUTOPTR, 669697883Sgibbs AUSCBPTR_EN | offsetof(struct hardware_scb, tag)); 669797883Sgibbs 669897883Sgibbs /* We haven't been enabled for target mode yet. */ 669997883Sgibbs ahd_outb(ahd, MULTARGID, 0); 670097883Sgibbs ahd_outb(ahd, MULTARGID + 1, 0); 670197883Sgibbs 670297883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 6703107441Sscottl /* Initialize the negotiation table. */ 6704107441Sscottl if ((ahd->features & AHD_NEW_IOCELL_OPTS) == 0) { 6705107441Sscottl /* 6706107441Sscottl * Clear the spare bytes in the neg table to avoid 6707107441Sscottl * spurious parity errors. 6708107441Sscottl */ 6709107441Sscottl for (target = 0; target < AHD_NUM_TARGETS; target++) { 6710107441Sscottl ahd_outb(ahd, NEGOADDR, target); 6711107441Sscottl ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PER_DEV0); 6712107441Sscottl for (i = 0; i < AHD_NUM_PER_DEV_ANNEXCOLS; i++) 6713107441Sscottl ahd_outb(ahd, ANNEXDAT, 0); 6714107441Sscottl } 6715107441Sscottl } 671697883Sgibbs for (target = 0; target < AHD_NUM_TARGETS; target++) { 6717107441Sscottl struct ahd_devinfo devinfo; 6718107441Sscottl struct ahd_initiator_tinfo *tinfo; 6719107441Sscottl struct ahd_tmode_tstate *tstate; 672097883Sgibbs 6721107441Sscottl tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, 6722107441Sscottl target, &tstate); 6723107441Sscottl ahd_compile_devinfo(&devinfo, ahd->our_id, 6724107441Sscottl target, CAM_LUN_WILDCARD, 6725107441Sscottl 'A', ROLE_INITIATOR); 6726107441Sscottl ahd_update_neg_table(ahd, &devinfo, &tinfo->curr); 672797883Sgibbs } 6728107441Sscottl 672997883Sgibbs ahd_outb(ahd, CLRSINT3, NTRAMPERR|OSRAMPERR); 6730102679Sgibbs ahd_outb(ahd, CLRINT, CLRSCSIINT); 673197883Sgibbs 6732153072Sru#ifdef NEEDS_MORE_TESTING 673397883Sgibbs /* 673497883Sgibbs * Always enable abort on incoming L_Qs if this feature is 673597883Sgibbs * supported. We use this to catch invalid SCB references. 673697883Sgibbs */ 673797883Sgibbs if ((ahd->bugs & AHD_ABORT_LQI_BUG) == 0) 673897883Sgibbs ahd_outb(ahd, LQCTL1, ABORTPENDING); 673997883Sgibbs else 6740116935Sgibbs#endif 674197883Sgibbs ahd_outb(ahd, LQCTL1, 0); 674297883Sgibbs 674397883Sgibbs /* All of our queues are empty */ 674497883Sgibbs ahd->qoutfifonext = 0; 6745125448Sgibbs ahd->qoutfifonext_valid_tag = QOUTFIFO_ENTRY_VALID; 6746125448Sgibbs ahd_outb(ahd, QOUTFIFO_ENTRY_VALID_TAG, QOUTFIFO_ENTRY_VALID); 674797883Sgibbs for (i = 0; i < AHD_QOUT_SIZE; i++) 6748125448Sgibbs ahd->qoutfifo[i].valid_tag = 0; 674997883Sgibbs ahd_sync_qoutfifo(ahd, BUS_DMASYNC_PREREAD); 675097883Sgibbs 675197883Sgibbs ahd->qinfifonext = 0; 675297883Sgibbs for (i = 0; i < AHD_QIN_SIZE; i++) 675397883Sgibbs ahd->qinfifo[i] = SCB_LIST_NULL; 675497883Sgibbs 675597883Sgibbs if ((ahd->features & AHD_TARGETMODE) != 0) { 675697883Sgibbs /* All target command blocks start out invalid. */ 675797883Sgibbs for (i = 0; i < AHD_TMODE_CMDS; i++) 675897883Sgibbs ahd->targetcmds[i].cmd_valid = 0; 675997883Sgibbs ahd_sync_tqinfifo(ahd, BUS_DMASYNC_PREREAD); 676097883Sgibbs ahd->tqinfifonext = 1; 676197883Sgibbs ahd_outb(ahd, KERNEL_TQINPOS, ahd->tqinfifonext - 1); 676297883Sgibbs ahd_outb(ahd, TQINPOS, ahd->tqinfifonext); 676397883Sgibbs } 676497883Sgibbs 676597883Sgibbs /* Initialize Scratch Ram. */ 676697883Sgibbs ahd_outb(ahd, SEQ_FLAGS, 0); 676797883Sgibbs ahd_outb(ahd, SEQ_FLAGS2, 0); 676897883Sgibbs 676997883Sgibbs /* We don't have any waiting selections */ 677097883Sgibbs ahd_outw(ahd, WAITING_TID_HEAD, SCB_LIST_NULL); 677197883Sgibbs ahd_outw(ahd, WAITING_TID_TAIL, SCB_LIST_NULL); 6772133122Sgibbs ahd_outw(ahd, MK_MESSAGE_SCB, SCB_LIST_NULL); 6773133122Sgibbs ahd_outw(ahd, MK_MESSAGE_SCSIID, 0xFF); 677497883Sgibbs for (i = 0; i < AHD_NUM_TARGETS; i++) 677597883Sgibbs ahd_outw(ahd, WAITING_SCB_TAILS + (2 * i), SCB_LIST_NULL); 677697883Sgibbs 677797883Sgibbs /* 677897883Sgibbs * Nobody is waiting to be DMAed into the QOUTFIFO. 677997883Sgibbs */ 678097883Sgibbs ahd_outw(ahd, COMPLETE_SCB_HEAD, SCB_LIST_NULL); 678197883Sgibbs ahd_outw(ahd, COMPLETE_SCB_DMAINPROG_HEAD, SCB_LIST_NULL); 678297883Sgibbs ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, SCB_LIST_NULL); 6783125448Sgibbs ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, SCB_LIST_NULL); 6784125448Sgibbs ahd_outw(ahd, COMPLETE_ON_QFREEZE_HEAD, SCB_LIST_NULL); 678597883Sgibbs 678697883Sgibbs /* 678797883Sgibbs * The Freeze Count is 0. 678897883Sgibbs */ 6789125448Sgibbs ahd->qfreeze_cnt = 0; 679097883Sgibbs ahd_outw(ahd, QFREEZE_COUNT, 0); 6791125448Sgibbs ahd_outw(ahd, KERNEL_QFREEZE_COUNT, 0); 679297883Sgibbs 679397883Sgibbs /* 679497883Sgibbs * Tell the sequencer where it can find our arrays in memory. 679597883Sgibbs */ 6796123579Sgibbs busaddr = ahd->shared_data_map.busaddr; 6797123579Sgibbs ahd_outl(ahd, SHARED_DATA_ADDR, busaddr); 6798123579Sgibbs ahd_outl(ahd, QOUTFIFO_NEXT_ADDR, busaddr); 679997883Sgibbs 680097883Sgibbs /* 680197883Sgibbs * Setup the allowed SCSI Sequences based on operational mode. 680297883Sgibbs * If we are a target, we'll enable select in operations once 680397883Sgibbs * we've had a lun enabled. 680497883Sgibbs */ 680597883Sgibbs scsiseq_template = ENAUTOATNP; 680697883Sgibbs if ((ahd->flags & AHD_INITIATORROLE) != 0) 680797883Sgibbs scsiseq_template |= ENRSELI; 680897883Sgibbs ahd_outb(ahd, SCSISEQ_TEMPLATE, scsiseq_template); 680997883Sgibbs 681097883Sgibbs /* There are no busy SCBs yet. */ 681197883Sgibbs for (target = 0; target < AHD_NUM_TARGETS; target++) { 681297883Sgibbs int lun; 681397883Sgibbs 681497883Sgibbs for (lun = 0; lun < AHD_NUM_LUNS_NONPKT; lun++) 681597883Sgibbs ahd_unbusy_tcl(ahd, BUILD_TCL_RAW(target, 'A', lun)); 681697883Sgibbs } 681797883Sgibbs 681897883Sgibbs /* 681997883Sgibbs * Initialize the group code to command length table. 682097883Sgibbs * Vendor Unique codes are set to 0 so we only capture 682197883Sgibbs * the first byte of the cdb. These can be overridden 682297883Sgibbs * when target mode is enabled. 682397883Sgibbs */ 682497883Sgibbs ahd_outb(ahd, CMDSIZE_TABLE, 5); 682597883Sgibbs ahd_outb(ahd, CMDSIZE_TABLE + 1, 9); 682697883Sgibbs ahd_outb(ahd, CMDSIZE_TABLE + 2, 9); 682797883Sgibbs ahd_outb(ahd, CMDSIZE_TABLE + 3, 0); 682897883Sgibbs ahd_outb(ahd, CMDSIZE_TABLE + 4, 15); 682997883Sgibbs ahd_outb(ahd, CMDSIZE_TABLE + 5, 11); 683097883Sgibbs ahd_outb(ahd, CMDSIZE_TABLE + 6, 0); 683197883Sgibbs ahd_outb(ahd, CMDSIZE_TABLE + 7, 0); 683297883Sgibbs 683397883Sgibbs /* Tell the sequencer of our initial queue positions */ 683497883Sgibbs ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); 683597883Sgibbs ahd_outb(ahd, QOFF_CTLSTA, SCB_QSIZE_512); 683697883Sgibbs ahd->qinfifonext = 0; 683797883Sgibbs ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); 683897883Sgibbs ahd_set_hescb_qoff(ahd, 0); 683997883Sgibbs ahd_set_snscb_qoff(ahd, 0); 684097883Sgibbs ahd_set_sescb_qoff(ahd, 0); 684197883Sgibbs ahd_set_sdscb_qoff(ahd, 0); 684297883Sgibbs 684397883Sgibbs /* 684497883Sgibbs * Tell the sequencer which SCB will be the next one it receives. 684597883Sgibbs */ 6846123579Sgibbs busaddr = aic_le32toh(ahd->next_queued_hscb->hscb_busaddr); 6847123579Sgibbs ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr); 6848109588Sgibbs 6849109588Sgibbs /* 6850115329Sgibbs * Default to coalescing disabled. 6851109588Sgibbs */ 6852115329Sgibbs ahd_outw(ahd, INT_COALESCING_CMDCOUNT, 0); 6853109588Sgibbs ahd_outw(ahd, CMDS_PENDING, 0); 6854115329Sgibbs ahd_update_coalescing_values(ahd, ahd->int_coalescing_timer, 6855115329Sgibbs ahd->int_coalescing_maxcmds, 6856115329Sgibbs ahd->int_coalescing_mincmds); 6857115329Sgibbs ahd_enable_coalescing(ahd, FALSE); 6858109588Sgibbs 685997883Sgibbs ahd_loadseq(ahd); 686097883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 686197883Sgibbs} 686297883Sgibbs 686397883Sgibbs/* 686497883Sgibbs * Setup default device and controller settings. 686597883Sgibbs * This should only be called if our probe has 686697883Sgibbs * determined that no configuration data is available. 686797883Sgibbs */ 686897883Sgibbsint 686997883Sgibbsahd_default_config(struct ahd_softc *ahd) 687097883Sgibbs{ 687197883Sgibbs int targ; 687297883Sgibbs 687397883Sgibbs ahd->our_id = 7; 687497883Sgibbs 687597883Sgibbs /* 687697883Sgibbs * Allocate a tstate to house information for our 687797883Sgibbs * initiator presence on the bus as well as the user 687897883Sgibbs * data for any target mode initiator. 687997883Sgibbs */ 688097883Sgibbs if (ahd_alloc_tstate(ahd, ahd->our_id, 'A') == NULL) { 688197883Sgibbs printf("%s: unable to allocate ahd_tmode_tstate. " 688297883Sgibbs "Failing attach\n", ahd_name(ahd)); 6883199260Sattilio AHD_FATAL_ERROR(ahd); 688497883Sgibbs return (ENOMEM); 688597883Sgibbs } 688697883Sgibbs 688797883Sgibbs for (targ = 0; targ < AHD_NUM_TARGETS; targ++) { 688897883Sgibbs struct ahd_devinfo devinfo; 688997883Sgibbs struct ahd_initiator_tinfo *tinfo; 689097883Sgibbs struct ahd_tmode_tstate *tstate; 689197883Sgibbs uint16_t target_mask; 689297883Sgibbs 689397883Sgibbs tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, 689497883Sgibbs targ, &tstate); 689597883Sgibbs /* 689697883Sgibbs * We support SPC2 and SPI4. 689797883Sgibbs */ 689897883Sgibbs tinfo->user.protocol_version = 4; 689997883Sgibbs tinfo->user.transport_version = 4; 690097883Sgibbs 690197883Sgibbs target_mask = 0x01 << targ; 690297883Sgibbs ahd->user_discenable |= target_mask; 690397883Sgibbs tstate->discenable |= target_mask; 690497883Sgibbs ahd->user_tagenable |= target_mask; 690597883Sgibbs#ifdef AHD_FORCE_160 690697883Sgibbs tinfo->user.period = AHD_SYNCRATE_DT; 690797883Sgibbs#else 690897883Sgibbs tinfo->user.period = AHD_SYNCRATE_160; 690997883Sgibbs#endif 6910111653Sgibbs tinfo->user.offset = MAX_OFFSET; 691197883Sgibbs tinfo->user.ppr_options = MSG_EXT_PPR_RD_STRM 691297883Sgibbs | MSG_EXT_PPR_WR_FLOW 6913104023Sgibbs | MSG_EXT_PPR_HOLD_MCS 691497883Sgibbs | MSG_EXT_PPR_IU_REQ 691597883Sgibbs | MSG_EXT_PPR_QAS_REQ 691697883Sgibbs | MSG_EXT_PPR_DT_REQ; 6917107441Sscottl if ((ahd->features & AHD_RTI) != 0) 6918107441Sscottl tinfo->user.ppr_options |= MSG_EXT_PPR_RTI; 691997883Sgibbs 692097883Sgibbs tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; 692197883Sgibbs 692297883Sgibbs /* 692397883Sgibbs * Start out Async/Narrow/Untagged and with 692497883Sgibbs * conservative protocol support. 692597883Sgibbs */ 692697883Sgibbs tinfo->goal.protocol_version = 2; 692797883Sgibbs tinfo->goal.transport_version = 2; 692897883Sgibbs tinfo->curr.protocol_version = 2; 692997883Sgibbs tinfo->curr.transport_version = 2; 693097883Sgibbs ahd_compile_devinfo(&devinfo, ahd->our_id, 693197883Sgibbs targ, CAM_LUN_WILDCARD, 693297883Sgibbs 'A', ROLE_INITIATOR); 693397883Sgibbs tstate->tagenable &= ~target_mask; 693497883Sgibbs ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, 693597883Sgibbs AHD_TRANS_CUR|AHD_TRANS_GOAL, /*paused*/TRUE); 693697883Sgibbs ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, 693797883Sgibbs /*ppr_options*/0, AHD_TRANS_CUR|AHD_TRANS_GOAL, 693897883Sgibbs /*paused*/TRUE); 693997883Sgibbs } 694097883Sgibbs return (0); 694197883Sgibbs} 694297883Sgibbs 694397883Sgibbs/* 694497883Sgibbs * Parse device configuration information. 694597883Sgibbs */ 694697883Sgibbsint 694797883Sgibbsahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc) 694897883Sgibbs{ 694997883Sgibbs int targ; 695097883Sgibbs int max_targ; 695197883Sgibbs 695297883Sgibbs max_targ = sc->max_targets & CFMAXTARG; 695397883Sgibbs ahd->our_id = sc->brtime_id & CFSCSIID; 695497883Sgibbs 695597883Sgibbs /* 695697883Sgibbs * Allocate a tstate to house information for our 695797883Sgibbs * initiator presence on the bus as well as the user 695897883Sgibbs * data for any target mode initiator. 695997883Sgibbs */ 696097883Sgibbs if (ahd_alloc_tstate(ahd, ahd->our_id, 'A') == NULL) { 696197883Sgibbs printf("%s: unable to allocate ahd_tmode_tstate. " 696297883Sgibbs "Failing attach\n", ahd_name(ahd)); 6963199260Sattilio AHD_FATAL_ERROR(ahd); 696497883Sgibbs return (ENOMEM); 696597883Sgibbs } 696697883Sgibbs 696797883Sgibbs for (targ = 0; targ < max_targ; targ++) { 696897883Sgibbs struct ahd_devinfo devinfo; 696997883Sgibbs struct ahd_initiator_tinfo *tinfo; 697097883Sgibbs struct ahd_transinfo *user_tinfo; 697197883Sgibbs struct ahd_tmode_tstate *tstate; 697297883Sgibbs uint16_t target_mask; 697397883Sgibbs 697497883Sgibbs tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, 697597883Sgibbs targ, &tstate); 697697883Sgibbs user_tinfo = &tinfo->user; 697797883Sgibbs 697897883Sgibbs /* 697997883Sgibbs * We support SPC2 and SPI4. 698097883Sgibbs */ 698197883Sgibbs tinfo->user.protocol_version = 4; 698297883Sgibbs tinfo->user.transport_version = 4; 698397883Sgibbs 698497883Sgibbs target_mask = 0x01 << targ; 698597883Sgibbs ahd->user_discenable &= ~target_mask; 698697883Sgibbs tstate->discenable &= ~target_mask; 698797883Sgibbs ahd->user_tagenable &= ~target_mask; 698897883Sgibbs if (sc->device_flags[targ] & CFDISC) { 698997883Sgibbs tstate->discenable |= target_mask; 699097883Sgibbs ahd->user_discenable |= target_mask; 699197883Sgibbs ahd->user_tagenable |= target_mask; 699297883Sgibbs } else { 699397883Sgibbs /* 699497883Sgibbs * Cannot be packetized without disconnection. 699597883Sgibbs */ 699697883Sgibbs sc->device_flags[targ] &= ~CFPACKETIZED; 699797883Sgibbs } 699897883Sgibbs 699997883Sgibbs user_tinfo->ppr_options = 0; 700097883Sgibbs user_tinfo->period = (sc->device_flags[targ] & CFXFER); 700197883Sgibbs if (user_tinfo->period < CFXFER_ASYNC) { 700297883Sgibbs if (user_tinfo->period <= AHD_PERIOD_10MHz) 700397883Sgibbs user_tinfo->ppr_options |= MSG_EXT_PPR_DT_REQ; 700497883Sgibbs user_tinfo->offset = MAX_OFFSET; 700597883Sgibbs } else { 700697883Sgibbs user_tinfo->offset = 0; 7007109588Sgibbs user_tinfo->period = AHD_ASYNC_XFER_PERIOD; 700897883Sgibbs } 700997883Sgibbs#ifdef AHD_FORCE_160 701097883Sgibbs if (user_tinfo->period <= AHD_SYNCRATE_160) 701197883Sgibbs user_tinfo->period = AHD_SYNCRATE_DT; 701297883Sgibbs#endif 701397883Sgibbs 7014107441Sscottl if ((sc->device_flags[targ] & CFPACKETIZED) != 0) { 701597883Sgibbs user_tinfo->ppr_options |= MSG_EXT_PPR_RD_STRM 701697883Sgibbs | MSG_EXT_PPR_WR_FLOW 7017104023Sgibbs | MSG_EXT_PPR_HOLD_MCS 701897883Sgibbs | MSG_EXT_PPR_IU_REQ; 7019107441Sscottl if ((ahd->features & AHD_RTI) != 0) 7020107441Sscottl user_tinfo->ppr_options |= MSG_EXT_PPR_RTI; 7021107441Sscottl } 702297883Sgibbs 702397883Sgibbs if ((sc->device_flags[targ] & CFQAS) != 0) 702497883Sgibbs user_tinfo->ppr_options |= MSG_EXT_PPR_QAS_REQ; 702597883Sgibbs 702697883Sgibbs if ((sc->device_flags[targ] & CFWIDEB) != 0) 702797883Sgibbs user_tinfo->width = MSG_EXT_WDTR_BUS_16_BIT; 702897883Sgibbs else 702997883Sgibbs user_tinfo->width = MSG_EXT_WDTR_BUS_8_BIT; 703097883Sgibbs#ifdef AHD_DEBUG 703197883Sgibbs if ((ahd_debug & AHD_SHOW_MISC) != 0) 703297883Sgibbs printf("(%d): %x:%x:%x:%x\n", targ, user_tinfo->width, 703397883Sgibbs user_tinfo->period, user_tinfo->offset, 703497883Sgibbs user_tinfo->ppr_options); 703597883Sgibbs#endif 703697883Sgibbs /* 703797883Sgibbs * Start out Async/Narrow/Untagged and with 703897883Sgibbs * conservative protocol support. 703997883Sgibbs */ 704097883Sgibbs tstate->tagenable &= ~target_mask; 704197883Sgibbs tinfo->goal.protocol_version = 2; 704297883Sgibbs tinfo->goal.transport_version = 2; 704397883Sgibbs tinfo->curr.protocol_version = 2; 704497883Sgibbs tinfo->curr.transport_version = 2; 704597883Sgibbs ahd_compile_devinfo(&devinfo, ahd->our_id, 704697883Sgibbs targ, CAM_LUN_WILDCARD, 704797883Sgibbs 'A', ROLE_INITIATOR); 704897883Sgibbs ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, 704997883Sgibbs AHD_TRANS_CUR|AHD_TRANS_GOAL, /*paused*/TRUE); 705097883Sgibbs ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, 705197883Sgibbs /*ppr_options*/0, AHD_TRANS_CUR|AHD_TRANS_GOAL, 705297883Sgibbs /*paused*/TRUE); 705397883Sgibbs } 705497883Sgibbs 705597883Sgibbs ahd->flags &= ~AHD_SPCHK_ENB_A; 705697883Sgibbs if (sc->bios_control & CFSPARITY) 705797883Sgibbs ahd->flags |= AHD_SPCHK_ENB_A; 705897883Sgibbs 705997883Sgibbs ahd->flags &= ~AHD_RESET_BUS_A; 706097883Sgibbs if (sc->bios_control & CFRESETB) 706197883Sgibbs ahd->flags |= AHD_RESET_BUS_A; 706297883Sgibbs 706397883Sgibbs ahd->flags &= ~AHD_EXTENDED_TRANS_A; 706497883Sgibbs if (sc->bios_control & CFEXTEND) 706597883Sgibbs ahd->flags |= AHD_EXTENDED_TRANS_A; 706697883Sgibbs 706797883Sgibbs ahd->flags &= ~AHD_BIOS_ENABLED; 706897883Sgibbs if ((sc->bios_control & CFBIOSSTATE) == CFBS_ENABLED) 706997883Sgibbs ahd->flags |= AHD_BIOS_ENABLED; 707097883Sgibbs 707197883Sgibbs ahd->flags &= ~AHD_STPWLEVEL_A; 707297883Sgibbs if ((sc->adapter_control & CFSTPWLEVEL) != 0) 707397883Sgibbs ahd->flags |= AHD_STPWLEVEL_A; 707497883Sgibbs 707597883Sgibbs return (0); 707697883Sgibbs} 707797883Sgibbs 7078114623Sgibbs/* 7079114623Sgibbs * Parse device configuration information. 7080114623Sgibbs */ 7081114623Sgibbsint 7082114623Sgibbsahd_parse_vpddata(struct ahd_softc *ahd, struct vpd_config *vpd) 7083114623Sgibbs{ 7084114623Sgibbs int error; 7085114623Sgibbs 7086114623Sgibbs error = ahd_verify_vpd_cksum(vpd); 7087114623Sgibbs if (error == 0) 7088114623Sgibbs return (EINVAL); 7089114623Sgibbs if ((vpd->bios_flags & VPDBOOTHOST) != 0) 7090114623Sgibbs ahd->flags |= AHD_BOOT_CHANNEL; 7091114623Sgibbs return (0); 7092114623Sgibbs} 7093114623Sgibbs 709497883Sgibbsvoid 709597883Sgibbsahd_intr_enable(struct ahd_softc *ahd, int enable) 709697883Sgibbs{ 709797883Sgibbs u_int hcntrl; 709897883Sgibbs 709997883Sgibbs hcntrl = ahd_inb(ahd, HCNTRL); 710097883Sgibbs hcntrl &= ~INTEN; 710197883Sgibbs ahd->pause &= ~INTEN; 710297883Sgibbs ahd->unpause &= ~INTEN; 710397883Sgibbs if (enable) { 710497883Sgibbs hcntrl |= INTEN; 710597883Sgibbs ahd->pause |= INTEN; 710697883Sgibbs ahd->unpause |= INTEN; 710797883Sgibbs } 710897883Sgibbs ahd_outb(ahd, HCNTRL, hcntrl); 710997883Sgibbs} 711097883Sgibbs 7111109588Sgibbsvoid 7112115329Sgibbsahd_update_coalescing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds, 7113109588Sgibbs u_int mincmds) 7114109588Sgibbs{ 7115109588Sgibbs if (timer > AHD_TIMER_MAX_US) 7116109588Sgibbs timer = AHD_TIMER_MAX_US; 7117115329Sgibbs ahd->int_coalescing_timer = timer; 7118109588Sgibbs 7119115329Sgibbs if (maxcmds > AHD_INT_COALESCING_MAXCMDS_MAX) 7120115329Sgibbs maxcmds = AHD_INT_COALESCING_MAXCMDS_MAX; 7121115329Sgibbs if (mincmds > AHD_INT_COALESCING_MINCMDS_MAX) 7122115329Sgibbs mincmds = AHD_INT_COALESCING_MINCMDS_MAX; 7123115329Sgibbs ahd->int_coalescing_maxcmds = maxcmds; 7124115329Sgibbs ahd_outw(ahd, INT_COALESCING_TIMER, timer / AHD_TIMER_US_PER_TICK); 7125115329Sgibbs ahd_outb(ahd, INT_COALESCING_MAXCMDS, -maxcmds); 7126115329Sgibbs ahd_outb(ahd, INT_COALESCING_MINCMDS, -mincmds); 7127109588Sgibbs} 7128109588Sgibbs 7129109588Sgibbsvoid 7130115329Sgibbsahd_enable_coalescing(struct ahd_softc *ahd, int enable) 7131109588Sgibbs{ 7132109588Sgibbs 7133115329Sgibbs ahd->hs_mailbox &= ~ENINT_COALESCE; 7134109588Sgibbs if (enable) 7135115329Sgibbs ahd->hs_mailbox |= ENINT_COALESCE; 7136109588Sgibbs ahd_outb(ahd, HS_MAILBOX, ahd->hs_mailbox); 7137109588Sgibbs ahd_flush_device_writes(ahd); 7138109588Sgibbs ahd_run_qoutfifo(ahd); 7139109588Sgibbs} 7140109588Sgibbs 714197883Sgibbs/* 714297883Sgibbs * Ensure that the card is paused in a location 714397883Sgibbs * outside of all critical sections and that all 714497883Sgibbs * pending work is completed prior to returning. 714597883Sgibbs * This routine should only be called from outside 714697883Sgibbs * an interrupt context. 714797883Sgibbs */ 714897883Sgibbsvoid 714997883Sgibbsahd_pause_and_flushwork(struct ahd_softc *ahd) 715097883Sgibbs{ 7151114623Sgibbs u_int intstat; 7152114623Sgibbs u_int maxloops; 715397883Sgibbs 715497883Sgibbs maxloops = 1000; 715597883Sgibbs ahd->flags |= AHD_ALL_INTERRUPTS; 7156114623Sgibbs ahd_pause(ahd); 7157114623Sgibbs /* 7158125448Sgibbs * Freeze the outgoing selections. We do this only 7159114623Sgibbs * until we are safely paused without further selections 7160114623Sgibbs * pending. 7161114623Sgibbs */ 7162125448Sgibbs ahd->qfreeze_cnt--; 7163125448Sgibbs ahd_outw(ahd, KERNEL_QFREEZE_COUNT, ahd->qfreeze_cnt); 7164114623Sgibbs ahd_outb(ahd, SEQ_FLAGS2, ahd_inb(ahd, SEQ_FLAGS2) | SELECTOUT_QFROZEN); 716597883Sgibbs do { 7166109588Sgibbs 7167114623Sgibbs ahd_unpause(ahd); 7168123579Sgibbs /* 7169123579Sgibbs * Give the sequencer some time to service 7170123579Sgibbs * any active selections. 7171123579Sgibbs */ 7172129134Sgibbs aic_delay(500); 7173123579Sgibbs 717497883Sgibbs ahd_intr(ahd); 717597883Sgibbs ahd_pause(ahd); 7176114623Sgibbs intstat = ahd_inb(ahd, INTSTAT); 7177129134Sgibbs if ((intstat & INT_PEND) == 0) { 7178129134Sgibbs ahd_clear_critical_section(ahd); 7179129134Sgibbs intstat = ahd_inb(ahd, INTSTAT); 7180129134Sgibbs } 7181109588Sgibbs } while (--maxloops 7182111653Sgibbs && (intstat != 0xFF || (ahd->features & AHD_REMOVABLE) == 0) 7183111653Sgibbs && ((intstat & INT_PEND) != 0 7184114623Sgibbs || (ahd_inb(ahd, SCSISEQ0) & ENSELO) != 0 7185114623Sgibbs || (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) != 0)); 7186114623Sgibbs 718797883Sgibbs if (maxloops == 0) { 718897883Sgibbs printf("Infinite interrupt loop, INTSTAT = %x", 718997883Sgibbs ahd_inb(ahd, INTSTAT)); 7190199260Sattilio AHD_FATAL_ERROR(ahd); 719197883Sgibbs } 7192125448Sgibbs ahd->qfreeze_cnt++; 7193125448Sgibbs ahd_outw(ahd, KERNEL_QFREEZE_COUNT, ahd->qfreeze_cnt); 7194109588Sgibbs 7195109588Sgibbs ahd_flush_qoutfifo(ahd); 7196109588Sgibbs 719797883Sgibbs ahd_platform_flushwork(ahd); 719897883Sgibbs ahd->flags &= ~AHD_ALL_INTERRUPTS; 719997883Sgibbs} 720097883Sgibbs 720197883Sgibbsint 720297883Sgibbsahd_suspend(struct ahd_softc *ahd) 720397883Sgibbs{ 720497883Sgibbs 720597883Sgibbs ahd_pause_and_flushwork(ahd); 720697883Sgibbs 7207115917Sgibbs if (LIST_FIRST(&ahd->pending_scbs) != NULL) { 7208115917Sgibbs ahd_unpause(ahd); 720997883Sgibbs return (EBUSY); 721097883Sgibbs } 721197883Sgibbs ahd_shutdown(ahd); 721297883Sgibbs return (0); 721397883Sgibbs} 721497883Sgibbs 721597883Sgibbsint 721697883Sgibbsahd_resume(struct ahd_softc *ahd) 721797883Sgibbs{ 721897883Sgibbs 7219115917Sgibbs ahd_reset(ahd, /*reinit*/TRUE); 7220115917Sgibbs ahd_intr_enable(ahd, TRUE); 7221115917Sgibbs ahd_restart(ahd); 722297883Sgibbs return (0); 722397883Sgibbs} 722497883Sgibbs 722597883Sgibbs/************************** Busy Target Table *********************************/ 722697883Sgibbs/* 722797883Sgibbs * Set SCBPTR to the SCB that contains the busy 722897883Sgibbs * table entry for TCL. Return the offset into 722997883Sgibbs * the SCB that contains the entry for TCL. 723097883Sgibbs * saved_scbid is dereferenced and set to the 723197883Sgibbs * scbid that should be restored once manipualtion 723297883Sgibbs * of the TCL entry is complete. 723397883Sgibbs */ 723497883Sgibbsstatic __inline u_int 723597883Sgibbsahd_index_busy_tcl(struct ahd_softc *ahd, u_int *saved_scbid, u_int tcl) 723697883Sgibbs{ 723797883Sgibbs /* 723897883Sgibbs * Index to the SCB that contains the busy entry. 723997883Sgibbs */ 7240104023Sgibbs AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 7241104023Sgibbs *saved_scbid = ahd_get_scbptr(ahd); 724297883Sgibbs ahd_set_scbptr(ahd, TCL_LUN(tcl) 7243102679Sgibbs | ((TCL_TARGET_OFFSET(tcl) & 0xC) << 4)); 724497883Sgibbs 724597883Sgibbs /* 724697883Sgibbs * And now calculate the SCB offset to the entry. 724797883Sgibbs * Each entry is 2 bytes wide, hence the 724897883Sgibbs * multiplication by 2. 724997883Sgibbs */ 7250102679Sgibbs return (((TCL_TARGET_OFFSET(tcl) & 0x3) << 1) + SCB_DISCONNECTED_LISTS); 725197883Sgibbs} 725297883Sgibbs 725397883Sgibbs/* 725497883Sgibbs * Return the untagged transaction id for a given target/channel lun. 725597883Sgibbs */ 725697883Sgibbsu_int 725797883Sgibbsahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl) 725897883Sgibbs{ 725997883Sgibbs u_int scbid; 726097883Sgibbs u_int scb_offset; 726197883Sgibbs u_int saved_scbptr; 726297883Sgibbs 726397883Sgibbs scb_offset = ahd_index_busy_tcl(ahd, &saved_scbptr, tcl); 726497883Sgibbs scbid = ahd_inw_scbram(ahd, scb_offset); 726597883Sgibbs ahd_set_scbptr(ahd, saved_scbptr); 726697883Sgibbs return (scbid); 726797883Sgibbs} 726897883Sgibbs 726997883Sgibbsvoid 727097883Sgibbsahd_busy_tcl(struct ahd_softc *ahd, u_int tcl, u_int scbid) 727197883Sgibbs{ 727297883Sgibbs u_int scb_offset; 727397883Sgibbs u_int saved_scbptr; 727497883Sgibbs 727597883Sgibbs scb_offset = ahd_index_busy_tcl(ahd, &saved_scbptr, tcl); 727697883Sgibbs ahd_outw(ahd, scb_offset, scbid); 727797883Sgibbs ahd_set_scbptr(ahd, saved_scbptr); 727897883Sgibbs} 727997883Sgibbs 728097883Sgibbs/************************** SCB and SCB queue management **********************/ 728197883Sgibbsint 728297883Sgibbsahd_match_scb(struct ahd_softc *ahd, struct scb *scb, int target, 728397883Sgibbs char channel, int lun, u_int tag, role_t role) 728497883Sgibbs{ 728597883Sgibbs int targ = SCB_GET_TARGET(ahd, scb); 728697883Sgibbs char chan = SCB_GET_CHANNEL(ahd, scb); 728797883Sgibbs int slun = SCB_GET_LUN(scb); 728897883Sgibbs int match; 728997883Sgibbs 729097883Sgibbs match = ((chan == channel) || (channel == ALL_CHANNELS)); 729197883Sgibbs if (match != 0) 729297883Sgibbs match = ((targ == target) || (target == CAM_TARGET_WILDCARD)); 729397883Sgibbs if (match != 0) 729497883Sgibbs match = ((lun == slun) || (lun == CAM_LUN_WILDCARD)); 729597883Sgibbs if (match != 0) { 7296153072Sru#ifdef AHD_TARGET_MODE 729797883Sgibbs int group; 729897883Sgibbs 729997883Sgibbs group = XPT_FC_GROUP(scb->io_ctx->ccb_h.func_code); 730097883Sgibbs if (role == ROLE_INITIATOR) { 730197883Sgibbs match = (group != XPT_FC_GROUP_TMODE) 730297883Sgibbs && ((tag == SCB_GET_TAG(scb)) 730397883Sgibbs || (tag == SCB_LIST_NULL)); 730497883Sgibbs } else if (role == ROLE_TARGET) { 730597883Sgibbs match = (group == XPT_FC_GROUP_TMODE) 730697883Sgibbs && ((tag == scb->io_ctx->csio.tag_id) 730797883Sgibbs || (tag == SCB_LIST_NULL)); 730897883Sgibbs } 730997883Sgibbs#else /* !AHD_TARGET_MODE */ 731097883Sgibbs match = ((tag == SCB_GET_TAG(scb)) || (tag == SCB_LIST_NULL)); 731197883Sgibbs#endif /* AHD_TARGET_MODE */ 731297883Sgibbs } 731397883Sgibbs 731497883Sgibbs return match; 731597883Sgibbs} 731697883Sgibbs 731797883Sgibbsvoid 731897883Sgibbsahd_freeze_devq(struct ahd_softc *ahd, struct scb *scb) 731997883Sgibbs{ 732097883Sgibbs int target; 732197883Sgibbs char channel; 732297883Sgibbs int lun; 732397883Sgibbs 732497883Sgibbs target = SCB_GET_TARGET(ahd, scb); 732597883Sgibbs lun = SCB_GET_LUN(scb); 732697883Sgibbs channel = SCB_GET_CHANNEL(ahd, scb); 732797883Sgibbs 732897883Sgibbs ahd_search_qinfifo(ahd, target, channel, lun, 732997883Sgibbs /*tag*/SCB_LIST_NULL, ROLE_UNKNOWN, 733097883Sgibbs CAM_REQUEUE_REQ, SEARCH_COMPLETE); 733197883Sgibbs 733297883Sgibbs ahd_platform_freeze_devq(ahd, scb); 733397883Sgibbs} 733497883Sgibbs 733597883Sgibbsvoid 733697883Sgibbsahd_qinfifo_requeue_tail(struct ahd_softc *ahd, struct scb *scb) 733797883Sgibbs{ 7338107441Sscottl struct scb *prev_scb; 7339107441Sscottl ahd_mode_state saved_modes; 734097883Sgibbs 7341107441Sscottl saved_modes = ahd_save_modes(ahd); 7342107441Sscottl ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); 734397883Sgibbs prev_scb = NULL; 734497883Sgibbs if (ahd_qinfifo_count(ahd) != 0) { 734597883Sgibbs u_int prev_tag; 734697883Sgibbs u_int prev_pos; 734797883Sgibbs 734897883Sgibbs prev_pos = AHD_QIN_WRAP(ahd->qinfifonext - 1); 734997883Sgibbs prev_tag = ahd->qinfifo[prev_pos]; 735097883Sgibbs prev_scb = ahd_lookup_scb(ahd, prev_tag); 735197883Sgibbs } 735297883Sgibbs ahd_qinfifo_requeue(ahd, prev_scb, scb); 735397883Sgibbs ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); 7354107441Sscottl ahd_restore_modes(ahd, saved_modes); 735597883Sgibbs} 735697883Sgibbs 735797883Sgibbsstatic void 735897883Sgibbsahd_qinfifo_requeue(struct ahd_softc *ahd, struct scb *prev_scb, 735997883Sgibbs struct scb *scb) 736097883Sgibbs{ 736197883Sgibbs if (prev_scb == NULL) { 736297883Sgibbs uint32_t busaddr; 736397883Sgibbs 7364123579Sgibbs busaddr = aic_le32toh(scb->hscb->hscb_busaddr); 7365123579Sgibbs ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr); 736697883Sgibbs } else { 736797883Sgibbs prev_scb->hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr; 736897883Sgibbs ahd_sync_scb(ahd, prev_scb, 736997883Sgibbs BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 737097883Sgibbs } 737197883Sgibbs ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb); 737297883Sgibbs ahd->qinfifonext++; 7373102679Sgibbs scb->hscb->next_hscb_busaddr = ahd->next_queued_hscb->hscb_busaddr; 737497883Sgibbs ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 737597883Sgibbs} 737697883Sgibbs 737797883Sgibbsstatic int 737897883Sgibbsahd_qinfifo_count(struct ahd_softc *ahd) 737997883Sgibbs{ 738097883Sgibbs u_int qinpos; 738197883Sgibbs u_int wrap_qinpos; 738297883Sgibbs u_int wrap_qinfifonext; 738397883Sgibbs 738497883Sgibbs AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 738597883Sgibbs qinpos = ahd_get_snscb_qoff(ahd); 738697883Sgibbs wrap_qinpos = AHD_QIN_WRAP(qinpos); 738797883Sgibbs wrap_qinfifonext = AHD_QIN_WRAP(ahd->qinfifonext); 7388109588Sgibbs if (wrap_qinfifonext >= wrap_qinpos) 738997883Sgibbs return (wrap_qinfifonext - wrap_qinpos); 739097883Sgibbs else 739197883Sgibbs return (wrap_qinfifonext 739297883Sgibbs + NUM_ELEMENTS(ahd->qinfifo) - wrap_qinpos); 739397883Sgibbs} 739497883Sgibbs 7395109588Sgibbsvoid 7396109588Sgibbsahd_reset_cmds_pending(struct ahd_softc *ahd) 7397109588Sgibbs{ 7398109588Sgibbs struct scb *scb; 7399109588Sgibbs ahd_mode_state saved_modes; 7400109588Sgibbs u_int pending_cmds; 7401109588Sgibbs 7402109588Sgibbs saved_modes = ahd_save_modes(ahd); 7403109588Sgibbs ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); 7404109588Sgibbs 7405109588Sgibbs /* 7406109588Sgibbs * Don't count any commands as outstanding that the 7407109588Sgibbs * sequencer has already marked for completion. 7408109588Sgibbs */ 7409109588Sgibbs ahd_flush_qoutfifo(ahd); 7410109588Sgibbs 7411109588Sgibbs pending_cmds = 0; 7412109588Sgibbs LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) { 7413109588Sgibbs pending_cmds++; 7414109588Sgibbs } 7415109588Sgibbs ahd_outw(ahd, CMDS_PENDING, pending_cmds - ahd_qinfifo_count(ahd)); 7416109588Sgibbs ahd_restore_modes(ahd, saved_modes); 7417109588Sgibbs ahd->flags &= ~AHD_UPDATE_PEND_CMDS; 7418109588Sgibbs} 7419109588Sgibbs 7420133122Sgibbsvoid 7421133122Sgibbsahd_done_with_status(struct ahd_softc *ahd, struct scb *scb, uint32_t status) 7422133122Sgibbs{ 7423133122Sgibbs cam_status ostat; 7424133122Sgibbs cam_status cstat; 7425133122Sgibbs 7426133122Sgibbs ostat = aic_get_transaction_status(scb); 7427133122Sgibbs if (ostat == CAM_REQ_INPROG) 7428133122Sgibbs aic_set_transaction_status(scb, status); 7429133122Sgibbs cstat = aic_get_transaction_status(scb); 7430133122Sgibbs if (cstat != CAM_REQ_CMP) 7431133122Sgibbs aic_freeze_scb(scb); 7432133122Sgibbs ahd_done(ahd, scb); 7433133122Sgibbs} 7434133122Sgibbs 743597883Sgibbsint 743697883Sgibbsahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel, 743797883Sgibbs int lun, u_int tag, role_t role, uint32_t status, 743897883Sgibbs ahd_search_action action) 743997883Sgibbs{ 744097883Sgibbs struct scb *scb; 7441133122Sgibbs struct scb *mk_msg_scb; 744297883Sgibbs struct scb *prev_scb; 744397883Sgibbs ahd_mode_state saved_modes; 744497883Sgibbs u_int qinstart; 744597883Sgibbs u_int qinpos; 744697883Sgibbs u_int qintail; 744797883Sgibbs u_int tid_next; 744897883Sgibbs u_int tid_prev; 744997883Sgibbs u_int scbid; 7450133122Sgibbs u_int seq_flags2; 745197883Sgibbs u_int savedscbptr; 745297883Sgibbs uint32_t busaddr; 745397883Sgibbs int found; 745497883Sgibbs int targets; 745597883Sgibbs 745697883Sgibbs /* Must be in CCHAN mode */ 745797883Sgibbs saved_modes = ahd_save_modes(ahd); 745897883Sgibbs ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); 745997883Sgibbs 746097883Sgibbs /* 746197883Sgibbs * Halt any pending SCB DMA. The sequencer will reinitiate 746297883Sgibbs * this dma if the qinfifo is not empty once we unpause. 746397883Sgibbs */ 746497883Sgibbs if ((ahd_inb(ahd, CCSCBCTL) & (CCARREN|CCSCBEN|CCSCBDIR)) 746597883Sgibbs == (CCARREN|CCSCBEN|CCSCBDIR)) { 746697883Sgibbs ahd_outb(ahd, CCSCBCTL, 746797883Sgibbs ahd_inb(ahd, CCSCBCTL) & ~(CCARREN|CCSCBEN)); 746897883Sgibbs while ((ahd_inb(ahd, CCSCBCTL) & (CCARREN|CCSCBEN)) != 0) 746997883Sgibbs ; 747097883Sgibbs } 747197883Sgibbs /* Determine sequencer's position in the qinfifo. */ 747297883Sgibbs qintail = AHD_QIN_WRAP(ahd->qinfifonext); 747397883Sgibbs qinstart = ahd_get_snscb_qoff(ahd); 747497883Sgibbs qinpos = AHD_QIN_WRAP(qinstart); 747597883Sgibbs found = 0; 747697883Sgibbs prev_scb = NULL; 747797883Sgibbs 747897883Sgibbs if (action == SEARCH_PRINT) { 747997883Sgibbs printf("qinstart = %d qinfifonext = %d\nQINFIFO:", 748097883Sgibbs qinstart, ahd->qinfifonext); 748197883Sgibbs } 748297883Sgibbs 748397883Sgibbs /* 748497883Sgibbs * Start with an empty queue. Entries that are not chosen 748597883Sgibbs * for removal will be re-added to the queue as we go. 748697883Sgibbs */ 748797883Sgibbs ahd->qinfifonext = qinstart; 7488123579Sgibbs busaddr = aic_le32toh(ahd->next_queued_hscb->hscb_busaddr); 7489123579Sgibbs ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr); 749097883Sgibbs 749197883Sgibbs while (qinpos != qintail) { 749297883Sgibbs scb = ahd_lookup_scb(ahd, ahd->qinfifo[qinpos]); 749397883Sgibbs if (scb == NULL) { 749497883Sgibbs printf("qinpos = %d, SCB index = %d\n", 749597883Sgibbs qinpos, ahd->qinfifo[qinpos]); 7496199260Sattilio AHD_FATAL_ERROR(ahd); 749797883Sgibbs panic("Loop 1\n"); 749897883Sgibbs } 749997883Sgibbs 750097883Sgibbs if (ahd_match_scb(ahd, scb, target, channel, lun, tag, role)) { 750197883Sgibbs /* 750297883Sgibbs * We found an scb that needs to be acted on. 750397883Sgibbs */ 750497883Sgibbs found++; 750597883Sgibbs switch (action) { 750697883Sgibbs case SEARCH_COMPLETE: 750797883Sgibbs if ((scb->flags & SCB_ACTIVE) == 0) 750897883Sgibbs printf("Inactive SCB in qinfifo\n"); 7509133122Sgibbs ahd_done_with_status(ahd, scb, status); 751097883Sgibbs /* FALLTHROUGH */ 751197883Sgibbs case SEARCH_REMOVE: 751297883Sgibbs break; 751397883Sgibbs case SEARCH_PRINT: 751497883Sgibbs printf(" 0x%x", ahd->qinfifo[qinpos]); 751597883Sgibbs /* FALLTHROUGH */ 751697883Sgibbs case SEARCH_COUNT: 751797883Sgibbs ahd_qinfifo_requeue(ahd, prev_scb, scb); 751897883Sgibbs prev_scb = scb; 751997883Sgibbs break; 752097883Sgibbs } 752197883Sgibbs } else { 752297883Sgibbs ahd_qinfifo_requeue(ahd, prev_scb, scb); 752397883Sgibbs prev_scb = scb; 752497883Sgibbs } 752597883Sgibbs qinpos = AHD_QIN_WRAP(qinpos+1); 752697883Sgibbs } 752797883Sgibbs 752897883Sgibbs ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); 752997883Sgibbs 753097883Sgibbs if (action == SEARCH_PRINT) 753197883Sgibbs printf("\nWAITING_TID_QUEUES:\n"); 753297883Sgibbs 753397883Sgibbs /* 753497883Sgibbs * Search waiting for selection lists. We traverse the 753597883Sgibbs * list of "their ids" waiting for selection and, if 753697883Sgibbs * appropriate, traverse the SCBs of each "their id" 753797883Sgibbs * looking for matches. 753897883Sgibbs */ 7539125448Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 7540133122Sgibbs seq_flags2 = ahd_inb(ahd, SEQ_FLAGS2); 7541133122Sgibbs if ((seq_flags2 & PENDING_MK_MESSAGE) != 0) { 7542133122Sgibbs scbid = ahd_inw(ahd, MK_MESSAGE_SCB); 7543133122Sgibbs mk_msg_scb = ahd_lookup_scb(ahd, scbid); 7544133122Sgibbs } else 7545133122Sgibbs mk_msg_scb = NULL; 754697883Sgibbs savedscbptr = ahd_get_scbptr(ahd); 754797883Sgibbs tid_next = ahd_inw(ahd, WAITING_TID_HEAD); 754897883Sgibbs tid_prev = SCB_LIST_NULL; 754997883Sgibbs targets = 0; 755097883Sgibbs for (scbid = tid_next; !SCBID_IS_NULL(scbid); scbid = tid_next) { 755197883Sgibbs u_int tid_head; 7552133122Sgibbs u_int tid_tail; 755397883Sgibbs 755497883Sgibbs targets++; 7555133122Sgibbs if (targets > AHD_NUM_TARGETS) 755697883Sgibbs panic("TID LIST LOOP"); 7557133122Sgibbs 755897883Sgibbs if (scbid >= ahd->scb_data.numscbs) { 755997883Sgibbs printf("%s: Waiting TID List inconsistency. " 756097883Sgibbs "SCB index == 0x%x, yet numscbs == 0x%x.", 756197883Sgibbs ahd_name(ahd), scbid, ahd->scb_data.numscbs); 756297883Sgibbs ahd_dump_card_state(ahd); 756397883Sgibbs panic("for safety"); 756497883Sgibbs } 756597883Sgibbs scb = ahd_lookup_scb(ahd, scbid); 756697883Sgibbs if (scb == NULL) { 756797883Sgibbs printf("%s: SCB = 0x%x Not Active!\n", 756897883Sgibbs ahd_name(ahd), scbid); 756997883Sgibbs panic("Waiting TID List traversal\n"); 757097883Sgibbs } 757197883Sgibbs ahd_set_scbptr(ahd, scbid); 757297883Sgibbs tid_next = ahd_inw_scbram(ahd, SCB_NEXT2); 757397883Sgibbs if (ahd_match_scb(ahd, scb, target, channel, CAM_LUN_WILDCARD, 757497883Sgibbs SCB_LIST_NULL, ROLE_UNKNOWN) == 0) { 757597883Sgibbs tid_prev = scbid; 757697883Sgibbs continue; 757797883Sgibbs } 757897883Sgibbs 757997883Sgibbs /* 758097883Sgibbs * We found a list of scbs that needs to be searched. 758197883Sgibbs */ 758297883Sgibbs if (action == SEARCH_PRINT) 758397883Sgibbs printf(" %d ( ", SCB_GET_TARGET(ahd, scb)); 758497883Sgibbs tid_head = scbid; 758597883Sgibbs found += ahd_search_scb_list(ahd, target, channel, 758697883Sgibbs lun, tag, role, status, 7587133122Sgibbs action, &tid_head, &tid_tail, 758897883Sgibbs SCB_GET_TARGET(ahd, scb)); 7589133122Sgibbs /* 7590133122Sgibbs * Check any MK_MESSAGE SCB that is still waiting to 7591133122Sgibbs * enter this target's waiting for selection queue. 7592133122Sgibbs */ 7593133122Sgibbs if (mk_msg_scb != NULL 7594133122Sgibbs && ahd_match_scb(ahd, mk_msg_scb, target, channel, 7595133122Sgibbs lun, tag, role)) { 7596133122Sgibbs 7597133122Sgibbs /* 7598133122Sgibbs * We found an scb that needs to be acted on. 7599133122Sgibbs */ 7600133122Sgibbs found++; 7601133122Sgibbs switch (action) { 7602133122Sgibbs case SEARCH_COMPLETE: 7603133122Sgibbs if ((mk_msg_scb->flags & SCB_ACTIVE) == 0) 7604133122Sgibbs printf("Inactive SCB pending MK_MSG\n"); 7605133122Sgibbs ahd_done_with_status(ahd, mk_msg_scb, status); 7606133122Sgibbs /* FALLTHROUGH */ 7607133122Sgibbs case SEARCH_REMOVE: 7608133122Sgibbs { 7609133122Sgibbs u_int tail_offset; 7610133122Sgibbs 7611133122Sgibbs printf("Removing MK_MSG scb\n"); 7612133122Sgibbs 7613133122Sgibbs /* 7614133122Sgibbs * Reset our tail to the tail of the 7615133122Sgibbs * main per-target list. 7616133122Sgibbs */ 7617133122Sgibbs tail_offset = WAITING_SCB_TAILS 7618133122Sgibbs + (2 * SCB_GET_TARGET(ahd, mk_msg_scb)); 7619133122Sgibbs ahd_outw(ahd, tail_offset, tid_tail); 7620133122Sgibbs 7621133122Sgibbs seq_flags2 &= ~PENDING_MK_MESSAGE; 7622133122Sgibbs ahd_outb(ahd, SEQ_FLAGS2, seq_flags2); 7623133122Sgibbs ahd_outw(ahd, CMDS_PENDING, 7624133122Sgibbs ahd_inw(ahd, CMDS_PENDING)-1); 7625133122Sgibbs mk_msg_scb = NULL; 7626133122Sgibbs break; 7627133122Sgibbs } 7628133122Sgibbs case SEARCH_PRINT: 7629133122Sgibbs printf(" 0x%x", SCB_GET_TAG(scb)); 7630133122Sgibbs /* FALLTHROUGH */ 7631133122Sgibbs case SEARCH_COUNT: 7632133122Sgibbs break; 7633133122Sgibbs } 7634133122Sgibbs } 7635133122Sgibbs 7636133122Sgibbs if (mk_msg_scb != NULL 7637133122Sgibbs && SCBID_IS_NULL(tid_head) 7638133122Sgibbs && ahd_match_scb(ahd, scb, target, channel, CAM_LUN_WILDCARD, 7639133122Sgibbs SCB_LIST_NULL, ROLE_UNKNOWN)) { 7640133122Sgibbs 7641133122Sgibbs /* 7642133122Sgibbs * When removing the last SCB for a target 7643133122Sgibbs * queue with a pending MK_MESSAGE scb, we 7644133122Sgibbs * must queue the MK_MESSAGE scb. 7645133122Sgibbs */ 7646133122Sgibbs printf("Queueing mk_msg_scb\n"); 7647133122Sgibbs tid_head = ahd_inw(ahd, MK_MESSAGE_SCB); 7648133122Sgibbs seq_flags2 &= ~PENDING_MK_MESSAGE; 7649133122Sgibbs ahd_outb(ahd, SEQ_FLAGS2, seq_flags2); 7650133122Sgibbs mk_msg_scb = NULL; 7651133122Sgibbs } 765297883Sgibbs if (tid_head != scbid) 765397883Sgibbs ahd_stitch_tid_list(ahd, tid_prev, tid_head, tid_next); 765497883Sgibbs if (!SCBID_IS_NULL(tid_head)) 765597883Sgibbs tid_prev = tid_head; 765697883Sgibbs if (action == SEARCH_PRINT) 765797883Sgibbs printf(")\n"); 765897883Sgibbs } 7659133122Sgibbs 7660133122Sgibbs /* Restore saved state. */ 766197883Sgibbs ahd_set_scbptr(ahd, savedscbptr); 766297883Sgibbs ahd_restore_modes(ahd, saved_modes); 766397883Sgibbs return (found); 766497883Sgibbs} 766597883Sgibbs 766697883Sgibbsstatic int 766797883Sgibbsahd_search_scb_list(struct ahd_softc *ahd, int target, char channel, 766897883Sgibbs int lun, u_int tag, role_t role, uint32_t status, 7669133122Sgibbs ahd_search_action action, u_int *list_head, 7670133122Sgibbs u_int *list_tail, u_int tid) 767197883Sgibbs{ 767297883Sgibbs struct scb *scb; 767397883Sgibbs u_int scbid; 767497883Sgibbs u_int next; 767597883Sgibbs u_int prev; 767697883Sgibbs int found; 767797883Sgibbs 7678125448Sgibbs AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 767997883Sgibbs found = 0; 768097883Sgibbs prev = SCB_LIST_NULL; 768197883Sgibbs next = *list_head; 7682133122Sgibbs *list_tail = SCB_LIST_NULL; 768397883Sgibbs for (scbid = next; !SCBID_IS_NULL(scbid); scbid = next) { 768497883Sgibbs if (scbid >= ahd->scb_data.numscbs) { 768597883Sgibbs printf("%s:SCB List inconsistency. " 768697883Sgibbs "SCB == 0x%x, yet numscbs == 0x%x.", 768797883Sgibbs ahd_name(ahd), scbid, ahd->scb_data.numscbs); 768897883Sgibbs ahd_dump_card_state(ahd); 768997883Sgibbs panic("for safety"); 769097883Sgibbs } 769197883Sgibbs scb = ahd_lookup_scb(ahd, scbid); 769297883Sgibbs if (scb == NULL) { 769397883Sgibbs printf("%s: SCB = %d Not Active!\n", 769497883Sgibbs ahd_name(ahd), scbid); 769597883Sgibbs panic("Waiting List traversal\n"); 769697883Sgibbs } 769797883Sgibbs ahd_set_scbptr(ahd, scbid); 7698133122Sgibbs *list_tail = scbid; 769997883Sgibbs next = ahd_inw_scbram(ahd, SCB_NEXT); 770097883Sgibbs if (ahd_match_scb(ahd, scb, target, channel, 770197883Sgibbs lun, SCB_LIST_NULL, role) == 0) { 770297883Sgibbs prev = scbid; 770397883Sgibbs continue; 770497883Sgibbs } 770597883Sgibbs found++; 770697883Sgibbs switch (action) { 770797883Sgibbs case SEARCH_COMPLETE: 770897883Sgibbs if ((scb->flags & SCB_ACTIVE) == 0) 770997883Sgibbs printf("Inactive SCB in Waiting List\n"); 7710133122Sgibbs ahd_done_with_status(ahd, scb, status); 771197883Sgibbs /* FALLTHROUGH */ 771297883Sgibbs case SEARCH_REMOVE: 771397883Sgibbs ahd_rem_wscb(ahd, scbid, prev, next, tid); 7714133122Sgibbs *list_tail = prev; 7715133122Sgibbs if (SCBID_IS_NULL(prev)) 771697883Sgibbs *list_head = next; 771797883Sgibbs break; 771897883Sgibbs case SEARCH_PRINT: 771997883Sgibbs printf("0x%x ", scbid); 772097883Sgibbs case SEARCH_COUNT: 772197883Sgibbs prev = scbid; 772297883Sgibbs break; 772397883Sgibbs } 772497883Sgibbs if (found > AHD_SCB_MAX) 772597883Sgibbs panic("SCB LIST LOOP"); 772697883Sgibbs } 7727109588Sgibbs if (action == SEARCH_COMPLETE 7728109588Sgibbs || action == SEARCH_REMOVE) 7729109588Sgibbs ahd_outw(ahd, CMDS_PENDING, ahd_inw(ahd, CMDS_PENDING) - found); 773097883Sgibbs return (found); 773197883Sgibbs} 773297883Sgibbs 773397883Sgibbsstatic void 773497883Sgibbsahd_stitch_tid_list(struct ahd_softc *ahd, u_int tid_prev, 773597883Sgibbs u_int tid_cur, u_int tid_next) 773697883Sgibbs{ 7737125448Sgibbs AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 773897883Sgibbs 773997883Sgibbs if (SCBID_IS_NULL(tid_cur)) { 774097883Sgibbs 774197883Sgibbs /* Bypass current TID list */ 774297883Sgibbs if (SCBID_IS_NULL(tid_prev)) { 774397883Sgibbs ahd_outw(ahd, WAITING_TID_HEAD, tid_next); 774497883Sgibbs } else { 774597883Sgibbs ahd_set_scbptr(ahd, tid_prev); 774697883Sgibbs ahd_outw(ahd, SCB_NEXT2, tid_next); 774797883Sgibbs } 774897883Sgibbs if (SCBID_IS_NULL(tid_next)) 774997883Sgibbs ahd_outw(ahd, WAITING_TID_TAIL, tid_prev); 775097883Sgibbs } else { 775197883Sgibbs 775297883Sgibbs /* Stitch through tid_cur */ 775397883Sgibbs if (SCBID_IS_NULL(tid_prev)) { 775497883Sgibbs ahd_outw(ahd, WAITING_TID_HEAD, tid_cur); 775597883Sgibbs } else { 775697883Sgibbs ahd_set_scbptr(ahd, tid_prev); 775797883Sgibbs ahd_outw(ahd, SCB_NEXT2, tid_cur); 775897883Sgibbs } 775997883Sgibbs ahd_set_scbptr(ahd, tid_cur); 776097883Sgibbs ahd_outw(ahd, SCB_NEXT2, tid_next); 776197883Sgibbs 776297883Sgibbs if (SCBID_IS_NULL(tid_next)) 776397883Sgibbs ahd_outw(ahd, WAITING_TID_TAIL, tid_cur); 776497883Sgibbs } 776597883Sgibbs} 776697883Sgibbs 776797883Sgibbs/* 776897883Sgibbs * Manipulate the waiting for selection list and return the 776997883Sgibbs * scb that follows the one that we remove. 777097883Sgibbs */ 777197883Sgibbsstatic u_int 777297883Sgibbsahd_rem_wscb(struct ahd_softc *ahd, u_int scbid, 777397883Sgibbs u_int prev, u_int next, u_int tid) 777497883Sgibbs{ 777597883Sgibbs u_int tail_offset; 777697883Sgibbs 7777125448Sgibbs AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 777897883Sgibbs if (!SCBID_IS_NULL(prev)) { 777997883Sgibbs ahd_set_scbptr(ahd, prev); 778097883Sgibbs ahd_outw(ahd, SCB_NEXT, next); 778197883Sgibbs } 778297883Sgibbs 778397883Sgibbs /* 7784133122Sgibbs * SCBs that have MK_MESSAGE set in them may 7785133122Sgibbs * cause the tail pointer to be updated without 7786133122Sgibbs * setting the next pointer of the previous tail. 7787133122Sgibbs * Only clear the tail if the removed SCB was 7788133122Sgibbs * the tail. 778997883Sgibbs */ 779097883Sgibbs tail_offset = WAITING_SCB_TAILS + (2 * tid); 779197883Sgibbs if (SCBID_IS_NULL(next) 779297883Sgibbs && ahd_inw(ahd, tail_offset) == scbid) 779397883Sgibbs ahd_outw(ahd, tail_offset, prev); 7794133122Sgibbs 779597883Sgibbs ahd_add_scb_to_free_list(ahd, scbid); 779697883Sgibbs return (next); 779797883Sgibbs} 779897883Sgibbs 779997883Sgibbs/* 780097883Sgibbs * Add the SCB as selected by SCBPTR onto the on chip list of 780197883Sgibbs * free hardware SCBs. This list is empty/unused if we are not 780297883Sgibbs * performing SCB paging. 780397883Sgibbs */ 780497883Sgibbsstatic void 780597883Sgibbsahd_add_scb_to_free_list(struct ahd_softc *ahd, u_int scbid) 780697883Sgibbs{ 780797883Sgibbs/* XXX Need some other mechanism to designate "free". */ 780897883Sgibbs /* 780997883Sgibbs * Invalidate the tag so that our abort 781097883Sgibbs * routines don't think it's active. 781197883Sgibbs ahd_outb(ahd, SCB_TAG, SCB_LIST_NULL); 781297883Sgibbs */ 781397883Sgibbs} 781497883Sgibbs 781597883Sgibbs/******************************** Error Handling ******************************/ 781697883Sgibbs/* 781797883Sgibbs * Abort all SCBs that match the given description (target/channel/lun/tag), 781897883Sgibbs * setting their status to the passed in status if the status has not already 781997883Sgibbs * been modified from CAM_REQ_INPROG. This routine assumes that the sequencer 782097883Sgibbs * is paused before it is called. 782197883Sgibbs */ 782297883Sgibbsint 782397883Sgibbsahd_abort_scbs(struct ahd_softc *ahd, int target, char channel, 782497883Sgibbs int lun, u_int tag, role_t role, uint32_t status) 782597883Sgibbs{ 7826104023Sgibbs struct scb *scbp; 7827104023Sgibbs struct scb *scbp_next; 7828104023Sgibbs u_int i, j; 7829104023Sgibbs u_int maxtarget; 7830104023Sgibbs u_int minlun; 7831104023Sgibbs u_int maxlun; 7832104023Sgibbs int found; 7833104023Sgibbs ahd_mode_state saved_modes; 783497883Sgibbs 7835114623Sgibbs /* restore this when we're done */ 7836104023Sgibbs saved_modes = ahd_save_modes(ahd); 7837114623Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 783897883Sgibbs 783997883Sgibbs found = ahd_search_qinfifo(ahd, target, channel, lun, SCB_LIST_NULL, 784097883Sgibbs role, CAM_REQUEUE_REQ, SEARCH_COMPLETE); 784197883Sgibbs 784297883Sgibbs /* 784397883Sgibbs * Clean out the busy target table for any untagged commands. 784497883Sgibbs */ 784597883Sgibbs i = 0; 784697883Sgibbs maxtarget = 16; 784797883Sgibbs if (target != CAM_TARGET_WILDCARD) { 784897883Sgibbs i = target; 784997883Sgibbs if (channel == 'B') 785097883Sgibbs i += 8; 785197883Sgibbs maxtarget = i + 1; 785297883Sgibbs } 785397883Sgibbs 785497883Sgibbs if (lun == CAM_LUN_WILDCARD) { 785597883Sgibbs minlun = 0; 785697883Sgibbs maxlun = AHD_NUM_LUNS_NONPKT; 785797883Sgibbs } else if (lun >= AHD_NUM_LUNS_NONPKT) { 785897883Sgibbs minlun = maxlun = 0; 785997883Sgibbs } else { 786097883Sgibbs minlun = lun; 786197883Sgibbs maxlun = lun + 1; 786297883Sgibbs } 786397883Sgibbs 786497883Sgibbs if (role != ROLE_TARGET) { 786597883Sgibbs for (;i < maxtarget; i++) { 786697883Sgibbs for (j = minlun;j < maxlun; j++) { 786797883Sgibbs u_int scbid; 786897883Sgibbs u_int tcl; 786997883Sgibbs 7870102679Sgibbs tcl = BUILD_TCL_RAW(i, 'A', j); 787197883Sgibbs scbid = ahd_find_busy_tcl(ahd, tcl); 787297883Sgibbs scbp = ahd_lookup_scb(ahd, scbid); 787397883Sgibbs if (scbp == NULL 787497883Sgibbs || ahd_match_scb(ahd, scbp, target, channel, 787597883Sgibbs lun, tag, role) == 0) 787697883Sgibbs continue; 787797883Sgibbs ahd_unbusy_tcl(ahd, BUILD_TCL_RAW(i, 'A', j)); 787897883Sgibbs } 787997883Sgibbs } 788097883Sgibbs } 788197883Sgibbs 788297883Sgibbs /* 7883109588Sgibbs * Don't abort commands that have already completed, 7884109588Sgibbs * but haven't quite made it up to the host yet. 7885109588Sgibbs */ 7886109588Sgibbs ahd_flush_qoutfifo(ahd); 7887109588Sgibbs 7888109588Sgibbs /* 788997883Sgibbs * Go through the pending CCB list and look for 789097883Sgibbs * commands for this target that are still active. 789197883Sgibbs * These are other tagged commands that were 789297883Sgibbs * disconnected when the reset occurred. 789397883Sgibbs */ 789497883Sgibbs scbp_next = LIST_FIRST(&ahd->pending_scbs); 789597883Sgibbs while (scbp_next != NULL) { 789697883Sgibbs scbp = scbp_next; 789797883Sgibbs scbp_next = LIST_NEXT(scbp, pending_links); 789897883Sgibbs if (ahd_match_scb(ahd, scbp, target, channel, lun, tag, role)) { 789997883Sgibbs cam_status ostat; 790097883Sgibbs 7901123579Sgibbs ostat = aic_get_transaction_status(scbp); 790297883Sgibbs if (ostat == CAM_REQ_INPROG) 7903123579Sgibbs aic_set_transaction_status(scbp, status); 7904123579Sgibbs if (aic_get_transaction_status(scbp) != CAM_REQ_CMP) 7905123579Sgibbs aic_freeze_scb(scbp); 790697883Sgibbs if ((scbp->flags & SCB_ACTIVE) == 0) 790797883Sgibbs printf("Inactive SCB on pending list\n"); 790897883Sgibbs ahd_done(ahd, scbp); 790997883Sgibbs found++; 791097883Sgibbs } 791197883Sgibbs } 7912104023Sgibbs ahd_restore_modes(ahd, saved_modes); 791397883Sgibbs ahd_platform_abort_scbs(ahd, target, channel, lun, tag, role, status); 7914109588Sgibbs ahd->flags |= AHD_UPDATE_PEND_CMDS; 791597883Sgibbs return found; 791697883Sgibbs} 791797883Sgibbs 791897883Sgibbsstatic void 791997883Sgibbsahd_reset_current_bus(struct ahd_softc *ahd) 792097883Sgibbs{ 792197883Sgibbs uint8_t scsiseq; 792297883Sgibbs 792397883Sgibbs AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 792497883Sgibbs ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) & ~ENSCSIRST); 7925102679Sgibbs scsiseq = ahd_inb(ahd, SCSISEQ0) & ~(ENSELO|ENARBO|SCSIRSTO); 792697883Sgibbs ahd_outb(ahd, SCSISEQ0, scsiseq | SCSIRSTO); 7927116935Sgibbs ahd_flush_device_writes(ahd); 7928123579Sgibbs aic_delay(AHD_BUSRESET_DELAY); 792997883Sgibbs /* Turn off the bus reset */ 7930102679Sgibbs ahd_outb(ahd, SCSISEQ0, scsiseq); 7931116935Sgibbs ahd_flush_device_writes(ahd); 7932123579Sgibbs aic_delay(AHD_BUSRESET_DELAY); 793397883Sgibbs if ((ahd->bugs & AHD_SCSIRST_BUG) != 0) { 793497883Sgibbs /* 793597883Sgibbs * 2A Razor #474 793697883Sgibbs * Certain chip state is not cleared for 793797883Sgibbs * SCSI bus resets that we initiate, so 793897883Sgibbs * we must reset the chip. 793997883Sgibbs */ 7940115917Sgibbs ahd_reset(ahd, /*reinit*/TRUE); 794197883Sgibbs ahd_intr_enable(ahd, /*enable*/TRUE); 794297883Sgibbs AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 794397883Sgibbs } 794497883Sgibbs 794597883Sgibbs ahd_clear_intstat(ahd); 794697883Sgibbs} 794797883Sgibbs 794897883Sgibbsint 794997883Sgibbsahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) 795097883Sgibbs{ 795197883Sgibbs struct ahd_devinfo devinfo; 7952102679Sgibbs u_int initiator; 795397883Sgibbs u_int target; 795497883Sgibbs u_int max_scsiid; 795597883Sgibbs int found; 7956102679Sgibbs u_int fifo; 7957102679Sgibbs u_int next_fifo; 795897883Sgibbs 795997883Sgibbs ahd->pending_device = NULL; 796097883Sgibbs 796197883Sgibbs ahd_compile_devinfo(&devinfo, 796297883Sgibbs CAM_TARGET_WILDCARD, 796397883Sgibbs CAM_TARGET_WILDCARD, 796497883Sgibbs CAM_LUN_WILDCARD, 796597883Sgibbs channel, ROLE_UNKNOWN); 796697883Sgibbs ahd_pause(ahd); 796797883Sgibbs 796897883Sgibbs /* Make sure the sequencer is in a safe location. */ 796997883Sgibbs ahd_clear_critical_section(ahd); 797097883Sgibbs 7971153072Sru#ifdef AHD_TARGET_MODE 797297883Sgibbs if ((ahd->flags & AHD_TARGETROLE) != 0) { 797397883Sgibbs ahd_run_tqinfifo(ahd, /*paused*/TRUE); 797497883Sgibbs } 797597883Sgibbs#endif 797697883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 797797883Sgibbs 797897883Sgibbs /* 7979102679Sgibbs * Disable selections so no automatic hardware 7980102679Sgibbs * functions will modify chip state. 7981102679Sgibbs */ 7982102679Sgibbs ahd_outb(ahd, SCSISEQ0, 0); 7983102679Sgibbs ahd_outb(ahd, SCSISEQ1, 0); 7984102679Sgibbs 7985102679Sgibbs /* 7986102679Sgibbs * Safely shut down our DMA engines. Always start with 7987102679Sgibbs * the FIFO that is not currently active (if any are 7988102679Sgibbs * actively connected). 7989102679Sgibbs */ 7990102679Sgibbs next_fifo = fifo = ahd_inb(ahd, DFFSTAT) & CURRFIFO; 7991107441Sscottl if (next_fifo > CURRFIFO_1) 7992107441Sscottl /* If disconneced, arbitrarily start with FIFO1. */ 7993107441Sscottl next_fifo = fifo = 0; 7994102679Sgibbs do { 7995107441Sscottl next_fifo ^= CURRFIFO_1; 7996102679Sgibbs ahd_set_modes(ahd, next_fifo, next_fifo); 7997104023Sgibbs ahd_outb(ahd, DFCNTRL, 7998104023Sgibbs ahd_inb(ahd, DFCNTRL) & ~(SCSIEN|HDMAEN)); 7999102679Sgibbs while ((ahd_inb(ahd, DFCNTRL) & HDMAENACK) != 0) 8000123579Sgibbs aic_delay(10); 8001102679Sgibbs /* 8002102679Sgibbs * Set CURRFIFO to the now inactive channel. 8003102679Sgibbs */ 8004102679Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 8005102679Sgibbs ahd_outb(ahd, DFFSTAT, next_fifo); 8006102679Sgibbs } while (next_fifo != fifo); 8007114623Sgibbs 8008102679Sgibbs /* 800997883Sgibbs * Reset the bus if we are initiating this reset 801097883Sgibbs */ 801197883Sgibbs ahd_clear_msg_state(ahd); 8012104023Sgibbs ahd_outb(ahd, SIMODE1, 8013123579Sgibbs ahd_inb(ahd, SIMODE1) & ~(ENBUSFREE|ENSCSIRST)); 8014114623Sgibbs 801597883Sgibbs if (initiate_reset) 801697883Sgibbs ahd_reset_current_bus(ahd); 8017114623Sgibbs 801897883Sgibbs ahd_clear_intstat(ahd); 801997883Sgibbs 802097883Sgibbs /* 802197883Sgibbs * Clean up all the state information for the 802297883Sgibbs * pending transactions on this bus. 802397883Sgibbs */ 802497883Sgibbs found = ahd_abort_scbs(ahd, CAM_TARGET_WILDCARD, channel, 802597883Sgibbs CAM_LUN_WILDCARD, SCB_LIST_NULL, 802697883Sgibbs ROLE_UNKNOWN, CAM_SCSI_BUS_RESET); 802797883Sgibbs 8028102679Sgibbs /* 8029102679Sgibbs * Cleanup anything left in the FIFOs. 8030102679Sgibbs */ 8031102679Sgibbs ahd_clear_fifo(ahd, 0); 8032102679Sgibbs ahd_clear_fifo(ahd, 1); 8033102679Sgibbs 8034102679Sgibbs /* 8035102679Sgibbs * Revert to async/narrow transfers until we renegotiate. 8036102679Sgibbs */ 8037102679Sgibbs max_scsiid = (ahd->features & AHD_WIDE) ? 15 : 7; 8038102679Sgibbs for (target = 0; target <= max_scsiid; target++) { 8039102679Sgibbs 8040102679Sgibbs if (ahd->enabled_targets[target] == NULL) 8041102679Sgibbs continue; 8042102679Sgibbs for (initiator = 0; initiator <= max_scsiid; initiator++) { 8043102679Sgibbs struct ahd_devinfo devinfo; 8044102679Sgibbs 8045102679Sgibbs ahd_compile_devinfo(&devinfo, target, initiator, 8046102679Sgibbs CAM_LUN_WILDCARD, 8047102679Sgibbs 'A', ROLE_UNKNOWN); 8048102679Sgibbs ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, 8049102679Sgibbs AHD_TRANS_CUR, /*paused*/TRUE); 8050102679Sgibbs ahd_set_syncrate(ahd, &devinfo, /*period*/0, 8051102679Sgibbs /*offset*/0, /*ppr_options*/0, 8052102679Sgibbs AHD_TRANS_CUR, /*paused*/TRUE); 8053102679Sgibbs } 8054102679Sgibbs } 8055102679Sgibbs 805697883Sgibbs#ifdef AHD_TARGET_MODE 805797883Sgibbs max_scsiid = (ahd->features & AHD_WIDE) ? 15 : 7; 805897883Sgibbs 805997883Sgibbs /* 806097883Sgibbs * Send an immediate notify ccb to all target more peripheral 806197883Sgibbs * drivers affected by this action. 806297883Sgibbs */ 806397883Sgibbs for (target = 0; target <= max_scsiid; target++) { 806497883Sgibbs struct ahd_tmode_tstate* tstate; 806597883Sgibbs u_int lun; 806697883Sgibbs 806797883Sgibbs tstate = ahd->enabled_targets[target]; 806897883Sgibbs if (tstate == NULL) 806997883Sgibbs continue; 807097883Sgibbs for (lun = 0; lun < AHD_NUM_LUNS; lun++) { 807197883Sgibbs struct ahd_tmode_lstate* lstate; 807297883Sgibbs 807397883Sgibbs lstate = tstate->enabled_luns[lun]; 807497883Sgibbs if (lstate == NULL) 807597883Sgibbs continue; 807697883Sgibbs 807797883Sgibbs ahd_queue_lstate_event(ahd, lstate, CAM_TARGET_WILDCARD, 807897883Sgibbs EVENT_TYPE_BUS_RESET, /*arg*/0); 807997883Sgibbs ahd_send_lstate_events(ahd, lstate); 808097883Sgibbs } 808197883Sgibbs } 808297883Sgibbs#endif 808397883Sgibbs /* Notify the XPT that a bus reset occurred */ 808497883Sgibbs ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD, 808597883Sgibbs CAM_LUN_WILDCARD, AC_BUS_RESET, NULL); 8086104023Sgibbs ahd_restart(ahd); 808797883Sgibbs /* 808897883Sgibbs * Freeze the SIMQ until our poller can determine that 808997883Sgibbs * the bus reset has really gone away. We set the initial 809097883Sgibbs * timer to 0 to have the check performed as soon as possible 809197883Sgibbs * from the timer context. 809297883Sgibbs */ 8093102679Sgibbs if ((ahd->flags & AHD_RESET_POLL_ACTIVE) == 0) { 8094102679Sgibbs ahd->flags |= AHD_RESET_POLL_ACTIVE; 8095123579Sgibbs aic_freeze_simq(ahd); 8096123579Sgibbs aic_timer_reset(&ahd->reset_timer, 0, ahd_reset_poll, ahd); 8097102679Sgibbs } 809897883Sgibbs return (found); 809997883Sgibbs} 810097883Sgibbs 810197883Sgibbs 8102137870Sgibbs#define AHD_RESET_POLL_MS 1 810397883Sgibbsstatic void 810497883Sgibbsahd_reset_poll(void *arg) 810597883Sgibbs{ 8106168807Sscottl struct ahd_softc *ahd = (struct ahd_softc *)arg; 810797883Sgibbs u_int scsiseq1; 810897883Sgibbs 8109168807Sscottl ahd_lock(ahd); 8110102679Sgibbs ahd_pause(ahd); 8111104023Sgibbs ahd_update_modes(ahd); 8112104023Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 8113102679Sgibbs ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI); 8114102679Sgibbs if ((ahd_inb(ahd, SSTAT1) & SCSIRSTI) != 0) { 8115137870Sgibbs aic_timer_reset(&ahd->reset_timer, AHD_RESET_POLL_MS, 811697883Sgibbs ahd_reset_poll, ahd); 8117102679Sgibbs ahd_unpause(ahd); 8118168807Sscottl ahd_unlock(ahd); 8119102679Sgibbs return; 812097883Sgibbs } 812197883Sgibbs 812297883Sgibbs /* Reset is now low. Complete chip reinitialization. */ 812397883Sgibbs ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) | ENSCSIRST); 812497883Sgibbs scsiseq1 = ahd_inb(ahd, SCSISEQ_TEMPLATE); 812597883Sgibbs ahd_outb(ahd, SCSISEQ1, scsiseq1 & (ENSELI|ENRSELI|ENAUTOATNP)); 8126102679Sgibbs ahd_unpause(ahd); 8127102679Sgibbs ahd->flags &= ~AHD_RESET_POLL_ACTIVE; 8128123579Sgibbs aic_release_simq(ahd); 8129168807Sscottl ahd_unlock(ahd); 813097883Sgibbs} 813197883Sgibbs 8132109588Sgibbs/**************************** Statistics Processing ***************************/ 8133109588Sgibbsstatic void 8134109588Sgibbsahd_stat_timer(void *arg) 8135109588Sgibbs{ 8136168807Sscottl struct ahd_softc *ahd = (struct ahd_softc *)arg; 8137109588Sgibbs int enint_coal; 8138109588Sgibbs 8139168807Sscottl ahd_lock(ahd); 8140115329Sgibbs enint_coal = ahd->hs_mailbox & ENINT_COALESCE; 8141115329Sgibbs if (ahd->cmdcmplt_total > ahd->int_coalescing_threshold) 8142115329Sgibbs enint_coal |= ENINT_COALESCE; 8143115329Sgibbs else if (ahd->cmdcmplt_total < ahd->int_coalescing_stop_threshold) 8144115329Sgibbs enint_coal &= ~ENINT_COALESCE; 8145109588Sgibbs 8146115329Sgibbs if (enint_coal != (ahd->hs_mailbox & ENINT_COALESCE)) { 8147115329Sgibbs ahd_enable_coalescing(ahd, enint_coal); 8148109588Sgibbs#ifdef AHD_DEBUG 8149115329Sgibbs if ((ahd_debug & AHD_SHOW_INT_COALESCING) != 0) 8150115329Sgibbs printf("%s: Interrupt coalescing " 8151109588Sgibbs "now %sabled. Cmds %d\n", 8152109588Sgibbs ahd_name(ahd), 8153115329Sgibbs (enint_coal & ENINT_COALESCE) ? "en" : "dis", 8154109588Sgibbs ahd->cmdcmplt_total); 8155109588Sgibbs#endif 8156109588Sgibbs } 8157109588Sgibbs 8158109588Sgibbs ahd->cmdcmplt_bucket = (ahd->cmdcmplt_bucket+1) & (AHD_STAT_BUCKETS-1); 8159109588Sgibbs ahd->cmdcmplt_total -= ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]; 8160109588Sgibbs ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket] = 0; 8161137870Sgibbs aic_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_MS, 8162109588Sgibbs ahd_stat_timer, ahd); 8163168807Sscottl ahd_unlock(ahd); 8164109588Sgibbs} 8165109588Sgibbs 816697883Sgibbs/****************************** Status Processing *****************************/ 816797883Sgibbsvoid 816897883Sgibbsahd_handle_scb_status(struct ahd_softc *ahd, struct scb *scb) 816997883Sgibbs{ 817097883Sgibbs if (scb->hscb->shared_data.istatus.scsi_status != 0) { 817197883Sgibbs ahd_handle_scsi_status(ahd, scb); 817297883Sgibbs } else { 817397883Sgibbs ahd_calc_residual(ahd, scb); 817497883Sgibbs ahd_done(ahd, scb); 817597883Sgibbs } 817697883Sgibbs} 817797883Sgibbs 817897883Sgibbsvoid 817997883Sgibbsahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) 818097883Sgibbs{ 8181123579Sgibbs struct hardware_scb *hscb; 8182123579Sgibbs int paused; 818397883Sgibbs 818497883Sgibbs /* 818597883Sgibbs * The sequencer freezes its select-out queue 818697883Sgibbs * anytime a SCSI status error occurs. We must 8187125448Sgibbs * handle the error and increment our qfreeze count 8188125448Sgibbs * to allow the sequencer to continue. We don't 8189125448Sgibbs * bother clearing critical sections here since all 8190125448Sgibbs * operations are on data structures that the sequencer 8191125448Sgibbs * is not touching once the queue is frozen. 819297883Sgibbs */ 819397883Sgibbs hscb = scb->hscb; 819497883Sgibbs 8195123579Sgibbs if (ahd_is_paused(ahd)) { 8196123579Sgibbs paused = 1; 8197123579Sgibbs } else { 8198123579Sgibbs paused = 0; 8199123579Sgibbs ahd_pause(ahd); 8200123579Sgibbs } 8201123579Sgibbs 820297883Sgibbs /* Freeze the queue until the client sees the error. */ 820397883Sgibbs ahd_freeze_devq(ahd, scb); 8204123579Sgibbs aic_freeze_scb(scb); 8205125448Sgibbs ahd->qfreeze_cnt++; 8206125448Sgibbs ahd_outw(ahd, KERNEL_QFREEZE_COUNT, ahd->qfreeze_cnt); 8207114623Sgibbs 8208123579Sgibbs if (paused == 0) 8209123579Sgibbs ahd_unpause(ahd); 8210123579Sgibbs 8211102679Sgibbs /* Don't want to clobber the original sense code */ 8212102679Sgibbs if ((scb->flags & SCB_SENSE) != 0) { 8213102679Sgibbs /* 8214102679Sgibbs * Clear the SCB_SENSE Flag and perform 8215102679Sgibbs * a normal command completion. 8216102679Sgibbs */ 8217102679Sgibbs scb->flags &= ~SCB_SENSE; 8218123579Sgibbs aic_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); 8219102679Sgibbs ahd_done(ahd, scb); 8220102679Sgibbs return; 8221102679Sgibbs } 8222123579Sgibbs aic_set_transaction_status(scb, CAM_SCSI_STATUS_ERROR); 8223123579Sgibbs aic_set_scsi_status(scb, hscb->shared_data.istatus.scsi_status); 822497883Sgibbs switch (hscb->shared_data.istatus.scsi_status) { 822597883Sgibbs case STATUS_PKT_SENSE: 822697883Sgibbs { 822797883Sgibbs struct scsi_status_iu_header *siu; 822897883Sgibbs 822997883Sgibbs ahd_sync_sense(ahd, scb, BUS_DMASYNC_POSTREAD); 823097883Sgibbs siu = (struct scsi_status_iu_header *)scb->sense_data; 8231123579Sgibbs aic_set_scsi_status(scb, siu->status); 823297883Sgibbs#ifdef AHD_DEBUG 8233107441Sscottl if ((ahd_debug & AHD_SHOW_SENSE) != 0) { 823497883Sgibbs ahd_print_path(ahd, scb); 823597883Sgibbs printf("SCB 0x%x Received PKT Status of 0x%x\n", 823697883Sgibbs SCB_GET_TAG(scb), siu->status); 823797883Sgibbs printf("\tflags = 0x%x, sense len = 0x%x, " 823897883Sgibbs "pktfail = 0x%x\n", 823997883Sgibbs siu->flags, scsi_4btoul(siu->sense_length), 824097883Sgibbs scsi_4btoul(siu->pkt_failures_length)); 8241107441Sscottl } 824297883Sgibbs#endif 824397883Sgibbs if ((siu->flags & SIU_RSPVALID) != 0) { 824497883Sgibbs ahd_print_path(ahd, scb); 824597883Sgibbs if (scsi_4btoul(siu->pkt_failures_length) < 4) { 824697883Sgibbs printf("Unable to parse pkt_failures\n"); 824797883Sgibbs } else { 824897883Sgibbs 824997883Sgibbs switch (SIU_PKTFAIL_CODE(siu)) { 825097883Sgibbs case SIU_PFC_NONE: 825197883Sgibbs printf("No packet failure found\n"); 8252199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 825397883Sgibbs break; 825497883Sgibbs case SIU_PFC_CIU_FIELDS_INVALID: 825597883Sgibbs printf("Invalid Command IU Field\n"); 8256199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 825797883Sgibbs break; 825897883Sgibbs case SIU_PFC_TMF_NOT_SUPPORTED: 825997883Sgibbs printf("TMF not supportd\n"); 8260199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 826197883Sgibbs break; 826297883Sgibbs case SIU_PFC_TMF_FAILED: 826397883Sgibbs printf("TMF failed\n"); 8264199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 826597883Sgibbs break; 826697883Sgibbs case SIU_PFC_INVALID_TYPE_CODE: 826797883Sgibbs printf("Invalid L_Q Type code\n"); 8268199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 826997883Sgibbs break; 827097883Sgibbs case SIU_PFC_ILLEGAL_REQUEST: 8271199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 827297883Sgibbs printf("Illegal request\n"); 827397883Sgibbs default: 827497883Sgibbs break; 827597883Sgibbs } 827697883Sgibbs } 827797883Sgibbs if (siu->status == SCSI_STATUS_OK) 8278123579Sgibbs aic_set_transaction_status(scb, 827997883Sgibbs CAM_REQ_CMP_ERR); 828097883Sgibbs } 828197883Sgibbs if ((siu->flags & SIU_SNSVALID) != 0) { 828297883Sgibbs scb->flags |= SCB_PKT_SENSE; 828397883Sgibbs#ifdef AHD_DEBUG 828497883Sgibbs if ((ahd_debug & AHD_SHOW_SENSE) != 0) 828597883Sgibbs printf("Sense data available\n"); 828697883Sgibbs#endif 828797883Sgibbs } 828897883Sgibbs ahd_done(ahd, scb); 828997883Sgibbs break; 829097883Sgibbs } 829197883Sgibbs case SCSI_STATUS_CMD_TERMINATED: 829297883Sgibbs case SCSI_STATUS_CHECK_COND: 829397883Sgibbs { 829497883Sgibbs struct ahd_devinfo devinfo; 829597883Sgibbs struct ahd_dma_seg *sg; 829697883Sgibbs struct scsi_sense *sc; 829797883Sgibbs struct ahd_initiator_tinfo *targ_info; 829897883Sgibbs struct ahd_tmode_tstate *tstate; 829997883Sgibbs struct ahd_transinfo *tinfo; 830097883Sgibbs#ifdef AHD_DEBUG 830197883Sgibbs if (ahd_debug & AHD_SHOW_SENSE) { 830297883Sgibbs ahd_print_path(ahd, scb); 830397883Sgibbs printf("SCB %d: requests Check Status\n", 830497883Sgibbs SCB_GET_TAG(scb)); 830597883Sgibbs } 830697883Sgibbs#endif 830797883Sgibbs 8308123579Sgibbs if (aic_perform_autosense(scb) == 0) 830997883Sgibbs break; 831097883Sgibbs 831197883Sgibbs ahd_compile_devinfo(&devinfo, SCB_GET_OUR_ID(scb), 831297883Sgibbs SCB_GET_TARGET(ahd, scb), 831397883Sgibbs SCB_GET_LUN(scb), 831497883Sgibbs SCB_GET_CHANNEL(ahd, scb), 831597883Sgibbs ROLE_INITIATOR); 831697883Sgibbs targ_info = ahd_fetch_transinfo(ahd, 831797883Sgibbs devinfo.channel, 831897883Sgibbs devinfo.our_scsiid, 831997883Sgibbs devinfo.target, 832097883Sgibbs &tstate); 832197883Sgibbs tinfo = &targ_info->curr; 832297883Sgibbs sg = scb->sg_list; 832397883Sgibbs sc = (struct scsi_sense *)hscb->shared_data.idata.cdb; 832497883Sgibbs /* 832597883Sgibbs * Save off the residual if there is one. 832697883Sgibbs */ 832797883Sgibbs ahd_update_residual(ahd, scb); 832897883Sgibbs#ifdef AHD_DEBUG 832997883Sgibbs if (ahd_debug & AHD_SHOW_SENSE) { 833097883Sgibbs ahd_print_path(ahd, scb); 833197883Sgibbs printf("Sending Sense\n"); 833297883Sgibbs } 833397883Sgibbs#endif 833497883Sgibbs scb->sg_count = 0; 833597883Sgibbs sg = ahd_sg_setup(ahd, scb, sg, ahd_get_sense_bufaddr(ahd, scb), 8336123579Sgibbs aic_get_sense_bufsize(ahd, scb), 833797883Sgibbs /*last*/TRUE); 833897883Sgibbs sc->opcode = REQUEST_SENSE; 833997883Sgibbs sc->byte2 = 0; 834097883Sgibbs if (tinfo->protocol_version <= SCSI_REV_2 834197883Sgibbs && SCB_GET_LUN(scb) < 8) 834297883Sgibbs sc->byte2 = SCB_GET_LUN(scb) << 5; 834397883Sgibbs sc->unused[0] = 0; 834497883Sgibbs sc->unused[1] = 0; 8345123579Sgibbs sc->length = aic_get_sense_bufsize(ahd, scb); 834697883Sgibbs sc->control = 0; 834797883Sgibbs 834897883Sgibbs /* 834997883Sgibbs * We can't allow the target to disconnect. 835097883Sgibbs * This will be an untagged transaction and 835197883Sgibbs * having the target disconnect will make this 835297883Sgibbs * transaction indestinguishable from outstanding 835397883Sgibbs * tagged transactions. 835497883Sgibbs */ 835597883Sgibbs hscb->control = 0; 835697883Sgibbs 835797883Sgibbs /* 835897883Sgibbs * This request sense could be because the 835997883Sgibbs * the device lost power or in some other 836097883Sgibbs * way has lost our transfer negotiations. 836197883Sgibbs * Renegotiate if appropriate. Unit attention 836297883Sgibbs * errors will be reported before any data 836397883Sgibbs * phases occur. 836497883Sgibbs */ 8365123579Sgibbs if (aic_get_residual(scb) == aic_get_transfer_length(scb)) { 836697883Sgibbs ahd_update_neg_request(ahd, &devinfo, 836797883Sgibbs tstate, targ_info, 8368107441Sscottl AHD_NEG_IF_NON_ASYNC); 836997883Sgibbs } 837097883Sgibbs if (tstate->auto_negotiate & devinfo.target_mask) { 837197883Sgibbs hscb->control |= MK_MESSAGE; 837297883Sgibbs scb->flags &= 837397883Sgibbs ~(SCB_NEGOTIATE|SCB_ABORT|SCB_DEVICE_RESET); 837497883Sgibbs scb->flags |= SCB_AUTO_NEGOTIATE; 837597883Sgibbs } 837697883Sgibbs hscb->cdb_len = sizeof(*sc); 837797883Sgibbs ahd_setup_data_scb(ahd, scb); 837897883Sgibbs scb->flags |= SCB_SENSE; 837997883Sgibbs ahd_queue_scb(ahd, scb); 838097883Sgibbs /* 838197883Sgibbs * Ensure we have enough time to actually 8382133911Sgibbs * retrieve the sense, but only schedule 8383133911Sgibbs * the timer if we are not in recovery or 8384133911Sgibbs * this is a recovery SCB that is allowed 8385133911Sgibbs * to have an active timer. 838697883Sgibbs */ 8387133911Sgibbs if (ahd->scb_data.recovery_scbs == 0 8388133911Sgibbs || (scb->flags & SCB_RECOVERY_SCB) != 0) 8389137870Sgibbs aic_scb_timer_reset(scb, 5 * 1000); 839097883Sgibbs break; 839197883Sgibbs } 839297883Sgibbs case SCSI_STATUS_OK: 839397883Sgibbs printf("%s: Interrupted for staus of 0???\n", 839497883Sgibbs ahd_name(ahd)); 839597883Sgibbs /* FALLTHROUGH */ 839697883Sgibbs default: 839797883Sgibbs ahd_done(ahd, scb); 839897883Sgibbs break; 839997883Sgibbs } 840097883Sgibbs} 840197883Sgibbs 840297883Sgibbs/* 840397883Sgibbs * Calculate the residual for a just completed SCB. 840497883Sgibbs */ 840597883Sgibbsvoid 840697883Sgibbsahd_calc_residual(struct ahd_softc *ahd, struct scb *scb) 840797883Sgibbs{ 840897883Sgibbs struct hardware_scb *hscb; 840997883Sgibbs struct initiator_status *spkt; 841097883Sgibbs uint32_t sgptr; 841197883Sgibbs uint32_t resid_sgptr; 841297883Sgibbs uint32_t resid; 841397883Sgibbs 841497883Sgibbs /* 841597883Sgibbs * 5 cases. 841697883Sgibbs * 1) No residual. 841797883Sgibbs * SG_STATUS_VALID clear in sgptr. 841897883Sgibbs * 2) Transferless command 841997883Sgibbs * 3) Never performed any transfers. 842097883Sgibbs * sgptr has SG_FULL_RESID set. 842197883Sgibbs * 4) No residual but target did not 842297883Sgibbs * save data pointers after the 842397883Sgibbs * last transfer, so sgptr was 842497883Sgibbs * never updated. 842597883Sgibbs * 5) We have a partial residual. 842697883Sgibbs * Use residual_sgptr to determine 842797883Sgibbs * where we are. 842897883Sgibbs */ 842997883Sgibbs 843097883Sgibbs hscb = scb->hscb; 8431123579Sgibbs sgptr = aic_le32toh(hscb->sgptr); 843297883Sgibbs if ((sgptr & SG_STATUS_VALID) == 0) 843397883Sgibbs /* Case 1 */ 843497883Sgibbs return; 843597883Sgibbs sgptr &= ~SG_STATUS_VALID; 843697883Sgibbs 843797883Sgibbs if ((sgptr & SG_LIST_NULL) != 0) 843897883Sgibbs /* Case 2 */ 843997883Sgibbs return; 844097883Sgibbs 844197883Sgibbs /* 844297883Sgibbs * Residual fields are the same in both 844397883Sgibbs * target and initiator status packets, 844497883Sgibbs * so we can always use the initiator fields 844597883Sgibbs * regardless of the role for this SCB. 844697883Sgibbs */ 844797883Sgibbs spkt = &hscb->shared_data.istatus; 8448123579Sgibbs resid_sgptr = aic_le32toh(spkt->residual_sgptr); 844997883Sgibbs if ((sgptr & SG_FULL_RESID) != 0) { 845097883Sgibbs /* Case 3 */ 8451123579Sgibbs resid = aic_get_transfer_length(scb); 845297883Sgibbs } else if ((resid_sgptr & SG_LIST_NULL) != 0) { 845397883Sgibbs /* Case 4 */ 845497883Sgibbs return; 845597883Sgibbs } else if ((resid_sgptr & SG_OVERRUN_RESID) != 0) { 845697883Sgibbs ahd_print_path(ahd, scb); 845797883Sgibbs printf("data overrun detected Tag == 0x%x.\n", 845897883Sgibbs SCB_GET_TAG(scb)); 845997883Sgibbs ahd_freeze_devq(ahd, scb); 8460123579Sgibbs aic_set_transaction_status(scb, CAM_DATA_RUN_ERR); 8461123579Sgibbs aic_freeze_scb(scb); 846297883Sgibbs return; 846397883Sgibbs } else if ((resid_sgptr & ~SG_PTR_MASK) != 0) { 846497883Sgibbs panic("Bogus resid sgptr value 0x%x\n", resid_sgptr); 846597883Sgibbs /* NOTREACHED */ 846697883Sgibbs } else { 846797883Sgibbs struct ahd_dma_seg *sg; 846897883Sgibbs 846997883Sgibbs /* 847097883Sgibbs * Remainder of the SG where the transfer 847197883Sgibbs * stopped. 847297883Sgibbs */ 8473123579Sgibbs resid = aic_le32toh(spkt->residual_datacnt) & AHD_SG_LEN_MASK; 847497883Sgibbs sg = ahd_sg_bus_to_virt(ahd, scb, resid_sgptr & SG_PTR_MASK); 847597883Sgibbs 847697883Sgibbs /* The residual sg_ptr always points to the next sg */ 847797883Sgibbs sg--; 847897883Sgibbs 847997883Sgibbs /* 848097883Sgibbs * Add up the contents of all residual 848197883Sgibbs * SG segments that are after the SG where 848297883Sgibbs * the transfer stopped. 848397883Sgibbs */ 8484123579Sgibbs while ((aic_le32toh(sg->len) & AHD_DMA_LAST_SEG) == 0) { 848597883Sgibbs sg++; 8486123579Sgibbs resid += aic_le32toh(sg->len) & AHD_SG_LEN_MASK; 848797883Sgibbs } 848897883Sgibbs } 848997883Sgibbs if ((scb->flags & SCB_SENSE) == 0) 8490123579Sgibbs aic_set_residual(scb, resid); 849197883Sgibbs else 8492123579Sgibbs aic_set_sense_residual(scb, resid); 849397883Sgibbs 849497883Sgibbs#ifdef AHD_DEBUG 849597883Sgibbs if ((ahd_debug & AHD_SHOW_MISC) != 0) { 849697883Sgibbs ahd_print_path(ahd, scb); 8497109588Sgibbs printf("Handled %sResidual of %d bytes\n", 8498109588Sgibbs (scb->flags & SCB_SENSE) ? "Sense " : "", resid); 849997883Sgibbs } 850097883Sgibbs#endif 850197883Sgibbs} 850297883Sgibbs 850397883Sgibbs/******************************* Target Mode **********************************/ 850497883Sgibbs#ifdef AHD_TARGET_MODE 850597883Sgibbs/* 850697883Sgibbs * Add a target mode event to this lun's queue 850797883Sgibbs */ 850897883Sgibbsstatic void 850997883Sgibbsahd_queue_lstate_event(struct ahd_softc *ahd, struct ahd_tmode_lstate *lstate, 851097883Sgibbs u_int initiator_id, u_int event_type, u_int event_arg) 851197883Sgibbs{ 851297883Sgibbs struct ahd_tmode_event *event; 851397883Sgibbs int pending; 851497883Sgibbs 851597883Sgibbs xpt_freeze_devq(lstate->path, /*count*/1); 851697883Sgibbs if (lstate->event_w_idx >= lstate->event_r_idx) 851797883Sgibbs pending = lstate->event_w_idx - lstate->event_r_idx; 851897883Sgibbs else 851997883Sgibbs pending = AHD_TMODE_EVENT_BUFFER_SIZE + 1 852097883Sgibbs - (lstate->event_r_idx - lstate->event_w_idx); 852197883Sgibbs 852297883Sgibbs if (event_type == EVENT_TYPE_BUS_RESET 852397883Sgibbs || event_type == MSG_BUS_DEV_RESET) { 852497883Sgibbs /* 852597883Sgibbs * Any earlier events are irrelevant, so reset our buffer. 852697883Sgibbs * This has the effect of allowing us to deal with reset 852797883Sgibbs * floods (an external device holding down the reset line) 852897883Sgibbs * without losing the event that is really interesting. 852997883Sgibbs */ 853097883Sgibbs lstate->event_r_idx = 0; 853197883Sgibbs lstate->event_w_idx = 0; 853297883Sgibbs xpt_release_devq(lstate->path, pending, /*runqueue*/FALSE); 853397883Sgibbs } 853497883Sgibbs 853597883Sgibbs if (pending == AHD_TMODE_EVENT_BUFFER_SIZE) { 853697883Sgibbs xpt_print_path(lstate->path); 853797883Sgibbs printf("immediate event %x:%x lost\n", 853897883Sgibbs lstate->event_buffer[lstate->event_r_idx].event_type, 853997883Sgibbs lstate->event_buffer[lstate->event_r_idx].event_arg); 854097883Sgibbs lstate->event_r_idx++; 854197883Sgibbs if (lstate->event_r_idx == AHD_TMODE_EVENT_BUFFER_SIZE) 854297883Sgibbs lstate->event_r_idx = 0; 854397883Sgibbs xpt_release_devq(lstate->path, /*count*/1, /*runqueue*/FALSE); 854497883Sgibbs } 854597883Sgibbs 854697883Sgibbs event = &lstate->event_buffer[lstate->event_w_idx]; 854797883Sgibbs event->initiator_id = initiator_id; 854897883Sgibbs event->event_type = event_type; 854997883Sgibbs event->event_arg = event_arg; 855097883Sgibbs lstate->event_w_idx++; 855197883Sgibbs if (lstate->event_w_idx == AHD_TMODE_EVENT_BUFFER_SIZE) 855297883Sgibbs lstate->event_w_idx = 0; 855397883Sgibbs} 855497883Sgibbs 855597883Sgibbs/* 855697883Sgibbs * Send any target mode events queued up waiting 855797883Sgibbs * for immediate notify resources. 855897883Sgibbs */ 855997883Sgibbsvoid 856097883Sgibbsahd_send_lstate_events(struct ahd_softc *ahd, struct ahd_tmode_lstate *lstate) 856197883Sgibbs{ 856297883Sgibbs struct ccb_hdr *ccbh; 8563237825Sken struct ccb_immediate_notify *inot; 856497883Sgibbs 856597883Sgibbs while (lstate->event_r_idx != lstate->event_w_idx 856697883Sgibbs && (ccbh = SLIST_FIRST(&lstate->immed_notifies)) != NULL) { 856797883Sgibbs struct ahd_tmode_event *event; 856897883Sgibbs 856997883Sgibbs event = &lstate->event_buffer[lstate->event_r_idx]; 857097883Sgibbs SLIST_REMOVE_HEAD(&lstate->immed_notifies, sim_links.sle); 8571237825Sken inot = (struct ccb_immediate_notify *)ccbh; 857297883Sgibbs switch (event->event_type) { 857397883Sgibbs case EVENT_TYPE_BUS_RESET: 857497883Sgibbs ccbh->status = CAM_SCSI_BUS_RESET|CAM_DEV_QFRZN; 857597883Sgibbs break; 857697883Sgibbs default: 857797883Sgibbs ccbh->status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN; 8578237825Sken inot->arg = event->event_type; 8579237825Sken inot->seq_id = event->event_arg; 858097883Sgibbs break; 858197883Sgibbs } 858297883Sgibbs inot->initiator_id = event->initiator_id; 858397883Sgibbs xpt_done((union ccb *)inot); 858497883Sgibbs lstate->event_r_idx++; 858597883Sgibbs if (lstate->event_r_idx == AHD_TMODE_EVENT_BUFFER_SIZE) 858697883Sgibbs lstate->event_r_idx = 0; 858797883Sgibbs } 858897883Sgibbs} 858997883Sgibbs#endif 859097883Sgibbs 859197883Sgibbs/******************** Sequencer Program Patching/Download *********************/ 859297883Sgibbs 859397883Sgibbs#ifdef AHD_DUMP_SEQ 859497883Sgibbsvoid 859597883Sgibbsahd_dumpseq(struct ahd_softc* ahd) 859697883Sgibbs{ 859797883Sgibbs int i; 859897883Sgibbs int max_prog; 859997883Sgibbs 860097883Sgibbs max_prog = 2048; 860197883Sgibbs 860297883Sgibbs ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); 8603123579Sgibbs ahd_outw(ahd, PRGMCNT, 0); 860497883Sgibbs for (i = 0; i < max_prog; i++) { 860597883Sgibbs uint8_t ins_bytes[4]; 860697883Sgibbs 860797883Sgibbs ahd_insb(ahd, SEQRAM, ins_bytes, 4); 860897883Sgibbs printf("0x%08x\n", ins_bytes[0] << 24 860997883Sgibbs | ins_bytes[1] << 16 861097883Sgibbs | ins_bytes[2] << 8 861197883Sgibbs | ins_bytes[3]); 861297883Sgibbs } 861397883Sgibbs} 861497883Sgibbs#endif 861597883Sgibbs 861697883Sgibbsstatic void 861797883Sgibbsahd_loadseq(struct ahd_softc *ahd) 861897883Sgibbs{ 861997883Sgibbs struct cs cs_table[num_critical_sections]; 862097883Sgibbs u_int begin_set[num_critical_sections]; 862197883Sgibbs u_int end_set[num_critical_sections]; 862297883Sgibbs struct patch *cur_patch; 862397883Sgibbs u_int cs_count; 862497883Sgibbs u_int cur_cs; 862597883Sgibbs u_int i; 862697883Sgibbs int downloaded; 862797883Sgibbs u_int skip_addr; 862897883Sgibbs u_int sg_prefetch_cnt; 862997883Sgibbs u_int sg_prefetch_cnt_limit; 863097883Sgibbs u_int sg_prefetch_align; 863197883Sgibbs u_int sg_size; 8632129134Sgibbs u_int cacheline_mask; 863397883Sgibbs uint8_t download_consts[DOWNLOAD_CONST_COUNT]; 863497883Sgibbs 863597883Sgibbs if (bootverbose) 863697883Sgibbs printf("%s: Downloading Sequencer Program...", 863797883Sgibbs ahd_name(ahd)); 863897883Sgibbs 8639129134Sgibbs#if DOWNLOAD_CONST_COUNT != 8 864097883Sgibbs#error "Download Const Mismatch" 864197883Sgibbs#endif 864297883Sgibbs /* 864397883Sgibbs * Start out with 0 critical sections 864497883Sgibbs * that apply to this firmware load. 864597883Sgibbs */ 864697883Sgibbs cs_count = 0; 864797883Sgibbs cur_cs = 0; 864897883Sgibbs memset(begin_set, 0, sizeof(begin_set)); 864997883Sgibbs memset(end_set, 0, sizeof(end_set)); 865097883Sgibbs 865197883Sgibbs /* 865297883Sgibbs * Setup downloadable constant table. 865397883Sgibbs * 865497883Sgibbs * The computation for the S/G prefetch variables is 865597883Sgibbs * a bit complicated. We would like to always fetch 865697883Sgibbs * in terms of cachelined sized increments. However, 865797883Sgibbs * if the cacheline is not an even multiple of the 865897883Sgibbs * SG element size or is larger than our SG RAM, using 865997883Sgibbs * just the cache size might leave us with only a portion 866097883Sgibbs * of an SG element at the tail of a prefetch. If the 866197883Sgibbs * cacheline is larger than our S/G prefetch buffer less 866297883Sgibbs * the size of an SG element, we may round down to a cacheline 866397883Sgibbs * that doesn't contain any or all of the S/G of interest 866497883Sgibbs * within the bounds of our S/G ram. Provide variables to 866597883Sgibbs * the sequencer that will allow it to handle these edge 866697883Sgibbs * cases. 866797883Sgibbs */ 866897883Sgibbs /* Start by aligning to the nearest cacheline. */ 866997883Sgibbs sg_prefetch_align = ahd->pci_cachesize; 867097883Sgibbs if (sg_prefetch_align == 0) 8671111653Sgibbs sg_prefetch_align = 8; 867297883Sgibbs /* Round down to the nearest power of 2. */ 867397883Sgibbs while (powerof2(sg_prefetch_align) == 0) 867497883Sgibbs sg_prefetch_align--; 8675129134Sgibbs 8676129134Sgibbs cacheline_mask = sg_prefetch_align - 1; 8677129134Sgibbs 867897883Sgibbs /* 867997883Sgibbs * If the cacheline boundary is greater than half our prefetch RAM 868097883Sgibbs * we risk not being able to fetch even a single complete S/G 868197883Sgibbs * segment if we align to that boundary. 868297883Sgibbs */ 868397883Sgibbs if (sg_prefetch_align > CCSGADDR_MAX/2) 868497883Sgibbs sg_prefetch_align = CCSGADDR_MAX/2; 868597883Sgibbs /* Start by fetching a single cacheline. */ 868697883Sgibbs sg_prefetch_cnt = sg_prefetch_align; 868797883Sgibbs /* 868897883Sgibbs * Increment the prefetch count by cachelines until 868997883Sgibbs * at least one S/G element will fit. 869097883Sgibbs */ 869197883Sgibbs sg_size = sizeof(struct ahd_dma_seg); 869297883Sgibbs if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) 869397883Sgibbs sg_size = sizeof(struct ahd_dma64_seg); 869497883Sgibbs while (sg_prefetch_cnt < sg_size) 869597883Sgibbs sg_prefetch_cnt += sg_prefetch_align; 869697883Sgibbs /* 869797883Sgibbs * If the cacheline is not an even multiple of 869897883Sgibbs * the S/G size, we may only get a partial S/G when 869997883Sgibbs * we align. Add a cacheline if this is the case. 870097883Sgibbs */ 870197883Sgibbs if ((sg_prefetch_align % sg_size) != 0 870297883Sgibbs && (sg_prefetch_cnt < CCSGADDR_MAX)) 870397883Sgibbs sg_prefetch_cnt += sg_prefetch_align; 870497883Sgibbs /* 870597883Sgibbs * Lastly, compute a value that the sequencer can use 870697883Sgibbs * to determine if the remainder of the CCSGRAM buffer 870797883Sgibbs * has a full S/G element in it. 870897883Sgibbs */ 870997883Sgibbs sg_prefetch_cnt_limit = -(sg_prefetch_cnt - sg_size + 1); 871097883Sgibbs download_consts[SG_PREFETCH_CNT] = sg_prefetch_cnt; 871197883Sgibbs download_consts[SG_PREFETCH_CNT_LIMIT] = sg_prefetch_cnt_limit; 871297883Sgibbs download_consts[SG_PREFETCH_ALIGN_MASK] = ~(sg_prefetch_align - 1); 871397883Sgibbs download_consts[SG_PREFETCH_ADDR_MASK] = (sg_prefetch_align - 1); 871497883Sgibbs download_consts[SG_SIZEOF] = sg_size; 871597883Sgibbs download_consts[PKT_OVERRUN_BUFOFFSET] = 8716102679Sgibbs (ahd->overrun_buf - (uint8_t *)ahd->qoutfifo) / 256; 8717102679Sgibbs download_consts[SCB_TRANSFER_SIZE] = SCB_TRANSFER_SIZE_1BYTE_LUN; 8718129134Sgibbs download_consts[CACHELINE_MASK] = cacheline_mask; 871997883Sgibbs cur_patch = patches; 872097883Sgibbs downloaded = 0; 872197883Sgibbs skip_addr = 0; 872297883Sgibbs ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); 8723123579Sgibbs ahd_outw(ahd, PRGMCNT, 0); 872497883Sgibbs 872597883Sgibbs for (i = 0; i < sizeof(seqprog)/4; i++) { 872697883Sgibbs if (ahd_check_patch(ahd, &cur_patch, i, &skip_addr) == 0) { 872797883Sgibbs /* 872897883Sgibbs * Don't download this instruction as it 872997883Sgibbs * is in a patch that was removed. 873097883Sgibbs */ 873197883Sgibbs continue; 873297883Sgibbs } 873397883Sgibbs /* 873497883Sgibbs * Move through the CS table until we find a CS 873597883Sgibbs * that might apply to this instruction. 873697883Sgibbs */ 873797883Sgibbs for (; cur_cs < num_critical_sections; cur_cs++) { 873897883Sgibbs if (critical_sections[cur_cs].end <= i) { 873997883Sgibbs if (begin_set[cs_count] == TRUE 874097883Sgibbs && end_set[cs_count] == FALSE) { 874197883Sgibbs cs_table[cs_count].end = downloaded; 874297883Sgibbs end_set[cs_count] = TRUE; 874397883Sgibbs cs_count++; 874497883Sgibbs } 874597883Sgibbs continue; 874697883Sgibbs } 874797883Sgibbs if (critical_sections[cur_cs].begin <= i 874897883Sgibbs && begin_set[cs_count] == FALSE) { 874997883Sgibbs cs_table[cs_count].begin = downloaded; 875097883Sgibbs begin_set[cs_count] = TRUE; 875197883Sgibbs } 875297883Sgibbs break; 875397883Sgibbs } 875497883Sgibbs ahd_download_instr(ahd, i, download_consts); 875597883Sgibbs downloaded++; 875697883Sgibbs } 875797883Sgibbs 875897883Sgibbs ahd->num_critical_sections = cs_count; 875997883Sgibbs if (cs_count != 0) { 876097883Sgibbs 876197883Sgibbs cs_count *= sizeof(struct cs); 876297883Sgibbs ahd->critical_sections = malloc(cs_count, M_DEVBUF, M_NOWAIT); 876397883Sgibbs if (ahd->critical_sections == NULL) 876497883Sgibbs panic("ahd_loadseq: Could not malloc"); 876597883Sgibbs memcpy(ahd->critical_sections, cs_table, cs_count); 876697883Sgibbs } 876797883Sgibbs ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE); 876897883Sgibbs 8769109588Sgibbs if (bootverbose) { 877097883Sgibbs printf(" %d instructions downloaded\n", downloaded); 8771109588Sgibbs printf("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n", 8772109588Sgibbs ahd_name(ahd), ahd->features, ahd->bugs, ahd->flags); 8773109588Sgibbs } 877497883Sgibbs} 877597883Sgibbs 877697883Sgibbsstatic int 877797883Sgibbsahd_check_patch(struct ahd_softc *ahd, struct patch **start_patch, 877897883Sgibbs u_int start_instr, u_int *skip_addr) 877997883Sgibbs{ 878097883Sgibbs struct patch *cur_patch; 878197883Sgibbs struct patch *last_patch; 878297883Sgibbs u_int num_patches; 878397883Sgibbs 878497883Sgibbs num_patches = sizeof(patches)/sizeof(struct patch); 878597883Sgibbs last_patch = &patches[num_patches]; 878697883Sgibbs cur_patch = *start_patch; 878797883Sgibbs 878897883Sgibbs while (cur_patch < last_patch && start_instr == cur_patch->begin) { 878997883Sgibbs 879097883Sgibbs if (cur_patch->patch_func(ahd) == 0) { 879197883Sgibbs 879297883Sgibbs /* Start rejecting code */ 879397883Sgibbs *skip_addr = start_instr + cur_patch->skip_instr; 879497883Sgibbs cur_patch += cur_patch->skip_patch; 879597883Sgibbs } else { 879697883Sgibbs /* Accepted this patch. Advance to the next 879797883Sgibbs * one and wait for our intruction pointer to 879897883Sgibbs * hit this point. 879997883Sgibbs */ 880097883Sgibbs cur_patch++; 880197883Sgibbs } 880297883Sgibbs } 880397883Sgibbs 880497883Sgibbs *start_patch = cur_patch; 880597883Sgibbs if (start_instr < *skip_addr) 880697883Sgibbs /* Still skipping */ 880797883Sgibbs return (0); 880897883Sgibbs 880997883Sgibbs return (1); 881097883Sgibbs} 881197883Sgibbs 881297883Sgibbsstatic u_int 881397883Sgibbsahd_resolve_seqaddr(struct ahd_softc *ahd, u_int address) 881497883Sgibbs{ 881597883Sgibbs struct patch *cur_patch; 881697883Sgibbs int address_offset; 881797883Sgibbs u_int skip_addr; 881897883Sgibbs u_int i; 881997883Sgibbs 882097883Sgibbs address_offset = 0; 882197883Sgibbs cur_patch = patches; 882297883Sgibbs skip_addr = 0; 882397883Sgibbs 882497883Sgibbs for (i = 0; i < address;) { 882597883Sgibbs 882697883Sgibbs ahd_check_patch(ahd, &cur_patch, i, &skip_addr); 882797883Sgibbs 882897883Sgibbs if (skip_addr > i) { 882997883Sgibbs int end_addr; 883097883Sgibbs 883197883Sgibbs end_addr = MIN(address, skip_addr); 883297883Sgibbs address_offset += end_addr - i; 883397883Sgibbs i = skip_addr; 883497883Sgibbs } else { 883597883Sgibbs i++; 883697883Sgibbs } 883797883Sgibbs } 883897883Sgibbs return (address - address_offset); 883997883Sgibbs} 884097883Sgibbs 884197883Sgibbsstatic void 884297883Sgibbsahd_download_instr(struct ahd_softc *ahd, u_int instrptr, uint8_t *dconsts) 884397883Sgibbs{ 884497883Sgibbs union ins_formats instr; 884597883Sgibbs struct ins_format1 *fmt1_ins; 884697883Sgibbs struct ins_format3 *fmt3_ins; 884797883Sgibbs u_int opcode; 884897883Sgibbs 884997883Sgibbs /* 885097883Sgibbs * The firmware is always compiled into a little endian format. 885197883Sgibbs */ 8852123579Sgibbs instr.integer = aic_le32toh(*(uint32_t*)&seqprog[instrptr * 4]); 885397883Sgibbs 885497883Sgibbs fmt1_ins = &instr.format1; 885597883Sgibbs fmt3_ins = NULL; 885697883Sgibbs 885797883Sgibbs /* Pull the opcode */ 885897883Sgibbs opcode = instr.format1.opcode; 885997883Sgibbs switch (opcode) { 886097883Sgibbs case AIC_OP_JMP: 886197883Sgibbs case AIC_OP_JC: 886297883Sgibbs case AIC_OP_JNC: 886397883Sgibbs case AIC_OP_CALL: 886497883Sgibbs case AIC_OP_JNE: 886597883Sgibbs case AIC_OP_JNZ: 886697883Sgibbs case AIC_OP_JE: 886797883Sgibbs case AIC_OP_JZ: 886897883Sgibbs { 886997883Sgibbs fmt3_ins = &instr.format3; 887097883Sgibbs fmt3_ins->address = ahd_resolve_seqaddr(ahd, fmt3_ins->address); 887197883Sgibbs /* FALLTHROUGH */ 887297883Sgibbs } 887397883Sgibbs case AIC_OP_OR: 887497883Sgibbs case AIC_OP_AND: 887597883Sgibbs case AIC_OP_XOR: 887697883Sgibbs case AIC_OP_ADD: 887797883Sgibbs case AIC_OP_ADC: 887897883Sgibbs case AIC_OP_BMOV: 887997883Sgibbs if (fmt1_ins->parity != 0) { 888097883Sgibbs fmt1_ins->immediate = dconsts[fmt1_ins->immediate]; 888197883Sgibbs } 888297883Sgibbs fmt1_ins->parity = 0; 888397883Sgibbs /* FALLTHROUGH */ 888497883Sgibbs case AIC_OP_ROL: 888597883Sgibbs { 888697883Sgibbs int i, count; 888797883Sgibbs 888897883Sgibbs /* Calculate odd parity for the instruction */ 888997883Sgibbs for (i = 0, count = 0; i < 31; i++) { 889097883Sgibbs uint32_t mask; 889197883Sgibbs 889297883Sgibbs mask = 0x01 << i; 889397883Sgibbs if ((instr.integer & mask) != 0) 889497883Sgibbs count++; 889597883Sgibbs } 889697883Sgibbs if ((count & 0x01) == 0) 889797883Sgibbs instr.format1.parity = 1; 889897883Sgibbs 889997883Sgibbs /* The sequencer is a little endian cpu */ 8900123579Sgibbs instr.integer = aic_htole32(instr.integer); 890197883Sgibbs ahd_outsb(ahd, SEQRAM, instr.bytes, 4); 890297883Sgibbs break; 890397883Sgibbs } 890497883Sgibbs default: 890597883Sgibbs panic("Unknown opcode encountered in seq program"); 890697883Sgibbs break; 890797883Sgibbs } 890897883Sgibbs} 890997883Sgibbs 8910107441Sscottlstatic int 8911107441Sscottlahd_probe_stack_size(struct ahd_softc *ahd) 8912107441Sscottl{ 8913107441Sscottl int last_probe; 8914107441Sscottl 8915107441Sscottl last_probe = 0; 8916107441Sscottl while (1) { 8917107441Sscottl int i; 8918107441Sscottl 8919107441Sscottl /* 8920107441Sscottl * We avoid using 0 as a pattern to avoid 8921107441Sscottl * confusion if the stack implementation 8922107441Sscottl * "back-fills" with zeros when "poping' 8923107441Sscottl * entries. 8924107441Sscottl */ 8925107441Sscottl for (i = 1; i <= last_probe+1; i++) { 8926107441Sscottl ahd_outb(ahd, STACK, i & 0xFF); 8927107441Sscottl ahd_outb(ahd, STACK, (i >> 8) & 0xFF); 8928107441Sscottl } 8929107441Sscottl 8930107441Sscottl /* Verify */ 8931107441Sscottl for (i = last_probe+1; i > 0; i--) { 8932107441Sscottl u_int stack_entry; 8933107441Sscottl 8934107441Sscottl stack_entry = ahd_inb(ahd, STACK) 8935107441Sscottl |(ahd_inb(ahd, STACK) << 8); 8936107441Sscottl if (stack_entry != i) 8937107441Sscottl goto sized; 8938107441Sscottl } 8939107441Sscottl last_probe++; 8940107441Sscottl } 8941107441Sscottlsized: 8942107441Sscottl return (last_probe); 8943107441Sscottl} 8944107441Sscottl 894597883Sgibbsvoid 8946115336Sgibbsahd_dump_all_cards_state(void) 894797883Sgibbs{ 894897883Sgibbs struct ahd_softc *list_ahd; 894997883Sgibbs 895097883Sgibbs TAILQ_FOREACH(list_ahd, &ahd_tailq, links) { 895197883Sgibbs ahd_dump_card_state(list_ahd); 895297883Sgibbs } 895397883Sgibbs} 895497883Sgibbs 8955102679Sgibbsint 8956102679Sgibbsahd_print_register(ahd_reg_parse_entry_t *table, u_int num_entries, 8957102679Sgibbs const char *name, u_int address, u_int value, 8958102679Sgibbs u_int *cur_column, u_int wrap_point) 8959102679Sgibbs{ 8960102679Sgibbs int printed; 8961102679Sgibbs u_int printed_mask; 8962141999Sgibbs u_int dummy_column; 8963102679Sgibbs 8964141999Sgibbs if (cur_column == NULL) { 8965141999Sgibbs dummy_column = 0; 8966141999Sgibbs cur_column = &dummy_column; 8967141999Sgibbs } 8968141999Sgibbs 8969107441Sscottl if (cur_column != NULL && *cur_column >= wrap_point) { 8970102679Sgibbs printf("\n"); 8971102679Sgibbs *cur_column = 0; 8972102679Sgibbs } 8973102679Sgibbs printed = printf("%s[0x%x]", name, value); 8974102679Sgibbs if (table == NULL) { 8975102679Sgibbs printed += printf(" "); 8976102679Sgibbs *cur_column += printed; 8977102679Sgibbs return (printed); 8978102679Sgibbs } 8979102679Sgibbs printed_mask = 0; 8980102679Sgibbs while (printed_mask != 0xFF) { 8981102679Sgibbs int entry; 8982102679Sgibbs 8983102679Sgibbs for (entry = 0; entry < num_entries; entry++) { 8984102679Sgibbs if (((value & table[entry].mask) 8985102679Sgibbs != table[entry].value) 8986102679Sgibbs || ((printed_mask & table[entry].mask) 8987102679Sgibbs == table[entry].mask)) 8988102679Sgibbs continue; 8989102679Sgibbs 8990102679Sgibbs printed += printf("%s%s", 8991102679Sgibbs printed_mask == 0 ? ":(" : "|", 8992102679Sgibbs table[entry].name); 8993102679Sgibbs printed_mask |= table[entry].mask; 8994102679Sgibbs 8995102679Sgibbs break; 8996102679Sgibbs } 8997102679Sgibbs if (entry >= num_entries) 8998102679Sgibbs break; 8999102679Sgibbs } 9000102679Sgibbs if (printed_mask != 0) 9001102679Sgibbs printed += printf(") "); 9002102679Sgibbs else 9003102679Sgibbs printed += printf(" "); 9004141999Sgibbs *cur_column += printed; 9005102679Sgibbs return (printed); 9006102679Sgibbs} 9007102679Sgibbs 900897883Sgibbsvoid 900997883Sgibbsahd_dump_card_state(struct ahd_softc *ahd) 901097883Sgibbs{ 901197883Sgibbs struct scb *scb; 901297883Sgibbs ahd_mode_state saved_modes; 901397883Sgibbs u_int dffstat; 901497883Sgibbs int paused; 901597883Sgibbs u_int scb_index; 9016104023Sgibbs u_int saved_scb_index; 9017102679Sgibbs u_int cur_col; 9018107441Sscottl int i; 901997883Sgibbs 902097883Sgibbs if (ahd_is_paused(ahd)) { 902197883Sgibbs paused = 1; 902297883Sgibbs } else { 902397883Sgibbs paused = 0; 902497883Sgibbs ahd_pause(ahd); 902597883Sgibbs } 902697883Sgibbs saved_modes = ahd_save_modes(ahd); 902797883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 9028102679Sgibbs printf(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n" 9029102679Sgibbs "%s: Dumping Card State at program address 0x%x Mode 0x%x\n", 903097883Sgibbs ahd_name(ahd), 9031123579Sgibbs ahd_inw(ahd, CURADDR), 903297883Sgibbs ahd_build_mode_state(ahd, ahd->saved_src_mode, 903397883Sgibbs ahd->saved_dst_mode)); 903497883Sgibbs if (paused) 903597883Sgibbs printf("Card was paused\n"); 9036116938Sgibbs 9037116938Sgibbs if (ahd_check_cmdcmpltqueues(ahd)) 9038116938Sgibbs printf("Completions are pending\n"); 9039116938Sgibbs 9040102679Sgibbs /* 9041102679Sgibbs * Mode independent registers. 9042102679Sgibbs */ 9043102679Sgibbs cur_col = 0; 9044133122Sgibbs ahd_intstat_print(ahd_inb(ahd, INTSTAT), &cur_col, 50); 9045133122Sgibbs ahd_seloid_print(ahd_inb(ahd, SELOID), &cur_col, 50); 9046133122Sgibbs ahd_selid_print(ahd_inb(ahd, SELID), &cur_col, 50); 9047109588Sgibbs ahd_hs_mailbox_print(ahd_inb(ahd, LOCAL_HS_MAILBOX), &cur_col, 50); 9048109588Sgibbs ahd_intctl_print(ahd_inb(ahd, INTCTL), &cur_col, 50); 9049109588Sgibbs ahd_seqintstat_print(ahd_inb(ahd, SEQINTSTAT), &cur_col, 50); 9050107441Sscottl ahd_saved_mode_print(ahd_inb(ahd, SAVED_MODE), &cur_col, 50); 9051107441Sscottl ahd_dffstat_print(ahd_inb(ahd, DFFSTAT), &cur_col, 50); 9052102679Sgibbs ahd_scsisigi_print(ahd_inb(ahd, SCSISIGI), &cur_col, 50); 9053102679Sgibbs ahd_scsiphase_print(ahd_inb(ahd, SCSIPHASE), &cur_col, 50); 9054104023Sgibbs ahd_scsibus_print(ahd_inb(ahd, SCSIBUS), &cur_col, 50); 9055102679Sgibbs ahd_lastphase_print(ahd_inb(ahd, LASTPHASE), &cur_col, 50); 9056107441Sscottl ahd_scsiseq0_print(ahd_inb(ahd, SCSISEQ0), &cur_col, 50); 9057107441Sscottl ahd_scsiseq1_print(ahd_inb(ahd, SCSISEQ1), &cur_col, 50); 9058107441Sscottl ahd_seqctl0_print(ahd_inb(ahd, SEQCTL0), &cur_col, 50); 9059107441Sscottl ahd_seqintctl_print(ahd_inb(ahd, SEQINTCTL), &cur_col, 50); 9060102679Sgibbs ahd_seq_flags_print(ahd_inb(ahd, SEQ_FLAGS), &cur_col, 50); 9061102679Sgibbs ahd_seq_flags2_print(ahd_inb(ahd, SEQ_FLAGS2), &cur_col, 50); 9062133122Sgibbs ahd_qfreeze_count_print(ahd_inw(ahd, QFREEZE_COUNT), &cur_col, 50); 9063133122Sgibbs ahd_kernel_qfreeze_count_print(ahd_inw(ahd, KERNEL_QFREEZE_COUNT), 9064133122Sgibbs &cur_col, 50); 9065133122Sgibbs ahd_mk_message_scb_print(ahd_inw(ahd, MK_MESSAGE_SCB), &cur_col, 50); 9066133122Sgibbs ahd_mk_message_scsiid_print(ahd_inb(ahd, MK_MESSAGE_SCSIID), 9067133122Sgibbs &cur_col, 50); 9068102679Sgibbs ahd_sstat0_print(ahd_inb(ahd, SSTAT0), &cur_col, 50); 9069102679Sgibbs ahd_sstat1_print(ahd_inb(ahd, SSTAT1), &cur_col, 50); 9070102679Sgibbs ahd_sstat2_print(ahd_inb(ahd, SSTAT2), &cur_col, 50); 9071102679Sgibbs ahd_sstat3_print(ahd_inb(ahd, SSTAT3), &cur_col, 50); 9072102679Sgibbs ahd_perrdiag_print(ahd_inb(ahd, PERRDIAG), &cur_col, 50); 9073104023Sgibbs ahd_simode1_print(ahd_inb(ahd, SIMODE1), &cur_col, 50); 9074104023Sgibbs ahd_lqistat0_print(ahd_inb(ahd, LQISTAT0), &cur_col, 50); 9075104023Sgibbs ahd_lqistat1_print(ahd_inb(ahd, LQISTAT1), &cur_col, 50); 9076104023Sgibbs ahd_lqistat2_print(ahd_inb(ahd, LQISTAT2), &cur_col, 50); 9077104023Sgibbs ahd_lqostat0_print(ahd_inb(ahd, LQOSTAT0), &cur_col, 50); 9078104023Sgibbs ahd_lqostat1_print(ahd_inb(ahd, LQOSTAT1), &cur_col, 50); 9079104023Sgibbs ahd_lqostat2_print(ahd_inb(ahd, LQOSTAT2), &cur_col, 50); 9080104023Sgibbs printf("\n"); 9081109588Sgibbs printf("\nSCB Count = %d CMDS_PENDING = %d LASTSCB 0x%x " 9082109588Sgibbs "CURRSCB 0x%x NEXTSCB 0x%x\n", 9083109588Sgibbs ahd->scb_data.numscbs, ahd_inw(ahd, CMDS_PENDING), 9084109588Sgibbs ahd_inw(ahd, LASTSCB), ahd_inw(ahd, CURRSCB), 9085109588Sgibbs ahd_inw(ahd, NEXTSCB)); 9086102679Sgibbs cur_col = 0; 908797883Sgibbs /* QINFIFO */ 908897883Sgibbs ahd_search_qinfifo(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS, 908997883Sgibbs CAM_LUN_WILDCARD, SCB_LIST_NULL, 909097883Sgibbs ROLE_UNKNOWN, /*status*/0, SEARCH_PRINT); 9091104023Sgibbs saved_scb_index = ahd_get_scbptr(ahd); 9092102679Sgibbs printf("Pending list:"); 909397883Sgibbs i = 0; 909497883Sgibbs LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) { 909597883Sgibbs if (i++ > AHD_SCB_MAX) 909697883Sgibbs break; 9097114623Sgibbs cur_col = printf("\n%3d FIFO_USE[0x%x] ", SCB_GET_TAG(scb), 9098116940Sgibbs ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT)); 909997883Sgibbs ahd_set_scbptr(ahd, SCB_GET_TAG(scb)); 9100116940Sgibbs ahd_scb_control_print(ahd_inb_scbram(ahd, SCB_CONTROL), 9101116940Sgibbs &cur_col, 60); 9102116940Sgibbs ahd_scb_scsiid_print(ahd_inb_scbram(ahd, SCB_SCSIID), 9103116940Sgibbs &cur_col, 60); 910497883Sgibbs } 9105109588Sgibbs printf("\nTotal %d\n", i); 910697883Sgibbs 9107150451Sgibbs printf("Kernel Free SCB lists: "); 910897883Sgibbs i = 0; 9109102679Sgibbs TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) { 9110102679Sgibbs struct scb *list_scb; 9111102679Sgibbs 9112150451Sgibbs printf("\n COLIDX[%d]: ", AHD_GET_SCB_COL_IDX(ahd, scb)); 9113102679Sgibbs list_scb = scb; 9114102679Sgibbs do { 9115102679Sgibbs printf("%d ", SCB_GET_TAG(list_scb)); 9116102679Sgibbs list_scb = LIST_NEXT(list_scb, collision_links); 9117102679Sgibbs } while (list_scb && i++ < AHD_SCB_MAX); 9118102679Sgibbs } 9119102679Sgibbs 9120150451Sgibbs printf("\n Any Device: "); 9121102679Sgibbs LIST_FOREACH(scb, &ahd->scb_data.any_dev_free_scb_list, links.le) { 912297883Sgibbs if (i++ > AHD_SCB_MAX) 912397883Sgibbs break; 912497883Sgibbs printf("%d ", SCB_GET_TAG(scb)); 912597883Sgibbs } 912697883Sgibbs printf("\n"); 912797883Sgibbs 912897883Sgibbs printf("Sequencer Complete DMA-inprog list: "); 912997883Sgibbs scb_index = ahd_inw(ahd, COMPLETE_SCB_DMAINPROG_HEAD); 913097883Sgibbs i = 0; 913197883Sgibbs while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { 913297883Sgibbs ahd_set_scbptr(ahd, scb_index); 913397883Sgibbs printf("%d ", scb_index); 9134116940Sgibbs scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); 913597883Sgibbs } 913697883Sgibbs printf("\n"); 913797883Sgibbs 913897883Sgibbs printf("Sequencer Complete list: "); 913997883Sgibbs scb_index = ahd_inw(ahd, COMPLETE_SCB_HEAD); 914097883Sgibbs i = 0; 914197883Sgibbs while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { 914297883Sgibbs ahd_set_scbptr(ahd, scb_index); 914397883Sgibbs printf("%d ", scb_index); 9144116940Sgibbs scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); 914597883Sgibbs } 914697883Sgibbs printf("\n"); 914797883Sgibbs 914897883Sgibbs 914997883Sgibbs printf("Sequencer DMA-Up and Complete list: "); 915097883Sgibbs scb_index = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD); 915197883Sgibbs i = 0; 915297883Sgibbs while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { 915397883Sgibbs ahd_set_scbptr(ahd, scb_index); 915497883Sgibbs printf("%d ", scb_index); 9155116940Sgibbs scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); 915697883Sgibbs } 915797883Sgibbs printf("\n"); 9158125448Sgibbs printf("Sequencer On QFreeze and Complete list: "); 9159125448Sgibbs scb_index = ahd_inw(ahd, COMPLETE_ON_QFREEZE_HEAD); 9160125448Sgibbs i = 0; 9161125448Sgibbs while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { 9162125448Sgibbs ahd_set_scbptr(ahd, scb_index); 9163125448Sgibbs printf("%d ", scb_index); 9164125448Sgibbs scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); 9165125448Sgibbs } 9166125448Sgibbs printf("\n"); 9167104023Sgibbs ahd_set_scbptr(ahd, saved_scb_index); 916897883Sgibbs dffstat = ahd_inb(ahd, DFFSTAT); 916997883Sgibbs for (i = 0; i < 2; i++) { 9170102679Sgibbs#ifdef AHD_DEBUG 917197883Sgibbs struct scb *fifo_scb; 9172102679Sgibbs#endif 917397883Sgibbs u_int fifo_scbptr; 917497883Sgibbs 917597883Sgibbs ahd_set_modes(ahd, AHD_MODE_DFF0 + i, AHD_MODE_DFF0 + i); 9176104023Sgibbs fifo_scbptr = ahd_get_scbptr(ahd); 9177133122Sgibbs printf("\n\n%s: FIFO%d %s, LONGJMP == 0x%x, SCB 0x%x\n", 917897883Sgibbs ahd_name(ahd), i, 917997883Sgibbs (dffstat & (FIFO0FREE << i)) ? "Free" : "Active", 9180114623Sgibbs ahd_inw(ahd, LONGJMP_ADDR), fifo_scbptr); 9181102679Sgibbs cur_col = 0; 9182102679Sgibbs ahd_seqimode_print(ahd_inb(ahd, SEQIMODE), &cur_col, 50); 9183102679Sgibbs ahd_seqintsrc_print(ahd_inb(ahd, SEQINTSRC), &cur_col, 50); 9184102679Sgibbs ahd_dfcntrl_print(ahd_inb(ahd, DFCNTRL), &cur_col, 50); 9185102679Sgibbs ahd_dfstatus_print(ahd_inb(ahd, DFSTATUS), &cur_col, 50); 9186102679Sgibbs ahd_sg_cache_shadow_print(ahd_inb(ahd, SG_CACHE_SHADOW), 9187102679Sgibbs &cur_col, 50); 9188102679Sgibbs ahd_sg_state_print(ahd_inb(ahd, SG_STATE), &cur_col, 50); 9189102679Sgibbs ahd_dffsxfrctl_print(ahd_inb(ahd, DFFSXFRCTL), &cur_col, 50); 9190102679Sgibbs ahd_soffcnt_print(ahd_inb(ahd, SOFFCNT), &cur_col, 50); 9191102679Sgibbs ahd_mdffstat_print(ahd_inb(ahd, MDFFSTAT), &cur_col, 50); 9192102679Sgibbs if (cur_col > 50) { 9193102679Sgibbs printf("\n"); 9194102679Sgibbs cur_col = 0; 9195102679Sgibbs } 9196109588Sgibbs cur_col += printf("SHADDR = 0x%x%x, SHCNT = 0x%x ", 9197102679Sgibbs ahd_inl(ahd, SHADDR+4), 9198102679Sgibbs ahd_inl(ahd, SHADDR), 9199102679Sgibbs (ahd_inb(ahd, SHCNT) 9200102679Sgibbs | (ahd_inb(ahd, SHCNT + 1) << 8) 9201102679Sgibbs | (ahd_inb(ahd, SHCNT + 2) << 16))); 9202102679Sgibbs if (cur_col > 50) { 9203102679Sgibbs printf("\n"); 9204102679Sgibbs cur_col = 0; 9205102679Sgibbs } 9206107441Sscottl cur_col += printf("HADDR = 0x%x%x, HCNT = 0x%x ", 9207102679Sgibbs ahd_inl(ahd, HADDR+4), 9208102679Sgibbs ahd_inl(ahd, HADDR), 9209102679Sgibbs (ahd_inb(ahd, HCNT) 9210102679Sgibbs | (ahd_inb(ahd, HCNT + 1) << 8) 9211102679Sgibbs | (ahd_inb(ahd, HCNT + 2) << 16))); 9212102679Sgibbs ahd_ccsgctl_print(ahd_inb(ahd, CCSGCTL), &cur_col, 50); 9213102679Sgibbs#ifdef AHD_DEBUG 9214102679Sgibbs if ((ahd_debug & AHD_SHOW_SG) != 0) { 9215102679Sgibbs fifo_scb = ahd_lookup_scb(ahd, fifo_scbptr); 9216102679Sgibbs if (fifo_scb != NULL) 9217102679Sgibbs ahd_dump_sglist(fifo_scb); 9218102679Sgibbs } 9219102679Sgibbs#endif 922097883Sgibbs } 9221104023Sgibbs printf("\nLQIN: "); 922297883Sgibbs for (i = 0; i < 20; i++) 922397883Sgibbs printf("0x%x ", ahd_inb(ahd, LQIN + i)); 922497883Sgibbs printf("\n"); 922597883Sgibbs ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 922697883Sgibbs printf("%s: LQISTATE = 0x%x, LQOSTATE = 0x%x, OPTIONMODE = 0x%x\n", 922797883Sgibbs ahd_name(ahd), ahd_inb(ahd, LQISTATE), ahd_inb(ahd, LQOSTATE), 922897883Sgibbs ahd_inb(ahd, OPTIONMODE)); 922997883Sgibbs printf("%s: OS_SPACE_CNT = 0x%x MAXCMDCNT = 0x%x\n", 923097883Sgibbs ahd_name(ahd), ahd_inb(ahd, OS_SPACE_CNT), 923197883Sgibbs ahd_inb(ahd, MAXCMDCNT)); 9232133122Sgibbs printf("%s: SAVED_SCSIID = 0x%x SAVED_LUN = 0x%x\n", 9233133122Sgibbs ahd_name(ahd), ahd_inb(ahd, SAVED_SCSIID), 9234133122Sgibbs ahd_inb(ahd, SAVED_LUN)); 9235107441Sscottl ahd_simode0_print(ahd_inb(ahd, SIMODE0), &cur_col, 50); 9236107441Sscottl printf("\n"); 9237109588Sgibbs ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); 9238109588Sgibbs cur_col = 0; 9239109588Sgibbs ahd_ccscbctl_print(ahd_inb(ahd, CCSCBCTL), &cur_col, 50); 9240109588Sgibbs printf("\n"); 924197883Sgibbs ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); 924297883Sgibbs printf("%s: REG0 == 0x%x, SINDEX = 0x%x, DINDEX = 0x%x\n", 924397883Sgibbs ahd_name(ahd), ahd_inw(ahd, REG0), ahd_inw(ahd, SINDEX), 924497883Sgibbs ahd_inw(ahd, DINDEX)); 924597883Sgibbs printf("%s: SCBPTR == 0x%x, SCB_NEXT == 0x%x, SCB_NEXT2 == 0x%x\n", 9246116940Sgibbs ahd_name(ahd), ahd_get_scbptr(ahd), 9247116940Sgibbs ahd_inw_scbram(ahd, SCB_NEXT), 9248116940Sgibbs ahd_inw_scbram(ahd, SCB_NEXT2)); 924997883Sgibbs printf("CDB %x %x %x %x %x %x\n", 9250116940Sgibbs ahd_inb_scbram(ahd, SCB_CDB_STORE), 9251116940Sgibbs ahd_inb_scbram(ahd, SCB_CDB_STORE+1), 9252116940Sgibbs ahd_inb_scbram(ahd, SCB_CDB_STORE+2), 9253116940Sgibbs ahd_inb_scbram(ahd, SCB_CDB_STORE+3), 9254116940Sgibbs ahd_inb_scbram(ahd, SCB_CDB_STORE+4), 9255116940Sgibbs ahd_inb_scbram(ahd, SCB_CDB_STORE+5)); 925697883Sgibbs printf("STACK:"); 9257107441Sscottl for (i = 0; i < ahd->stack_size; i++) { 9258107441Sscottl ahd->saved_stack[i] = 9259107441Sscottl ahd_inb(ahd, STACK)|(ahd_inb(ahd, STACK) << 8); 9260107441Sscottl printf(" 0x%x", ahd->saved_stack[i]); 9261107441Sscottl } 9262107441Sscottl for (i = ahd->stack_size-1; i >= 0; i--) { 9263107441Sscottl ahd_outb(ahd, STACK, ahd->saved_stack[i] & 0xFF); 9264107441Sscottl ahd_outb(ahd, STACK, (ahd->saved_stack[i] >> 8) & 0xFF); 9265107441Sscottl } 9266102679Sgibbs printf("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n"); 926797883Sgibbs ahd_platform_dump_card_state(ahd); 926897883Sgibbs ahd_restore_modes(ahd, saved_modes); 926997883Sgibbs if (paused == 0) 927097883Sgibbs ahd_unpause(ahd); 927197883Sgibbs} 927297883Sgibbs 927397883Sgibbsvoid 927497883Sgibbsahd_dump_scbs(struct ahd_softc *ahd) 927597883Sgibbs{ 927697883Sgibbs ahd_mode_state saved_modes; 9277104023Sgibbs u_int saved_scb_index; 927897883Sgibbs int i; 927997883Sgibbs 928097883Sgibbs saved_modes = ahd_save_modes(ahd); 928197883Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 9282104023Sgibbs saved_scb_index = ahd_get_scbptr(ahd); 928397883Sgibbs for (i = 0; i < AHD_SCB_MAX; i++) { 928497883Sgibbs ahd_set_scbptr(ahd, i); 928597883Sgibbs printf("%3d", i); 928697883Sgibbs printf("(CTRL 0x%x ID 0x%x N 0x%x N2 0x%x SG 0x%x, RSG 0x%x)\n", 9287116940Sgibbs ahd_inb_scbram(ahd, SCB_CONTROL), 9288116940Sgibbs ahd_inb_scbram(ahd, SCB_SCSIID), 9289116940Sgibbs ahd_inw_scbram(ahd, SCB_NEXT), 9290116940Sgibbs ahd_inw_scbram(ahd, SCB_NEXT2), 9291116940Sgibbs ahd_inl_scbram(ahd, SCB_SGPTR), 9292116940Sgibbs ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR)); 929397883Sgibbs } 929497883Sgibbs printf("\n"); 9295104023Sgibbs ahd_set_scbptr(ahd, saved_scb_index); 929697883Sgibbs ahd_restore_modes(ahd, saved_modes); 929797883Sgibbs} 929897883Sgibbs 9299123579Sgibbs 9300123579Sgibbs/*************************** Timeout Handling *********************************/ 9301123579Sgibbsvoid 9302123579Sgibbsahd_timeout(struct scb *scb) 9303123579Sgibbs{ 9304123579Sgibbs struct ahd_softc *ahd; 9305123579Sgibbs 9306123579Sgibbs ahd = scb->ahd_softc; 9307123579Sgibbs if ((scb->flags & SCB_ACTIVE) != 0) { 9308123579Sgibbs if ((scb->flags & SCB_TIMEDOUT) == 0) { 9309123579Sgibbs LIST_INSERT_HEAD(&ahd->timedout_scbs, scb, 9310123579Sgibbs timedout_links); 9311123579Sgibbs scb->flags |= SCB_TIMEDOUT; 9312123579Sgibbs } 9313123579Sgibbs ahd_wakeup_recovery_thread(ahd); 9314123579Sgibbs } 9315123579Sgibbs} 9316123579Sgibbs 9317123579Sgibbs/* 9318123579Sgibbs * ahd_recover_commands determines if any of the commands that have currently 9319123579Sgibbs * timedout are the root cause for this timeout. Innocent commands are given 9320123579Sgibbs * a new timeout while we wait for the command executing on the bus to timeout. 9321123579Sgibbs * This routine is invoked from a thread context so we are allowed to sleep. 9322123579Sgibbs * Our lock is not held on entry. 9323123579Sgibbs */ 9324123579Sgibbsvoid 9325123579Sgibbsahd_recover_commands(struct ahd_softc *ahd) 9326123579Sgibbs{ 9327123579Sgibbs struct scb *scb; 9328123579Sgibbs struct scb *active_scb; 9329123579Sgibbs int found; 9330123579Sgibbs int was_paused; 9331123579Sgibbs u_int active_scbptr; 9332123579Sgibbs u_int last_phase; 9333123579Sgibbs 9334123579Sgibbs /* 9335123579Sgibbs * Pause the controller and manually flush any 9336123579Sgibbs * commands that have just completed but that our 9337123579Sgibbs * interrupt handler has yet to see. 9338123579Sgibbs */ 9339123579Sgibbs was_paused = ahd_is_paused(ahd); 9340133122Sgibbs 9341133122Sgibbs printf("%s: Recovery Initiated - Card was %spaused\n", ahd_name(ahd), 9342133122Sgibbs was_paused ? "" : "not "); 9343199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 9344133122Sgibbs ahd_dump_card_state(ahd); 9345133122Sgibbs 9346123579Sgibbs ahd_pause_and_flushwork(ahd); 9347123579Sgibbs 9348123579Sgibbs if (LIST_EMPTY(&ahd->timedout_scbs) != 0) { 9349123579Sgibbs /* 9350123579Sgibbs * The timedout commands have already 9351123579Sgibbs * completed. This typically means 9352123579Sgibbs * that either the timeout value was on 9353123579Sgibbs * the hairy edge of what the device 9354123579Sgibbs * requires or - more likely - interrupts 9355123579Sgibbs * are not happening. 9356123579Sgibbs */ 9357123579Sgibbs printf("%s: Timedout SCBs already complete. " 9358123579Sgibbs "Interrupts may not be functioning.\n", ahd_name(ahd)); 9359123579Sgibbs ahd_unpause(ahd); 9360123579Sgibbs return; 9361123579Sgibbs } 9362123579Sgibbs 9363123579Sgibbs /* 9364123579Sgibbs * Determine identity of SCB acting on the bus. 9365123579Sgibbs * This test only catches non-packetized transactions. 9366123579Sgibbs * Due to the fleeting nature of packetized operations, 9367123579Sgibbs * we can't easily determine that a packetized operation 9368123579Sgibbs * is on the bus. 9369123579Sgibbs */ 9370123579Sgibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 9371123579Sgibbs last_phase = ahd_inb(ahd, LASTPHASE); 9372123579Sgibbs active_scbptr = ahd_get_scbptr(ahd); 9373123579Sgibbs active_scb = NULL; 9374123579Sgibbs if (last_phase != P_BUSFREE 9375123579Sgibbs || (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) 9376123579Sgibbs active_scb = ahd_lookup_scb(ahd, active_scbptr); 9377123579Sgibbs 9378123579Sgibbs while ((scb = LIST_FIRST(&ahd->timedout_scbs)) != NULL) { 9379123579Sgibbs int target; 9380123579Sgibbs int lun; 9381123579Sgibbs char channel; 9382123579Sgibbs 9383123579Sgibbs target = SCB_GET_TARGET(ahd, scb); 9384123579Sgibbs channel = SCB_GET_CHANNEL(ahd, scb); 9385123579Sgibbs lun = SCB_GET_LUN(scb); 9386123579Sgibbs 9387123579Sgibbs ahd_print_path(ahd, scb); 9388141999Sgibbs printf("SCB %d - timed out\n", SCB_GET_TAG(scb)); 9389123579Sgibbs 9390123579Sgibbs if (scb->flags & (SCB_DEVICE_RESET|SCB_ABORT)) { 9391123579Sgibbs /* 9392123579Sgibbs * Been down this road before. 9393123579Sgibbs * Do a full bus reset. 9394123579Sgibbs */ 9395123579Sgibbs aic_set_transaction_status(scb, CAM_CMD_TIMEOUT); 9396123579Sgibbsbus_reset: 9397123579Sgibbs found = ahd_reset_channel(ahd, channel, 9398123579Sgibbs /*Initiate Reset*/TRUE); 9399123579Sgibbs printf("%s: Issued Channel %c Bus Reset. " 9400123579Sgibbs "%d SCBs aborted\n", ahd_name(ahd), channel, 9401123579Sgibbs found); 9402123579Sgibbs continue; 9403123579Sgibbs } 9404123579Sgibbs 9405123579Sgibbs /* 9406123579Sgibbs * Remove the command from the timedout list in 9407123579Sgibbs * preparation for requeing it. 9408123579Sgibbs */ 9409123579Sgibbs LIST_REMOVE(scb, timedout_links); 9410123579Sgibbs scb->flags &= ~SCB_TIMEDOUT; 9411123579Sgibbs 9412123579Sgibbs if (active_scb != NULL) { 9413123579Sgibbs 9414123579Sgibbs if (active_scb != scb) { 9415129134Sgibbs 9416123579Sgibbs /* 9417123579Sgibbs * If the active SCB is not us, assume that 9418123579Sgibbs * the active SCB has a longer timeout than 9419123579Sgibbs * the timedout SCB, and wait for the active 9420129134Sgibbs * SCB to timeout. As a safeguard, only 9421129134Sgibbs * allow this deferral to continue if some 9422129134Sgibbs * untimed-out command is outstanding. 9423123579Sgibbs */ 9424129134Sgibbs if (ahd_other_scb_timeout(ahd, scb, 9425133966Sgibbs active_scb) == 0) 9426129134Sgibbs goto bus_reset; 9427123579Sgibbs continue; 9428123579Sgibbs } 9429123579Sgibbs 9430123579Sgibbs /* 9431123579Sgibbs * We're active on the bus, so assert ATN 9432123579Sgibbs * and hope that the target responds. 9433123579Sgibbs */ 9434123579Sgibbs ahd_set_recoveryscb(ahd, active_scb); 9435123579Sgibbs active_scb->flags |= SCB_RECOVERY_SCB|SCB_DEVICE_RESET; 9436123579Sgibbs ahd_outb(ahd, MSG_OUT, HOST_MSG); 9437123579Sgibbs ahd_outb(ahd, SCSISIGO, last_phase|ATNO); 9438123579Sgibbs ahd_print_path(ahd, active_scb); 9439123579Sgibbs printf("BDR message in message buffer\n"); 9440137870Sgibbs aic_scb_timer_reset(scb, 2 * 1000); 9441123579Sgibbs break; 9442123579Sgibbs } else if (last_phase != P_BUSFREE 9443123579Sgibbs && ahd_inb(ahd, SCSIPHASE) == 0) { 9444123579Sgibbs /* 9445123579Sgibbs * SCB is not identified, there 9446123579Sgibbs * is no pending REQ, and the sequencer 9447123579Sgibbs * has not seen a busfree. Looks like 9448123579Sgibbs * a stuck connection waiting to 9449123579Sgibbs * go busfree. Reset the bus. 9450123579Sgibbs */ 9451123579Sgibbs printf("%s: Connection stuck awaiting busfree or " 9452123579Sgibbs "Identify Msg.\n", ahd_name(ahd)); 9453123579Sgibbs goto bus_reset; 9454123579Sgibbs } else if (ahd_search_qinfifo(ahd, target, channel, lun, 9455141999Sgibbs SCB_GET_TAG(scb), 9456141978Sgibbs ROLE_INITIATOR, /*status*/0, 9457141978Sgibbs SEARCH_COUNT) > 0) { 9458123579Sgibbs 9459123579Sgibbs /* 9460123579Sgibbs * We haven't even gone out on the bus 9461123579Sgibbs * yet, so the timeout must be due to 9462123579Sgibbs * some other command. Reset the timer 9463123579Sgibbs * and go on. 9464123579Sgibbs */ 9465133966Sgibbs if (ahd_other_scb_timeout(ahd, scb, NULL) == 0) 9466129134Sgibbs goto bus_reset; 9467123579Sgibbs } else { 9468123579Sgibbs /* 9469123579Sgibbs * This SCB is for a disconnected transaction 9470123579Sgibbs * and we haven't found a better candidate on 9471123579Sgibbs * the bus to explain this timeout. 9472123579Sgibbs */ 9473123579Sgibbs ahd_set_recoveryscb(ahd, scb); 9474123579Sgibbs 9475123579Sgibbs /* 9476123579Sgibbs * Actually re-queue this SCB in an attempt 9477123579Sgibbs * to select the device before it reconnects. 9478123579Sgibbs * In either case (selection or reselection), 9479123579Sgibbs * we will now issue a target reset to the 9480123579Sgibbs * timed-out device. 9481123579Sgibbs */ 9482123579Sgibbs scb->flags |= SCB_DEVICE_RESET; 9483123579Sgibbs scb->hscb->cdb_len = 0; 9484123579Sgibbs scb->hscb->task_attribute = 0; 9485123579Sgibbs scb->hscb->task_management = SIU_TASKMGMT_ABORT_TASK; 9486123579Sgibbs 9487123579Sgibbs ahd_set_scbptr(ahd, SCB_GET_TAG(scb)); 9488123579Sgibbs if ((scb->flags & SCB_PACKETIZED) != 0) { 9489123579Sgibbs /* 9490123579Sgibbs * Mark the SCB has having an outstanding 9491123579Sgibbs * task management function. Should the command 9492123579Sgibbs * complete normally before the task management 9493123579Sgibbs * function can be sent, the host will be 9494123579Sgibbs * notified to abort our requeued SCB. 9495123579Sgibbs */ 9496123579Sgibbs ahd_outb(ahd, SCB_TASK_MANAGEMENT, 9497123579Sgibbs scb->hscb->task_management); 9498123579Sgibbs } else { 9499123579Sgibbs /* 9500123579Sgibbs * If non-packetized, set the MK_MESSAGE control 9501123579Sgibbs * bit indicating that we desire to send a 9502123579Sgibbs * message. We also set the disconnected flag 9503123579Sgibbs * since there is no guarantee that our SCB 9504123579Sgibbs * control byte matches the version on the 9505123579Sgibbs * card. We don't want the sequencer to abort 9506123579Sgibbs * the command thinking an unsolicited 9507123579Sgibbs * reselection occurred. 9508123579Sgibbs */ 9509123579Sgibbs scb->hscb->control |= MK_MESSAGE|DISCONNECTED; 9510123579Sgibbs 9511123579Sgibbs /* 9512123579Sgibbs * The sequencer will never re-reference the 9513123579Sgibbs * in-core SCB. To make sure we are notified 9514123579Sgibbs * during reslection, set the MK_MESSAGE flag in 9515123579Sgibbs * the card's copy of the SCB. 9516123579Sgibbs */ 9517123579Sgibbs ahd_outb(ahd, SCB_CONTROL, 9518123579Sgibbs ahd_inb(ahd, SCB_CONTROL)|MK_MESSAGE); 9519123579Sgibbs } 9520123579Sgibbs 9521123579Sgibbs /* 9522123579Sgibbs * Clear out any entries in the QINFIFO first 9523123579Sgibbs * so we are the next SCB for this target 9524123579Sgibbs * to run. 9525123579Sgibbs */ 9526123579Sgibbs ahd_search_qinfifo(ahd, target, channel, lun, 9527123579Sgibbs SCB_LIST_NULL, ROLE_INITIATOR, 9528123579Sgibbs CAM_REQUEUE_REQ, SEARCH_COMPLETE); 9529123579Sgibbs ahd_qinfifo_requeue_tail(ahd, scb); 9530123579Sgibbs ahd_set_scbptr(ahd, active_scbptr); 9531123579Sgibbs ahd_print_path(ahd, scb); 9532123579Sgibbs printf("Queuing a BDR SCB\n"); 9533137870Sgibbs aic_scb_timer_reset(scb, 2 * 1000); 9534123579Sgibbs break; 9535123579Sgibbs } 9536123579Sgibbs } 9537123579Sgibbs 9538123579Sgibbs /* 9539123579Sgibbs * Any remaining SCBs were not the "culprit", so remove 9540123579Sgibbs * them from the timeout list. The timer for these commands 9541123579Sgibbs * will be reset once the recovery SCB completes. 9542123579Sgibbs */ 9543123579Sgibbs while ((scb = LIST_FIRST(&ahd->timedout_scbs)) != NULL) { 9544123579Sgibbs 9545123579Sgibbs LIST_REMOVE(scb, timedout_links); 9546123579Sgibbs scb->flags &= ~SCB_TIMEDOUT; 9547123579Sgibbs } 9548123579Sgibbs 9549123579Sgibbs ahd_unpause(ahd); 9550123579Sgibbs} 9551123579Sgibbs 9552129134Sgibbs/* 9553129134Sgibbs * Re-schedule a timeout for the passed in SCB if we determine that some 9554129134Sgibbs * other SCB is in the process of recovery or an SCB with a longer 9555129134Sgibbs * timeout is still pending. Limit our search to just "other_scb" 9556129134Sgibbs * if it is non-NULL. 9557129134Sgibbs */ 9558129134Sgibbsstatic int 9559123579Sgibbsahd_other_scb_timeout(struct ahd_softc *ahd, struct scb *scb, 9560123579Sgibbs struct scb *other_scb) 9561123579Sgibbs{ 9562123579Sgibbs u_int newtimeout; 9563129134Sgibbs int found; 9564123579Sgibbs 9565123579Sgibbs ahd_print_path(ahd, scb); 9566123579Sgibbs printf("Other SCB Timeout%s", 9567123579Sgibbs (scb->flags & SCB_OTHERTCL_TIMEOUT) != 0 9568123579Sgibbs ? " again\n" : "\n"); 9569129134Sgibbs 9570199260Sattilio AHD_UNCORRECTABLE_ERROR(ahd); 9571129134Sgibbs newtimeout = aic_get_timeout(scb); 9572123579Sgibbs scb->flags |= SCB_OTHERTCL_TIMEOUT; 9573129134Sgibbs found = 0; 9574129134Sgibbs if (other_scb != NULL) { 9575129134Sgibbs if ((other_scb->flags 9576129134Sgibbs & (SCB_OTHERTCL_TIMEOUT|SCB_TIMEDOUT)) == 0 9577129134Sgibbs || (other_scb->flags & SCB_RECOVERY_SCB) != 0) { 9578129134Sgibbs found++; 9579129134Sgibbs newtimeout = MAX(aic_get_timeout(other_scb), 9580129134Sgibbs newtimeout); 9581129134Sgibbs } 9582129134Sgibbs } else { 9583129134Sgibbs LIST_FOREACH(other_scb, &ahd->pending_scbs, pending_links) { 9584129134Sgibbs if ((other_scb->flags 9585129134Sgibbs & (SCB_OTHERTCL_TIMEOUT|SCB_TIMEDOUT)) == 0 9586129134Sgibbs || (other_scb->flags & SCB_RECOVERY_SCB) != 0) { 9587129134Sgibbs found++; 9588129134Sgibbs newtimeout = MAX(aic_get_timeout(other_scb), 9589129134Sgibbs newtimeout); 9590129134Sgibbs } 9591129134Sgibbs } 9592129134Sgibbs } 9593129134Sgibbs 9594129134Sgibbs if (found != 0) 9595129134Sgibbs aic_scb_timer_reset(scb, newtimeout); 9596129134Sgibbs else { 9597129134Sgibbs ahd_print_path(ahd, scb); 9598129134Sgibbs printf("No other SCB worth waiting for...\n"); 9599129134Sgibbs } 9600129134Sgibbs 9601129134Sgibbs return (found != 0); 9602123579Sgibbs} 9603123579Sgibbs 960497883Sgibbs/**************************** Flexport Logic **********************************/ 960597883Sgibbs/* 960697883Sgibbs * Read count 16bit words from 16bit word address start_addr from the 960797883Sgibbs * SEEPROM attached to the controller, into buf, using the controller's 9608114623Sgibbs * SEEPROM reading state machine. Optionally treat the data as a byte 9609114623Sgibbs * stream in terms of byte order. 961097883Sgibbs */ 961197883Sgibbsint 961297883Sgibbsahd_read_seeprom(struct ahd_softc *ahd, uint16_t *buf, 9613114623Sgibbs u_int start_addr, u_int count, int bytestream) 961497883Sgibbs{ 961597883Sgibbs u_int cur_addr; 961697883Sgibbs u_int end_addr; 961797883Sgibbs int error; 961897883Sgibbs 961997883Sgibbs /* 962097883Sgibbs * If we never make it through the loop even once, 962197883Sgibbs * we were passed invalid arguments. 962297883Sgibbs */ 962397883Sgibbs error = EINVAL; 962497883Sgibbs AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 962597883Sgibbs end_addr = start_addr + count; 962697883Sgibbs for (cur_addr = start_addr; cur_addr < end_addr; cur_addr++) { 9627114623Sgibbs 962897883Sgibbs ahd_outb(ahd, SEEADR, cur_addr); 962997883Sgibbs ahd_outb(ahd, SEECTL, SEEOP_READ | SEESTART); 963097883Sgibbs 963197883Sgibbs error = ahd_wait_seeprom(ahd); 963297883Sgibbs if (error) 963397883Sgibbs break; 9634114623Sgibbs if (bytestream != 0) { 9635114623Sgibbs uint8_t *bytestream_ptr; 9636114623Sgibbs 9637114623Sgibbs bytestream_ptr = (uint8_t *)buf; 9638114623Sgibbs *bytestream_ptr++ = ahd_inb(ahd, SEEDAT); 9639114623Sgibbs *bytestream_ptr = ahd_inb(ahd, SEEDAT+1); 9640114623Sgibbs } else { 9641114623Sgibbs /* 9642114623Sgibbs * ahd_inw() already handles machine byte order. 9643114623Sgibbs */ 9644114623Sgibbs *buf = ahd_inw(ahd, SEEDAT); 9645114623Sgibbs } 9646114623Sgibbs buf++; 964797883Sgibbs } 964897883Sgibbs return (error); 964997883Sgibbs} 965097883Sgibbs 965197883Sgibbs/* 965297883Sgibbs * Write count 16bit words from buf, into SEEPROM attache to the 965397883Sgibbs * controller starting at 16bit word address start_addr, using the 965497883Sgibbs * controller's SEEPROM writing state machine. 965597883Sgibbs */ 965697883Sgibbsint 965797883Sgibbsahd_write_seeprom(struct ahd_softc *ahd, uint16_t *buf, 965897883Sgibbs u_int start_addr, u_int count) 965997883Sgibbs{ 966097883Sgibbs u_int cur_addr; 966197883Sgibbs u_int end_addr; 966297883Sgibbs int error; 966397883Sgibbs int retval; 966497883Sgibbs 966597883Sgibbs AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 966697883Sgibbs error = ENOENT; 966797883Sgibbs 966897883Sgibbs /* Place the chip into write-enable mode */ 966997883Sgibbs ahd_outb(ahd, SEEADR, SEEOP_EWEN_ADDR); 967097883Sgibbs ahd_outb(ahd, SEECTL, SEEOP_EWEN | SEESTART); 967197883Sgibbs error = ahd_wait_seeprom(ahd); 967297883Sgibbs if (error) 967397883Sgibbs return (error); 967497883Sgibbs 967597883Sgibbs /* 967697883Sgibbs * Write the data. If we don't get throught the loop at 967797883Sgibbs * least once, the arguments were invalid. 967897883Sgibbs */ 967997883Sgibbs retval = EINVAL; 968097883Sgibbs end_addr = start_addr + count; 968197883Sgibbs for (cur_addr = start_addr; cur_addr < end_addr; cur_addr++) { 968297883Sgibbs ahd_outw(ahd, SEEDAT, *buf++); 968397883Sgibbs ahd_outb(ahd, SEEADR, cur_addr); 968497883Sgibbs ahd_outb(ahd, SEECTL, SEEOP_WRITE | SEESTART); 968597883Sgibbs 968697883Sgibbs retval = ahd_wait_seeprom(ahd); 968797883Sgibbs if (retval) 968897883Sgibbs break; 968997883Sgibbs } 969097883Sgibbs 969197883Sgibbs /* 969297883Sgibbs * Disable writes. 969397883Sgibbs */ 969497883Sgibbs ahd_outb(ahd, SEEADR, SEEOP_EWDS_ADDR); 969597883Sgibbs ahd_outb(ahd, SEECTL, SEEOP_EWDS | SEESTART); 969697883Sgibbs error = ahd_wait_seeprom(ahd); 969797883Sgibbs if (error) 969897883Sgibbs return (error); 969997883Sgibbs return (retval); 970097883Sgibbs} 970197883Sgibbs 970297883Sgibbs/* 970397883Sgibbs * Wait ~100us for the serial eeprom to satisfy our request. 970497883Sgibbs */ 970597883Sgibbsint 970697883Sgibbsahd_wait_seeprom(struct ahd_softc *ahd) 970797883Sgibbs{ 970897883Sgibbs int cnt; 970997883Sgibbs 9710123579Sgibbs cnt = 5000; 971197883Sgibbs while ((ahd_inb(ahd, SEESTAT) & (SEEARBACK|SEEBUSY)) != 0 && --cnt) 9712123579Sgibbs aic_delay(5); 971397883Sgibbs 971497883Sgibbs if (cnt == 0) 971597883Sgibbs return (ETIMEDOUT); 971697883Sgibbs return (0); 971797883Sgibbs} 971897883Sgibbs 9719114623Sgibbs/* 9720114623Sgibbs * Validate the two checksums in the per_channel 9721114623Sgibbs * vital product data struct. 9722114623Sgibbs */ 972397883Sgibbsint 9724114623Sgibbsahd_verify_vpd_cksum(struct vpd_config *vpd) 9725114623Sgibbs{ 9726114623Sgibbs int i; 9727114623Sgibbs int maxaddr; 9728114623Sgibbs uint32_t checksum; 9729114623Sgibbs uint8_t *vpdarray; 9730114623Sgibbs 9731114623Sgibbs vpdarray = (uint8_t *)vpd; 9732114623Sgibbs maxaddr = offsetof(struct vpd_config, vpd_checksum); 9733114623Sgibbs checksum = 0; 9734114623Sgibbs for (i = offsetof(struct vpd_config, resource_type); i < maxaddr; i++) 9735114623Sgibbs checksum = checksum + vpdarray[i]; 9736114623Sgibbs if (checksum == 0 9737114623Sgibbs || (-checksum & 0xFF) != vpd->vpd_checksum) 9738114623Sgibbs return (0); 9739114623Sgibbs 9740114623Sgibbs checksum = 0; 9741114623Sgibbs maxaddr = offsetof(struct vpd_config, checksum); 9742114623Sgibbs for (i = offsetof(struct vpd_config, default_target_flags); 9743114623Sgibbs i < maxaddr; i++) 9744114623Sgibbs checksum = checksum + vpdarray[i]; 9745114623Sgibbs if (checksum == 0 9746114623Sgibbs || (-checksum & 0xFF) != vpd->checksum) 9747114623Sgibbs return (0); 9748114623Sgibbs return (1); 9749114623Sgibbs} 9750114623Sgibbs 9751114623Sgibbsint 975297883Sgibbsahd_verify_cksum(struct seeprom_config *sc) 975397883Sgibbs{ 975497883Sgibbs int i; 975597883Sgibbs int maxaddr; 975697883Sgibbs uint32_t checksum; 975797883Sgibbs uint16_t *scarray; 975897883Sgibbs 975997883Sgibbs maxaddr = (sizeof(*sc)/2) - 1; 976097883Sgibbs checksum = 0; 976197883Sgibbs scarray = (uint16_t *)sc; 976297883Sgibbs 976397883Sgibbs for (i = 0; i < maxaddr; i++) 976497883Sgibbs checksum = checksum + scarray[i]; 976597883Sgibbs if (checksum == 0 976697883Sgibbs || (checksum & 0xFFFF) != sc->checksum) { 976797883Sgibbs return (0); 976897883Sgibbs } else { 976997883Sgibbs return (1); 977097883Sgibbs } 977197883Sgibbs} 977297883Sgibbs 977397883Sgibbsint 977497883Sgibbsahd_acquire_seeprom(struct ahd_softc *ahd) 977597883Sgibbs{ 9776102679Sgibbs /* 9777102679Sgibbs * We should be able to determine the SEEPROM type 9778102679Sgibbs * from the flexport logic, but unfortunately not 9779102679Sgibbs * all implementations have this logic and there is 9780102679Sgibbs * no programatic method for determining if the logic 9781102679Sgibbs * is present. 9782102679Sgibbs */ 9783102679Sgibbs return (1); 9784102679Sgibbs#if 0 978597883Sgibbs uint8_t seetype; 978697883Sgibbs int error; 978797883Sgibbs 978897883Sgibbs error = ahd_read_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, &seetype); 978997883Sgibbs if (error != 0 979097883Sgibbs || ((seetype & FLX_ROMSTAT_SEECFG) == FLX_ROMSTAT_SEE_NONE)) 979197883Sgibbs return (0); 979297883Sgibbs return (1); 9793102679Sgibbs#endif 979497883Sgibbs} 979597883Sgibbs 979697883Sgibbsvoid 979797883Sgibbsahd_release_seeprom(struct ahd_softc *ahd) 979897883Sgibbs{ 979997883Sgibbs /* Currently a no-op */ 980097883Sgibbs} 980197883Sgibbs 980297883Sgibbsint 980397883Sgibbsahd_write_flexport(struct ahd_softc *ahd, u_int addr, u_int value) 980497883Sgibbs{ 980597883Sgibbs int error; 980697883Sgibbs 980797883Sgibbs AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 980897883Sgibbs if (addr > 7) 980997883Sgibbs panic("ahd_write_flexport: address out of range"); 981097883Sgibbs ahd_outb(ahd, BRDCTL, BRDEN|(addr << 3)); 981197883Sgibbs error = ahd_wait_flexport(ahd); 981297883Sgibbs if (error != 0) 981397883Sgibbs return (error); 981497883Sgibbs ahd_outb(ahd, BRDDAT, value); 981597883Sgibbs ahd_flush_device_writes(ahd); 981697883Sgibbs ahd_outb(ahd, BRDCTL, BRDSTB|BRDEN|(addr << 3)); 981797883Sgibbs ahd_flush_device_writes(ahd); 981897883Sgibbs ahd_outb(ahd, BRDCTL, BRDEN|(addr << 3)); 981997883Sgibbs ahd_flush_device_writes(ahd); 982097883Sgibbs ahd_outb(ahd, BRDCTL, 0); 982197883Sgibbs ahd_flush_device_writes(ahd); 982297883Sgibbs return (0); 982397883Sgibbs} 982497883Sgibbs 982597883Sgibbsint 982697883Sgibbsahd_read_flexport(struct ahd_softc *ahd, u_int addr, uint8_t *value) 982797883Sgibbs{ 982897883Sgibbs int error; 982997883Sgibbs 983097883Sgibbs AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 983197883Sgibbs if (addr > 7) 983297883Sgibbs panic("ahd_read_flexport: address out of range"); 983397883Sgibbs ahd_outb(ahd, BRDCTL, BRDRW|BRDEN|(addr << 3)); 983497883Sgibbs error = ahd_wait_flexport(ahd); 983597883Sgibbs if (error != 0) 983697883Sgibbs return (error); 983797883Sgibbs *value = ahd_inb(ahd, BRDDAT); 983897883Sgibbs ahd_outb(ahd, BRDCTL, 0); 983997883Sgibbs ahd_flush_device_writes(ahd); 984097883Sgibbs return (0); 984197883Sgibbs} 984297883Sgibbs 984397883Sgibbs/* 984497883Sgibbs * Wait at most 2 seconds for flexport arbitration to succeed. 984597883Sgibbs */ 984697883Sgibbsint 984797883Sgibbsahd_wait_flexport(struct ahd_softc *ahd) 984897883Sgibbs{ 984997883Sgibbs int cnt; 985097883Sgibbs 985197883Sgibbs AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 985297883Sgibbs cnt = 1000000 * 2 / 5; 985397883Sgibbs while ((ahd_inb(ahd, BRDCTL) & FLXARBACK) == 0 && --cnt) 9854123579Sgibbs aic_delay(5); 985597883Sgibbs 985697883Sgibbs if (cnt == 0) 985797883Sgibbs return (ETIMEDOUT); 985897883Sgibbs return (0); 985997883Sgibbs} 986097883Sgibbs 986197883Sgibbs/************************* Target Mode ****************************************/ 986297883Sgibbs#ifdef AHD_TARGET_MODE 986397883Sgibbscam_status 986497883Sgibbsahd_find_tmode_devs(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb, 986597883Sgibbs struct ahd_tmode_tstate **tstate, 986697883Sgibbs struct ahd_tmode_lstate **lstate, 986797883Sgibbs int notfound_failure) 986897883Sgibbs{ 986997883Sgibbs 987097883Sgibbs if ((ahd->features & AHD_TARGETMODE) == 0) 987197883Sgibbs return (CAM_REQ_INVALID); 987297883Sgibbs 987397883Sgibbs /* 987497883Sgibbs * Handle the 'black hole' device that sucks up 987597883Sgibbs * requests to unattached luns on enabled targets. 987697883Sgibbs */ 987797883Sgibbs if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD 987897883Sgibbs && ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) { 987997883Sgibbs *tstate = NULL; 988097883Sgibbs *lstate = ahd->black_hole; 988197883Sgibbs } else { 988297883Sgibbs u_int max_id; 988397883Sgibbs 988497883Sgibbs max_id = (ahd->features & AHD_WIDE) ? 15 : 7; 988597883Sgibbs if (ccb->ccb_h.target_id > max_id) 988697883Sgibbs return (CAM_TID_INVALID); 988797883Sgibbs 988897883Sgibbs if (ccb->ccb_h.target_lun >= AHD_NUM_LUNS) 988997883Sgibbs return (CAM_LUN_INVALID); 989097883Sgibbs 989197883Sgibbs *tstate = ahd->enabled_targets[ccb->ccb_h.target_id]; 989297883Sgibbs *lstate = NULL; 989397883Sgibbs if (*tstate != NULL) 989497883Sgibbs *lstate = 989597883Sgibbs (*tstate)->enabled_luns[ccb->ccb_h.target_lun]; 989697883Sgibbs } 989797883Sgibbs 989897883Sgibbs if (notfound_failure != 0 && *lstate == NULL) 989997883Sgibbs return (CAM_PATH_INVALID); 990097883Sgibbs 990197883Sgibbs return (CAM_REQ_CMP); 990297883Sgibbs} 990397883Sgibbs 990497883Sgibbsvoid 990597883Sgibbsahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) 990697883Sgibbs{ 990797883Sgibbs#if NOT_YET 990897883Sgibbs struct ahd_tmode_tstate *tstate; 990997883Sgibbs struct ahd_tmode_lstate *lstate; 991097883Sgibbs struct ccb_en_lun *cel; 991197883Sgibbs cam_status status; 991297883Sgibbs u_int target; 991397883Sgibbs u_int lun; 991497883Sgibbs u_int target_mask; 991597883Sgibbs u_long s; 991697883Sgibbs char channel; 991797883Sgibbs 991897883Sgibbs status = ahd_find_tmode_devs(ahd, sim, ccb, &tstate, &lstate, 991997883Sgibbs /*notfound_failure*/FALSE); 992097883Sgibbs 992197883Sgibbs if (status != CAM_REQ_CMP) { 992297883Sgibbs ccb->ccb_h.status = status; 992397883Sgibbs return; 992497883Sgibbs } 992597883Sgibbs 992697883Sgibbs if ((ahd->features & AHD_MULTIROLE) != 0) { 992797883Sgibbs u_int our_id; 992897883Sgibbs 992997883Sgibbs our_id = ahd->our_id; 993097883Sgibbs if (ccb->ccb_h.target_id != our_id) { 993197883Sgibbs if ((ahd->features & AHD_MULTI_TID) != 0 993297883Sgibbs && (ahd->flags & AHD_INITIATORROLE) != 0) { 993397883Sgibbs /* 993497883Sgibbs * Only allow additional targets if 993597883Sgibbs * the initiator role is disabled. 993697883Sgibbs * The hardware cannot handle a re-select-in 993797883Sgibbs * on the initiator id during a re-select-out 993897883Sgibbs * on a different target id. 993997883Sgibbs */ 994097883Sgibbs status = CAM_TID_INVALID; 994197883Sgibbs } else if ((ahd->flags & AHD_INITIATORROLE) != 0 994297883Sgibbs || ahd->enabled_luns > 0) { 994397883Sgibbs /* 994497883Sgibbs * Only allow our target id to change 994597883Sgibbs * if the initiator role is not configured 994697883Sgibbs * and there are no enabled luns which 994797883Sgibbs * are attached to the currently registered 994897883Sgibbs * scsi id. 994997883Sgibbs */ 995097883Sgibbs status = CAM_TID_INVALID; 995197883Sgibbs } 995297883Sgibbs } 995397883Sgibbs } 995497883Sgibbs 995597883Sgibbs if (status != CAM_REQ_CMP) { 995697883Sgibbs ccb->ccb_h.status = status; 995797883Sgibbs return; 995897883Sgibbs } 995997883Sgibbs 996097883Sgibbs /* 996197883Sgibbs * We now have an id that is valid. 996297883Sgibbs * If we aren't in target mode, switch modes. 996397883Sgibbs */ 996497883Sgibbs if ((ahd->flags & AHD_TARGETROLE) == 0 996597883Sgibbs && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) { 996697883Sgibbs printf("Configuring Target Mode\n"); 996797883Sgibbs if (LIST_FIRST(&ahd->pending_scbs) != NULL) { 996897883Sgibbs ccb->ccb_h.status = CAM_BUSY; 996997883Sgibbs return; 997097883Sgibbs } 997197883Sgibbs ahd->flags |= AHD_TARGETROLE; 997297883Sgibbs if ((ahd->features & AHD_MULTIROLE) == 0) 997397883Sgibbs ahd->flags &= ~AHD_INITIATORROLE; 997497883Sgibbs ahd_pause(ahd); 997597883Sgibbs ahd_loadseq(ahd); 9976115917Sgibbs ahd_restart(ahd); 997797883Sgibbs } 997897883Sgibbs cel = &ccb->cel; 997997883Sgibbs target = ccb->ccb_h.target_id; 998097883Sgibbs lun = ccb->ccb_h.target_lun; 998197883Sgibbs channel = SIM_CHANNEL(ahd, sim); 998297883Sgibbs target_mask = 0x01 << target; 998397883Sgibbs if (channel == 'B') 998497883Sgibbs target_mask <<= 8; 998597883Sgibbs 998697883Sgibbs if (cel->enable != 0) { 998797883Sgibbs u_int scsiseq1; 998897883Sgibbs 998997883Sgibbs /* Are we already enabled?? */ 999097883Sgibbs if (lstate != NULL) { 999197883Sgibbs xpt_print_path(ccb->ccb_h.path); 999297883Sgibbs printf("Lun already enabled\n"); 9993199260Sattilio AHD_CORRECTABLE_ERROR(ahd); 999497883Sgibbs ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; 999597883Sgibbs return; 999697883Sgibbs } 999797883Sgibbs 999897883Sgibbs if (cel->grp6_len != 0 999997883Sgibbs || cel->grp7_len != 0) { 1000097883Sgibbs /* 1000197883Sgibbs * Don't (yet?) support vendor 1000297883Sgibbs * specific commands. 1000397883Sgibbs */ 1000497883Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 1000597883Sgibbs printf("Non-zero Group Codes\n"); 1000697883Sgibbs return; 1000797883Sgibbs } 1000897883Sgibbs 1000997883Sgibbs /* 1001097883Sgibbs * Seems to be okay. 1001197883Sgibbs * Setup our data structures. 1001297883Sgibbs */ 1001397883Sgibbs if (target != CAM_TARGET_WILDCARD && tstate == NULL) { 1001497883Sgibbs tstate = ahd_alloc_tstate(ahd, target, channel); 1001597883Sgibbs if (tstate == NULL) { 1001697883Sgibbs xpt_print_path(ccb->ccb_h.path); 1001797883Sgibbs printf("Couldn't allocate tstate\n"); 1001897883Sgibbs ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 1001997883Sgibbs return; 1002097883Sgibbs } 1002197883Sgibbs } 1002297883Sgibbs lstate = malloc(sizeof(*lstate), M_DEVBUF, M_NOWAIT); 1002397883Sgibbs if (lstate == NULL) { 1002497883Sgibbs xpt_print_path(ccb->ccb_h.path); 1002597883Sgibbs printf("Couldn't allocate lstate\n"); 1002697883Sgibbs ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 1002797883Sgibbs return; 1002897883Sgibbs } 1002997883Sgibbs memset(lstate, 0, sizeof(*lstate)); 1003097883Sgibbs status = xpt_create_path(&lstate->path, /*periph*/NULL, 1003197883Sgibbs xpt_path_path_id(ccb->ccb_h.path), 1003297883Sgibbs xpt_path_target_id(ccb->ccb_h.path), 1003397883Sgibbs xpt_path_lun_id(ccb->ccb_h.path)); 1003497883Sgibbs if (status != CAM_REQ_CMP) { 1003597883Sgibbs free(lstate, M_DEVBUF); 1003697883Sgibbs xpt_print_path(ccb->ccb_h.path); 1003797883Sgibbs printf("Couldn't allocate path\n"); 1003897883Sgibbs ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 1003997883Sgibbs return; 1004097883Sgibbs } 1004197883Sgibbs SLIST_INIT(&lstate->accept_tios); 1004297883Sgibbs SLIST_INIT(&lstate->immed_notifies); 1004397883Sgibbs ahd_pause(ahd); 1004497883Sgibbs if (target != CAM_TARGET_WILDCARD) { 1004597883Sgibbs tstate->enabled_luns[lun] = lstate; 1004697883Sgibbs ahd->enabled_luns++; 1004797883Sgibbs 1004897883Sgibbs if ((ahd->features & AHD_MULTI_TID) != 0) { 1004997883Sgibbs u_int targid_mask; 1005097883Sgibbs 10051123579Sgibbs targid_mask = ahd_inw(ahd, TARGID); 1005297883Sgibbs targid_mask |= target_mask; 10053123579Sgibbs ahd_outw(ahd, TARGID, targid_mask); 1005497883Sgibbs ahd_update_scsiid(ahd, targid_mask); 1005597883Sgibbs } else { 1005697883Sgibbs u_int our_id; 1005797883Sgibbs char channel; 1005897883Sgibbs 1005997883Sgibbs channel = SIM_CHANNEL(ahd, sim); 1006097883Sgibbs our_id = SIM_SCSI_ID(ahd, sim); 1006197883Sgibbs 1006297883Sgibbs /* 1006397883Sgibbs * This can only happen if selections 1006497883Sgibbs * are not enabled 1006597883Sgibbs */ 1006697883Sgibbs if (target != our_id) { 1006797883Sgibbs u_int sblkctl; 1006897883Sgibbs char cur_channel; 1006997883Sgibbs int swap; 1007097883Sgibbs 1007197883Sgibbs sblkctl = ahd_inb(ahd, SBLKCTL); 1007297883Sgibbs cur_channel = (sblkctl & SELBUSB) 1007397883Sgibbs ? 'B' : 'A'; 1007497883Sgibbs if ((ahd->features & AHD_TWIN) == 0) 1007597883Sgibbs cur_channel = 'A'; 1007697883Sgibbs swap = cur_channel != channel; 1007797883Sgibbs ahd->our_id = target; 1007897883Sgibbs 1007997883Sgibbs if (swap) 1008097883Sgibbs ahd_outb(ahd, SBLKCTL, 1008197883Sgibbs sblkctl ^ SELBUSB); 1008297883Sgibbs 1008397883Sgibbs ahd_outb(ahd, SCSIID, target); 1008497883Sgibbs 1008597883Sgibbs if (swap) 1008697883Sgibbs ahd_outb(ahd, SBLKCTL, sblkctl); 1008797883Sgibbs } 1008897883Sgibbs } 1008997883Sgibbs } else 1009097883Sgibbs ahd->black_hole = lstate; 1009197883Sgibbs /* Allow select-in operations */ 1009297883Sgibbs if (ahd->black_hole != NULL && ahd->enabled_luns > 0) { 1009397883Sgibbs scsiseq1 = ahd_inb(ahd, SCSISEQ_TEMPLATE); 1009497883Sgibbs scsiseq1 |= ENSELI; 1009597883Sgibbs ahd_outb(ahd, SCSISEQ_TEMPLATE, scsiseq1); 1009697883Sgibbs scsiseq1 = ahd_inb(ahd, SCSISEQ1); 1009797883Sgibbs scsiseq1 |= ENSELI; 1009897883Sgibbs ahd_outb(ahd, SCSISEQ1, scsiseq1); 1009997883Sgibbs } 1010097883Sgibbs ahd_unpause(ahd); 1010197883Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 1010297883Sgibbs xpt_print_path(ccb->ccb_h.path); 1010397883Sgibbs printf("Lun now enabled for target mode\n"); 1010497883Sgibbs } else { 1010597883Sgibbs struct scb *scb; 1010697883Sgibbs int i, empty; 1010797883Sgibbs 1010897883Sgibbs if (lstate == NULL) { 1010997883Sgibbs ccb->ccb_h.status = CAM_LUN_INVALID; 1011097883Sgibbs return; 1011197883Sgibbs } 1011297883Sgibbs 1011397883Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 1011497883Sgibbs LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) { 1011597883Sgibbs struct ccb_hdr *ccbh; 1011697883Sgibbs 1011797883Sgibbs ccbh = &scb->io_ctx->ccb_h; 1011897883Sgibbs if (ccbh->func_code == XPT_CONT_TARGET_IO 1011997883Sgibbs && !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){ 1012097883Sgibbs printf("CTIO pending\n"); 1012197883Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 1012297883Sgibbs return; 1012397883Sgibbs } 1012497883Sgibbs } 1012597883Sgibbs 1012697883Sgibbs if (SLIST_FIRST(&lstate->accept_tios) != NULL) { 1012797883Sgibbs printf("ATIOs pending\n"); 1012897883Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 1012997883Sgibbs } 1013097883Sgibbs 1013197883Sgibbs if (SLIST_FIRST(&lstate->immed_notifies) != NULL) { 1013297883Sgibbs printf("INOTs pending\n"); 1013397883Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 1013497883Sgibbs } 1013597883Sgibbs 1013697883Sgibbs if (ccb->ccb_h.status != CAM_REQ_CMP) { 1013797883Sgibbs return; 1013897883Sgibbs } 1013997883Sgibbs 1014097883Sgibbs xpt_print_path(ccb->ccb_h.path); 1014197883Sgibbs printf("Target mode disabled\n"); 1014297883Sgibbs xpt_free_path(lstate->path); 1014397883Sgibbs free(lstate, M_DEVBUF); 1014497883Sgibbs 1014597883Sgibbs ahd_pause(ahd); 1014697883Sgibbs /* Can we clean up the target too? */ 1014797883Sgibbs if (target != CAM_TARGET_WILDCARD) { 1014897883Sgibbs tstate->enabled_luns[lun] = NULL; 1014997883Sgibbs ahd->enabled_luns--; 1015097883Sgibbs for (empty = 1, i = 0; i < 8; i++) 1015197883Sgibbs if (tstate->enabled_luns[i] != NULL) { 1015297883Sgibbs empty = 0; 1015397883Sgibbs break; 1015497883Sgibbs } 1015597883Sgibbs 1015697883Sgibbs if (empty) { 1015797883Sgibbs ahd_free_tstate(ahd, target, channel, 1015897883Sgibbs /*force*/FALSE); 1015997883Sgibbs if (ahd->features & AHD_MULTI_TID) { 1016097883Sgibbs u_int targid_mask; 1016197883Sgibbs 10162123579Sgibbs targid_mask = ahd_inw(ahd, TARGID); 1016397883Sgibbs targid_mask &= ~target_mask; 10164123579Sgibbs ahd_outw(ahd, TARGID, targid_mask); 1016597883Sgibbs ahd_update_scsiid(ahd, targid_mask); 1016697883Sgibbs } 1016797883Sgibbs } 1016897883Sgibbs } else { 1016997883Sgibbs 1017097883Sgibbs ahd->black_hole = NULL; 1017197883Sgibbs 1017297883Sgibbs /* 1017397883Sgibbs * We can't allow selections without 1017497883Sgibbs * our black hole device. 1017597883Sgibbs */ 1017697883Sgibbs empty = TRUE; 1017797883Sgibbs } 1017897883Sgibbs if (ahd->enabled_luns == 0) { 1017997883Sgibbs /* Disallow select-in */ 1018097883Sgibbs u_int scsiseq1; 1018197883Sgibbs 1018297883Sgibbs scsiseq1 = ahd_inb(ahd, SCSISEQ_TEMPLATE); 1018397883Sgibbs scsiseq1 &= ~ENSELI; 1018497883Sgibbs ahd_outb(ahd, SCSISEQ_TEMPLATE, scsiseq1); 1018597883Sgibbs scsiseq1 = ahd_inb(ahd, SCSISEQ1); 1018697883Sgibbs scsiseq1 &= ~ENSELI; 1018797883Sgibbs ahd_outb(ahd, SCSISEQ1, scsiseq1); 1018897883Sgibbs 1018997883Sgibbs if ((ahd->features & AHD_MULTIROLE) == 0) { 1019097883Sgibbs printf("Configuring Initiator Mode\n"); 1019197883Sgibbs ahd->flags &= ~AHD_TARGETROLE; 1019297883Sgibbs ahd->flags |= AHD_INITIATORROLE; 1019397883Sgibbs ahd_pause(ahd); 1019497883Sgibbs ahd_loadseq(ahd); 10195115917Sgibbs ahd_restart(ahd); 10196115917Sgibbs /* 10197115917Sgibbs * Unpaused. The extra unpause 10198115917Sgibbs * that follows is harmless. 10199115917Sgibbs */ 1020097883Sgibbs } 1020197883Sgibbs } 1020297883Sgibbs ahd_unpause(ahd); 1020397883Sgibbs } 1020497883Sgibbs#endif 1020597883Sgibbs} 1020697883Sgibbs 1020797883Sgibbsstatic void 1020897883Sgibbsahd_update_scsiid(struct ahd_softc *ahd, u_int targid_mask) 1020997883Sgibbs{ 1021097883Sgibbs#if NOT_YET 1021197883Sgibbs u_int scsiid_mask; 1021297883Sgibbs u_int scsiid; 1021397883Sgibbs 1021497883Sgibbs if ((ahd->features & AHD_MULTI_TID) == 0) 1021597883Sgibbs panic("ahd_update_scsiid called on non-multitid unit\n"); 1021697883Sgibbs 1021797883Sgibbs /* 10218102679Sgibbs * Since we will rely on the TARGID mask 1021997883Sgibbs * for selection enables, ensure that OID 1022097883Sgibbs * in SCSIID is not set to some other ID 1022197883Sgibbs * that we don't want to allow selections on. 1022297883Sgibbs */ 1022397883Sgibbs if ((ahd->features & AHD_ULTRA2) != 0) 1022497883Sgibbs scsiid = ahd_inb(ahd, SCSIID_ULTRA2); 1022597883Sgibbs else 1022697883Sgibbs scsiid = ahd_inb(ahd, SCSIID); 1022797883Sgibbs scsiid_mask = 0x1 << (scsiid & OID); 1022897883Sgibbs if ((targid_mask & scsiid_mask) == 0) { 1022997883Sgibbs u_int our_id; 1023097883Sgibbs 1023197883Sgibbs /* ffs counts from 1 */ 1023297883Sgibbs our_id = ffs(targid_mask); 1023397883Sgibbs if (our_id == 0) 1023497883Sgibbs our_id = ahd->our_id; 1023597883Sgibbs else 1023697883Sgibbs our_id--; 1023797883Sgibbs scsiid &= TID; 1023897883Sgibbs scsiid |= our_id; 1023997883Sgibbs } 1024097883Sgibbs if ((ahd->features & AHD_ULTRA2) != 0) 1024197883Sgibbs ahd_outb(ahd, SCSIID_ULTRA2, scsiid); 1024297883Sgibbs else 1024397883Sgibbs ahd_outb(ahd, SCSIID, scsiid); 1024497883Sgibbs#endif 1024597883Sgibbs} 1024697883Sgibbs 1024797883Sgibbsvoid 1024897883Sgibbsahd_run_tqinfifo(struct ahd_softc *ahd, int paused) 1024997883Sgibbs{ 1025097883Sgibbs struct target_cmd *cmd; 1025197883Sgibbs 1025297883Sgibbs ahd_sync_tqinfifo(ahd, BUS_DMASYNC_POSTREAD); 1025397883Sgibbs while ((cmd = &ahd->targetcmds[ahd->tqinfifonext])->cmd_valid != 0) { 1025497883Sgibbs 1025597883Sgibbs /* 1025697883Sgibbs * Only advance through the queue if we 1025797883Sgibbs * have the resources to process the command. 1025897883Sgibbs */ 1025997883Sgibbs if (ahd_handle_target_cmd(ahd, cmd) != 0) 1026097883Sgibbs break; 1026197883Sgibbs 1026297883Sgibbs cmd->cmd_valid = 0; 1026397883Sgibbs ahd_dmamap_sync(ahd, ahd->shared_data_dmat, 1026497883Sgibbs ahd->shared_data_dmamap, 1026597883Sgibbs ahd_targetcmd_offset(ahd, ahd->tqinfifonext), 1026697883Sgibbs sizeof(struct target_cmd), 1026797883Sgibbs BUS_DMASYNC_PREREAD); 1026897883Sgibbs ahd->tqinfifonext++; 1026997883Sgibbs 1027097883Sgibbs /* 1027197883Sgibbs * Lazily update our position in the target mode incoming 1027297883Sgibbs * command queue as seen by the sequencer. 1027397883Sgibbs */ 1027497883Sgibbs if ((ahd->tqinfifonext & (HOST_TQINPOS - 1)) == 1) { 1027597883Sgibbs u_int hs_mailbox; 1027697883Sgibbs 1027797883Sgibbs hs_mailbox = ahd_inb(ahd, HS_MAILBOX); 1027897883Sgibbs hs_mailbox &= ~HOST_TQINPOS; 1027997883Sgibbs hs_mailbox |= ahd->tqinfifonext & HOST_TQINPOS; 1028097883Sgibbs ahd_outb(ahd, HS_MAILBOX, hs_mailbox); 1028197883Sgibbs } 1028297883Sgibbs } 1028397883Sgibbs} 1028497883Sgibbs 1028597883Sgibbsstatic int 1028697883Sgibbsahd_handle_target_cmd(struct ahd_softc *ahd, struct target_cmd *cmd) 1028797883Sgibbs{ 1028897883Sgibbs struct ahd_tmode_tstate *tstate; 1028997883Sgibbs struct ahd_tmode_lstate *lstate; 1029097883Sgibbs struct ccb_accept_tio *atio; 1029197883Sgibbs uint8_t *byte; 1029297883Sgibbs int initiator; 1029397883Sgibbs int target; 1029497883Sgibbs int lun; 1029597883Sgibbs 1029697883Sgibbs initiator = SCSIID_TARGET(ahd, cmd->scsiid); 1029797883Sgibbs target = SCSIID_OUR_ID(cmd->scsiid); 1029897883Sgibbs lun = (cmd->identify & MSG_IDENTIFY_LUNMASK); 1029997883Sgibbs 1030097883Sgibbs byte = cmd->bytes; 1030197883Sgibbs tstate = ahd->enabled_targets[target]; 1030297883Sgibbs lstate = NULL; 1030397883Sgibbs if (tstate != NULL) 1030497883Sgibbs lstate = tstate->enabled_luns[lun]; 1030597883Sgibbs 1030697883Sgibbs /* 1030797883Sgibbs * Commands for disabled luns go to the black hole driver. 1030897883Sgibbs */ 1030997883Sgibbs if (lstate == NULL) 1031097883Sgibbs lstate = ahd->black_hole; 1031197883Sgibbs 1031297883Sgibbs atio = (struct ccb_accept_tio*)SLIST_FIRST(&lstate->accept_tios); 1031397883Sgibbs if (atio == NULL) { 1031497883Sgibbs ahd->flags |= AHD_TQINFIFO_BLOCKED; 1031597883Sgibbs /* 1031697883Sgibbs * Wait for more ATIOs from the peripheral driver for this lun. 1031797883Sgibbs */ 1031897883Sgibbs return (1); 1031997883Sgibbs } else 1032097883Sgibbs ahd->flags &= ~AHD_TQINFIFO_BLOCKED; 1032197883Sgibbs#ifdef AHD_DEBUG 1032297883Sgibbs if ((ahd_debug & AHD_SHOW_TQIN) != 0) 1032397883Sgibbs printf("Incoming command from %d for %d:%d%s\n", 1032497883Sgibbs initiator, target, lun, 1032597883Sgibbs lstate == ahd->black_hole ? "(Black Holed)" : ""); 1032697883Sgibbs#endif 1032797883Sgibbs SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle); 1032897883Sgibbs 1032997883Sgibbs if (lstate == ahd->black_hole) { 1033097883Sgibbs /* Fill in the wildcards */ 1033197883Sgibbs atio->ccb_h.target_id = target; 1033297883Sgibbs atio->ccb_h.target_lun = lun; 1033397883Sgibbs } 1033497883Sgibbs 1033597883Sgibbs /* 1033697883Sgibbs * Package it up and send it off to 1033797883Sgibbs * whomever has this lun enabled. 1033897883Sgibbs */ 1033997883Sgibbs atio->sense_len = 0; 1034097883Sgibbs atio->init_id = initiator; 1034197883Sgibbs if (byte[0] != 0xFF) { 1034297883Sgibbs /* Tag was included */ 1034397883Sgibbs atio->tag_action = *byte++; 1034497883Sgibbs atio->tag_id = *byte++; 1034597883Sgibbs atio->ccb_h.flags = CAM_TAG_ACTION_VALID; 1034697883Sgibbs } else { 1034797883Sgibbs atio->ccb_h.flags = 0; 1034897883Sgibbs } 1034997883Sgibbs byte++; 1035097883Sgibbs 1035197883Sgibbs /* Okay. Now determine the cdb size based on the command code */ 1035297883Sgibbs switch (*byte >> CMD_GROUP_CODE_SHIFT) { 1035397883Sgibbs case 0: 1035497883Sgibbs atio->cdb_len = 6; 1035597883Sgibbs break; 1035697883Sgibbs case 1: 1035797883Sgibbs case 2: 1035897883Sgibbs atio->cdb_len = 10; 1035997883Sgibbs break; 1036097883Sgibbs case 4: 1036197883Sgibbs atio->cdb_len = 16; 1036297883Sgibbs break; 1036397883Sgibbs case 5: 1036497883Sgibbs atio->cdb_len = 12; 1036597883Sgibbs break; 1036697883Sgibbs case 3: 1036797883Sgibbs default: 1036897883Sgibbs /* Only copy the opcode. */ 1036997883Sgibbs atio->cdb_len = 1; 1037097883Sgibbs printf("Reserved or VU command code type encountered\n"); 1037197883Sgibbs break; 1037297883Sgibbs } 1037397883Sgibbs 1037497883Sgibbs memcpy(atio->cdb_io.cdb_bytes, byte, atio->cdb_len); 1037597883Sgibbs 1037697883Sgibbs atio->ccb_h.status |= CAM_CDB_RECVD; 1037797883Sgibbs 1037897883Sgibbs if ((cmd->identify & MSG_IDENTIFY_DISCFLAG) == 0) { 1037997883Sgibbs /* 1038097883Sgibbs * We weren't allowed to disconnect. 1038197883Sgibbs * We're hanging on the bus until a 1038297883Sgibbs * continue target I/O comes in response 1038397883Sgibbs * to this accept tio. 1038497883Sgibbs */ 1038597883Sgibbs#ifdef AHD_DEBUG 1038697883Sgibbs if ((ahd_debug & AHD_SHOW_TQIN) != 0) 1038797883Sgibbs printf("Received Immediate Command %d:%d:%d - %p\n", 1038897883Sgibbs initiator, target, lun, ahd->pending_device); 1038997883Sgibbs#endif 1039097883Sgibbs ahd->pending_device = lstate; 1039197883Sgibbs ahd_freeze_ccb((union ccb *)atio); 1039297883Sgibbs atio->ccb_h.flags |= CAM_DIS_DISCONNECT; 1039397883Sgibbs } 1039497883Sgibbs xpt_done((union ccb*)atio); 1039597883Sgibbs return (0); 1039697883Sgibbs} 1039797883Sgibbs 1039897883Sgibbs#endif 10399