11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Core routines and tables shareable across OS platforms. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 1994-2002 Justin T. Gibbs. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2000-2003 Adaptec Inc. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All rights reserved. 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Redistribution and use in source and binary forms, with or without 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modification, are permitted provided that the following conditions 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are met: 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1. Redistributions of source code must retain the above copyright 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * notice, this list of conditions, and the following disclaimer, 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * without modification. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2. Redistributions in binary form must reproduce at minimum a disclaimer 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * substantially similar to the "NO WARRANTY" disclaimer below 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ("Disclaimer") and any redistribution must be conditioned upon 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * including a substantially similar Disclaimer requirement for further 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * binary redistribution. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3. Neither the names of the above-listed copyright holders nor the names 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of any contributors may be used to endorse or promote products derived 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from this software without specific prior written permission. 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Alternatively, this software may be distributed under the terms of the 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License ("GPL") version 2 as published by the Free 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Software Foundation. 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NO WARRANTY 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * POSSIBILITY OF SUCH DAMAGES. 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#250 $ 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __linux__ 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "aic79xx_osm.h" 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "aic79xx_inline.h" 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "aicasm/aicasm_insformat.h" 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <dev/aic7xxx/aic79xx_osm.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <dev/aic7xxx/aic79xx_inline.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <dev/aic7xxx/aicasm/aicasm_insformat.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***************************** Lookup Tables **********************************/ 55980b306a297725d4f25c779ca15086de757acadfDenys Vlasenkostatic const char *const ahd_chip_names[] = 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "NONE", 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "aic7901", 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "aic7902", 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "aic7901A" 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 626391a11375de5e2bb1eb8481e54619761dc65d9fTobias Klauserstatic const u_int num_chip_names = ARRAY_SIZE(ahd_chip_names); 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Hardware error codes. 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ahd_hard_error_entry { 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t errno; 69980b306a297725d4f25c779ca15086de757acadfDenys Vlasenko const char *errmesg; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 72980b306a297725d4f25c779ca15086de757acadfDenys Vlasenkostatic const struct ahd_hard_error_entry ahd_hard_errors[] = { 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { DSCTMOUT, "Discard Timer has timed out" }, 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { ILLOPCODE, "Illegal Opcode in sequencer program" }, 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { SQPARERR, "Sequencer Parity Error" }, 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { DPARERR, "Data-path Parity Error" }, 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { MPARERR, "Scratch or SCB Memory Parity Error" }, 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { CIOPARERR, "CIOBUS Parity Error" }, 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 806391a11375de5e2bb1eb8481e54619761dc65d9fTobias Klauserstatic const u_int num_errors = ARRAY_SIZE(ahd_hard_errors); 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 82980b306a297725d4f25c779ca15086de757acadfDenys Vlasenkostatic const struct ahd_phase_table_entry ahd_phase_table[] = 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { P_DATAOUT, MSG_NOOP, "in Data-out phase" }, 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { P_DATAIN, MSG_INITIATOR_DET_ERR, "in Data-in phase" }, 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { P_DATAOUT_DT, MSG_NOOP, "in DT Data-out phase" }, 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { P_DATAIN_DT, MSG_INITIATOR_DET_ERR, "in DT Data-in phase" }, 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { P_COMMAND, MSG_NOOP, "in Command phase" }, 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { P_MESGOUT, MSG_NOOP, "in Message-out phase" }, 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { P_STATUS, MSG_INITIATOR_DET_ERR, "in Status phase" }, 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { P_MESGIN, MSG_PARITY_ERROR, "in Message-in phase" }, 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { P_BUSFREE, MSG_NOOP, "while idle" }, 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0, MSG_NOOP, "in unknown phase" } 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In most cases we only wish to itterate over real phases, so 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * exclude the last element from the count. 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1006391a11375de5e2bb1eb8481e54619761dc65d9fTobias Klauserstatic const u_int num_phases = ARRAY_SIZE(ahd_phase_table) - 1; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Our Sequencer Program */ 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "aic79xx_seq.h" 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**************************** Function Declarations ***************************/ 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_handle_transmission_error(struct ahd_softc *ahd); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_handle_lqiphase_error(struct ahd_softc *ahd, 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lqistat1); 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ahd_handle_pkt_busfree(struct ahd_softc *ahd, 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int busfreetime); 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ahd_handle_nonpkt_busfree(struct ahd_softc *ahd); 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_handle_proto_violation(struct ahd_softc *ahd); 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_force_renegotiation(struct ahd_softc *ahd, 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo *devinfo); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ahd_tmode_tstate* 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_alloc_tstate(struct ahd_softc *ahd, 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scsi_id, char channel); 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_TARGET_MODE 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_free_tstate(struct ahd_softc *ahd, 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scsi_id, char channel, int force); 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_devlimited_syncrate(struct ahd_softc *ahd, 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_initiator_tinfo *, 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int *period, 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int *ppr_options, 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds role_t role); 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_update_neg_table(struct ahd_softc *ahd, 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo *devinfo, 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_transinfo *tinfo); 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_update_pending_scbs(struct ahd_softc *ahd); 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_fetch_devinfo(struct ahd_softc *ahd, 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo *devinfo); 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_scb_devinfo(struct ahd_softc *ahd, 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo *devinfo, 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb); 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_setup_initiator_msgout(struct ahd_softc *ahd, 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo *devinfo, 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_build_transfer_msg(struct ahd_softc *ahd, 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo *devinfo); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_construct_sdtr(struct ahd_softc *ahd, 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo *devinfo, 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int period, u_int offset); 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_construct_wdtr(struct ahd_softc *ahd, 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo *devinfo, 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int bus_width); 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_construct_ppr(struct ahd_softc *ahd, 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo *devinfo, 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int period, u_int offset, 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int bus_width, u_int ppr_options); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_clear_msg_state(struct ahd_softc *ahd); 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_handle_message_phase(struct ahd_softc *ahd); 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef enum { 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHDMSG_1B, 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHDMSG_2B, 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHDMSG_EXT 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} ahd_msgtype; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ahd_sent_msg(struct ahd_softc *ahd, ahd_msgtype type, 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int msgval, int full); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ahd_parse_msg(struct ahd_softc *ahd, 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo *devinfo); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ahd_handle_msg_reject(struct ahd_softc *ahd, 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo *devinfo); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_handle_ign_wide_residue(struct ahd_softc *ahd, 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo *devinfo); 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_reinitialize_dataptrs(struct ahd_softc *ahd); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_handle_devreset(struct ahd_softc *ahd, 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo *devinfo, 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lun, cam_status status, 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *message, int verbose_level); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_TARGET_MODE 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_setup_target_msgin(struct ahd_softc *ahd, 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo *devinfo, 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int ahd_sglist_size(struct ahd_softc *ahd); 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int ahd_sglist_allocsize(struct ahd_softc *ahd); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic bus_dmamap_callback_t 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dmamap_cb; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_initialize_hscbs(struct ahd_softc *ahd); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ahd_init_scbdata(struct ahd_softc *ahd); 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_fini_scbdata(struct ahd_softc *ahd); 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_setup_iocell_workaround(struct ahd_softc *ahd); 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_iocell_first_selection(struct ahd_softc *ahd); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_add_col_list(struct ahd_softc *ahd, 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb, u_int col_idx); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_rem_col_list(struct ahd_softc *ahd, 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_chip_init(struct ahd_softc *ahd); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_qinfifo_requeue(struct ahd_softc *ahd, 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *prev_scb, 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ahd_qinfifo_count(struct ahd_softc *ahd); 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ahd_search_scb_list(struct ahd_softc *ahd, int target, 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char channel, int lun, u_int tag, 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds role_t role, uint32_t status, 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_search_action action, 20053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke u_int *list_head, u_int *list_tail, 20153467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke u_int tid); 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_stitch_tid_list(struct ahd_softc *ahd, 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int tid_prev, u_int tid_cur, 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int tid_next); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_add_scb_to_free_list(struct ahd_softc *ahd, 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid); 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid, 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int prev, u_int next, u_int tid); 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_reset_current_bus(struct ahd_softc *ahd); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ahd_callback_t ahd_stat_timer; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DUMP_SEQ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_dumpseq(struct ahd_softc *ahd); 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_loadseq(struct ahd_softc *ahd); 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ahd_check_patch(struct ahd_softc *ahd, 216980b306a297725d4f25c779ca15086de757acadfDenys Vlasenko const struct patch **start_patch, 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int start_instr, u_int *skip_addr); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int ahd_resolve_seqaddr(struct ahd_softc *ahd, 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int address); 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_download_instr(struct ahd_softc *ahd, 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int instrptr, uint8_t *dconsts); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ahd_probe_stack_size(struct ahd_softc *ahd); 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ahd_scb_active_in_fifo(struct ahd_softc *ahd, 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb); 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_run_data_fifo(struct ahd_softc *ahd, 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb); 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_TARGET_MODE 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_queue_lstate_event(struct ahd_softc *ahd, 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_lstate *lstate, 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int initiator_id, 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int event_type, 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int event_arg); 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_update_scsiid(struct ahd_softc *ahd, 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int targid_mask); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ahd_handle_target_cmd(struct ahd_softc *ahd, 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct target_cmd *cmd); 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 240289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic int ahd_abort_scbs(struct ahd_softc *ahd, int target, 241289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk char channel, int lun, u_int tag, 242289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk role_t role, uint32_t status); 243289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void ahd_alloc_scbs(struct ahd_softc *ahd); 244289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void ahd_busy_tcl(struct ahd_softc *ahd, u_int tcl, 245289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk u_int scbid); 246289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void ahd_calc_residual(struct ahd_softc *ahd, 247289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk struct scb *scb); 248289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void ahd_clear_critical_section(struct ahd_softc *ahd); 249289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void ahd_clear_intstat(struct ahd_softc *ahd); 250289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void ahd_enable_coalescing(struct ahd_softc *ahd, 251289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk int enable); 252289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic u_int ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl); 253289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void ahd_freeze_devq(struct ahd_softc *ahd, 254289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk struct scb *scb); 255289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void ahd_handle_scb_status(struct ahd_softc *ahd, 256289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk struct scb *scb); 257980b306a297725d4f25c779ca15086de757acadfDenys Vlasenkostatic const struct ahd_phase_table_entry* ahd_lookup_phase_entry(int phase); 258289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void ahd_shutdown(void *arg); 259289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void ahd_update_coalescing_values(struct ahd_softc *ahd, 260289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk u_int timer, 261289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk u_int maxcmds, 262289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk u_int mincmds); 263289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic int ahd_verify_vpd_cksum(struct vpd_config *vpd); 264289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic int ahd_wait_seeprom(struct ahd_softc *ahd); 265a76106afbeb0c7d50762e7e5239496e5f7a0a074Adrian Bunkstatic int ahd_match_scb(struct ahd_softc *ahd, struct scb *scb, 266a76106afbeb0c7d50762e7e5239496e5f7a0a074Adrian Bunk int target, char channel, int lun, 267a76106afbeb0c7d50762e7e5239496e5f7a0a074Adrian Bunk u_int tag, role_t role); 268289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 269d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void ahd_reset_cmds_pending(struct ahd_softc *ahd); 270d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenko 271d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenko/*************************** Interrupt Services *******************************/ 272d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void ahd_run_qoutfifo(struct ahd_softc *ahd); 273d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenko#ifdef AHD_TARGET_MODE 274d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void ahd_run_tqinfifo(struct ahd_softc *ahd, int paused); 275d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenko#endif 276d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void ahd_handle_hwerrint(struct ahd_softc *ahd); 277d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat); 278d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void ahd_handle_scsiint(struct ahd_softc *ahd, 279d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenko u_int intstat); 280d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenko 281be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko/************************ Sequencer Execution Control *************************/ 282be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkovoid 283be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) 284be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 285be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (ahd->src_mode == src && ahd->dst_mode == dst) 286be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return; 287be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#ifdef AHD_DEBUG 288be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (ahd->src_mode == AHD_MODE_UNKNOWN 289be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko || ahd->dst_mode == AHD_MODE_UNKNOWN) 290be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko panic("Setting mode prior to saving it.\n"); 291be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((ahd_debug & AHD_SHOW_MODEPTR) != 0) 29248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Setting mode 0x%x\n", ahd_name(ahd), 293be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_build_mode_state(ahd, src, dst)); 294be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#endif 295be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst)); 296be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd->src_mode = src; 297be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd->dst_mode = dst; 298be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 299be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 300d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 301be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_update_modes(struct ahd_softc *ahd) 302be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 303be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_mode_state mode_ptr; 304be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_mode src; 305be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_mode dst; 306be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 307be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko mode_ptr = ahd_inb(ahd, MODE_PTR); 308be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#ifdef AHD_DEBUG 309be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((ahd_debug & AHD_SHOW_MODEPTR) != 0) 31048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Reading mode 0x%x\n", mode_ptr); 311be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#endif 312be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_extract_mode_state(ahd, mode_ptr, &src, &dst); 313be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_known_modes(ahd, src, dst); 314be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 315be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 316d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 317be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode, 318be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_mode dstmode, const char *file, int line) 319be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 320be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#ifdef AHD_DEBUG 321be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((srcmode & AHD_MK_MSK(ahd->src_mode)) == 0 322be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko || (dstmode & AHD_MK_MSK(ahd->dst_mode)) == 0) { 323be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko panic("%s:%s:%d: Mode assertion failed.\n", 324be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_name(ahd), file, line); 325be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } 326be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#endif 327be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 328be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 329be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#define AHD_ASSERT_MODES(ahd, source, dest) \ 330be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_assert_modes(ahd, source, dest, __FILE__, __LINE__); 331be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 332be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_mode_state 333be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_save_modes(struct ahd_softc *ahd) 334be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 335be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (ahd->src_mode == AHD_MODE_UNKNOWN 336be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko || ahd->dst_mode == AHD_MODE_UNKNOWN) 337be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_update_modes(ahd); 338be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 339be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (ahd_build_mode_state(ahd, ahd->src_mode, ahd->dst_mode)); 340be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 341be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 342be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkovoid 343be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_restore_modes(struct ahd_softc *ahd, ahd_mode_state state) 344be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 345be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_mode src; 346be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_mode dst; 347be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 348be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_extract_mode_state(ahd, state, &src, &dst); 349be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_set_modes(ahd, src, dst); 350be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 351be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 352be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko/* 353be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Determine whether the sequencer has halted code execution. 354be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Returns non-zero status if the sequencer is stopped. 355be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 356be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoint 357be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_is_paused(struct ahd_softc *ahd) 358be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 359be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return ((ahd_inb(ahd, HCNTRL) & PAUSE) != 0); 360be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 361be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 362be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko/* 363be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Request that the sequencer stop and wait, indefinitely, for it 364be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * to stop. The sequencer will only acknowledge that it is paused 365be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * once it has reached an instruction boundary and PAUSEDIS is 366be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * cleared in the SEQCTL register. The sequencer may use PAUSEDIS 367be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * for critical sections. 368be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 369be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkovoid 370be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_pause(struct ahd_softc *ahd) 371be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 372be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, HCNTRL, ahd->pause); 373be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 374be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* 375be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Since the sequencer can disable pausing in a critical section, we 376be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * must loop until it actually stops. 377be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 378be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko while (ahd_is_paused(ahd) == 0) 379be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ; 380be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 381be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 382be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko/* 383be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Allow the sequencer to continue program execution. 384be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * We check here to ensure that no additional interrupt 385be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * sources that would cause the sequencer to halt have been 386be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * asserted. If, for example, a SCSI bus reset is detected 387be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * while we are fielding a different, pausing, interrupt type, 388be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * we don't want to release the sequencer before going back 389be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * into our interrupt handler and dealing with this new 390be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * condition. 391be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 392be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkovoid 393be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_unpause(struct ahd_softc *ahd) 394be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 395be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* 396be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Automatically restore our modes to those saved 397be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * prior to the first change of the mode. 398be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 399be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (ahd->saved_src_mode != AHD_MODE_UNKNOWN 400be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko && ahd->saved_dst_mode != AHD_MODE_UNKNOWN) { 401be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((ahd->flags & AHD_UPDATE_PEND_CMDS) != 0) 402be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_reset_cmds_pending(ahd); 403be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); 404be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } 405be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 406be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((ahd_inb(ahd, INTSTAT) & ~CMDCMPLT) == 0) 407be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, HCNTRL, ahd->unpause); 408be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 409be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN); 410be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 411be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 412be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko/*********************** Scatter Gather List Handling *************************/ 413be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkovoid * 414be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_sg_setup(struct ahd_softc *ahd, struct scb *scb, 415be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko void *sgptr, dma_addr_t addr, bus_size_t len, int last) 416be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 417be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->sg_count++; 418be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (sizeof(dma_addr_t) > 4 419be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko && (ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 420be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko struct ahd_dma64_seg *sg; 421be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 422be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko sg = (struct ahd_dma64_seg *)sgptr; 423be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko sg->addr = ahd_htole64(addr); 424be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko sg->len = ahd_htole32(len | (last ? AHD_DMA_LAST_SEG : 0)); 425be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (sg + 1); 426be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } else { 427be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko struct ahd_dma_seg *sg; 428be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 429be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko sg = (struct ahd_dma_seg *)sgptr; 430be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko sg->addr = ahd_htole32(addr & 0xFFFFFFFF); 431be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000) 432be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko | (last ? AHD_DMA_LAST_SEG : 0)); 433be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (sg + 1); 434be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } 435be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 436be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 437d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 438be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb) 439be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 440be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* XXX Handle target mode SCBs. */ 441be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->crc_retry_count = 0; 442be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((scb->flags & SCB_PACKETIZED) != 0) { 443be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */ 444be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->hscb->task_attribute = scb->hscb->control & SCB_TAG_TYPE; 445be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } else { 446be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (ahd_get_transfer_length(scb) & 0x01) 447be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->hscb->task_attribute = SCB_XFERLEN_ODD; 448be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko else 449be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->hscb->task_attribute = 0; 450be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } 451be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 452be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR 453be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko || (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0) 454be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr = 455be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_htole32(scb->sense_busaddr); 456be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 457be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 458d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 459be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb) 460be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 461be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* 462be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Copy the first SG into the "current" data ponter area. 463be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 464be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 465be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko struct ahd_dma64_seg *sg; 466be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 467be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko sg = (struct ahd_dma64_seg *)scb->sg_list; 468be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->hscb->dataptr = sg->addr; 469be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->hscb->datacnt = sg->len; 470be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } else { 471be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko struct ahd_dma_seg *sg; 472be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko uint32_t *dataptr_words; 473be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 474be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko sg = (struct ahd_dma_seg *)scb->sg_list; 475be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko dataptr_words = (uint32_t*)&scb->hscb->dataptr; 476be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko dataptr_words[0] = sg->addr; 477be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko dataptr_words[1] = 0; 478be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) { 479be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko uint64_t high_addr; 480be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 481be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko high_addr = ahd_le32toh(sg->len) & 0x7F000000; 482be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->hscb->dataptr |= ahd_htole64(high_addr << 8); 483be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } 484be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->hscb->datacnt = sg->len; 485be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } 486be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* 487be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Note where to find the SG entries in bus space. 488be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * We also set the full residual flag which the 489be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * sequencer will clear as soon as a data transfer 490be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * occurs. 491be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 492be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID); 493be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 494be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 495d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 496be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb) 497be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 498be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->hscb->sgptr = ahd_htole32(SG_LIST_NULL); 499be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->hscb->dataptr = 0; 500be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->hscb->datacnt = 0; 501be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 502be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 503be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko/************************** Memory mapping routines ***************************/ 504d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void * 505be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr) 506be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 507be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko dma_addr_t sg_offset; 508be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 509be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* sg_list_phys points to entry 1, not 0 */ 510be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko sg_offset = sg_busaddr - (scb->sg_list_busaddr - ahd_sg_size(ahd)); 511be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return ((uint8_t *)scb->sg_list + sg_offset); 512be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 513be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 514d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic uint32_t 515be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg) 516be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 517be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko dma_addr_t sg_offset; 518be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 519be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* sg_list_phys points to entry 1, not 0 */ 520be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko sg_offset = ((uint8_t *)sg - (uint8_t *)scb->sg_list) 521be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko - ahd_sg_size(ahd); 522be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 523be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (scb->sg_list_busaddr + sg_offset); 524be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 525be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 526d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 527be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op) 528be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 529be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_dmamap_sync(ahd, ahd->scb_data.hscb_dmat, 530be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->hscb_map->dmamap, 531be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /*offset*/(uint8_t*)scb->hscb - scb->hscb_map->vaddr, 532be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /*len*/sizeof(*scb->hscb), op); 533be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 534be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 535be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkovoid 536be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op) 537be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 538be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (scb->sg_count == 0) 539be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return; 540be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 541be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_dmamap_sync(ahd, ahd->scb_data.sg_dmat, 542be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->sg_map->dmamap, 543be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /*offset*/scb->sg_list_busaddr - ahd_sg_size(ahd), 544be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /*len*/ahd_sg_size(ahd) * scb->sg_count, op); 545be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 546be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 547d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 548be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op) 549be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 550be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_dmamap_sync(ahd, ahd->scb_data.sense_dmat, 551be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->sense_map->dmamap, 552be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /*offset*/scb->sense_busaddr, 553be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /*len*/AHD_SENSE_BUFSIZE, op); 554be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 555be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 556d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenko#ifdef AHD_TARGET_MODE 557d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic uint32_t 558be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_targetcmd_offset(struct ahd_softc *ahd, u_int index) 559be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 560be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (((uint8_t *)&ahd->targetcmds[index]) 561be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko - (uint8_t *)ahd->qoutfifo); 562be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 563d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenko#endif 564be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 56525985edcedea6396277003854657b5f3cb31a628Lucas De Marchi/*********************** Miscellaneous Support Functions ***********************/ 566be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko/* 567be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Return pointers to the transfer negotiation information 568be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * for the specified our_id/remote_id pair. 569be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 570be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkostruct ahd_initiator_tinfo * 571be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id, 572be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko u_int remote_id, struct ahd_tmode_tstate **tstate) 573be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 574be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* 575be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Transfer data structures are stored from the perspective 576be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * of the target role. Since the parameters for a connection 577be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * in the initiator role to a given target are the same as 578be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * when the roles are reversed, we pretend we are the target. 579be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 580be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (channel == 'B') 581be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko our_id += 8; 582be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko *tstate = ahd->enabled_targets[our_id]; 583be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (&(*tstate)->transinfo[remote_id]); 584be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 585be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 586be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkouint16_t 587be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_inw(struct ahd_softc *ahd, u_int port) 588be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 589be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* 590be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Read high byte first as some registers increment 591be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * or have other side effects when the low byte is 592be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * read. 593be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 594be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko uint16_t r = ahd_inb(ahd, port+1) << 8; 595be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return r | ahd_inb(ahd, port); 596be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 597be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 598be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkovoid 599be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_outw(struct ahd_softc *ahd, u_int port, u_int value) 600be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 601be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* 60225985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Write low byte first to accommodate registers 603be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * such as PRGMCNT where the order maters. 604be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 605be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, port, value & 0xFF); 606be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, port+1, (value >> 8) & 0xFF); 607be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 608be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 609be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkouint32_t 610be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_inl(struct ahd_softc *ahd, u_int port) 611be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 612be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return ((ahd_inb(ahd, port)) 613be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko | (ahd_inb(ahd, port+1) << 8) 614be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko | (ahd_inb(ahd, port+2) << 16) 615be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko | (ahd_inb(ahd, port+3) << 24)); 616be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 617be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 618be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkovoid 619be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value) 620be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 621be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, port, (value) & 0xFF); 622be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF); 623be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF); 624be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF); 625be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 626be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 627be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkouint64_t 628be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_inq(struct ahd_softc *ahd, u_int port) 629be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 630be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return ((ahd_inb(ahd, port)) 631be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko | (ahd_inb(ahd, port+1) << 8) 632be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko | (ahd_inb(ahd, port+2) << 16) 633be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko | (ahd_inb(ahd, port+3) << 24) 634be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko | (((uint64_t)ahd_inb(ahd, port+4)) << 32) 635be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko | (((uint64_t)ahd_inb(ahd, port+5)) << 40) 636be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko | (((uint64_t)ahd_inb(ahd, port+6)) << 48) 637be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko | (((uint64_t)ahd_inb(ahd, port+7)) << 56)); 638be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 639be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 640be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkovoid 641be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value) 642be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 643be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, port, value & 0xFF); 644be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, port+1, (value >> 8) & 0xFF); 645be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, port+2, (value >> 16) & 0xFF); 646be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, port+3, (value >> 24) & 0xFF); 647be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, port+4, (value >> 32) & 0xFF); 648be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, port+5, (value >> 40) & 0xFF); 649be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, port+6, (value >> 48) & 0xFF); 650be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, port+7, (value >> 56) & 0xFF); 651be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 652be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 653be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkou_int 654be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_get_scbptr(struct ahd_softc *ahd) 655be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 656be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 657be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 658be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8)); 659be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 660be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 661be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkovoid 662be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr) 663be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 664be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 665be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 666be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, SCBPTR, scbptr & 0xFF); 667be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF); 668be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 669be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 670d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenko#if 0 /* unused */ 671d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic u_int 672be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_get_hnscb_qoff(struct ahd_softc *ahd) 673be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 674be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (ahd_inw_atomic(ahd, HNSCB_QOFF)); 675be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 676d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenko#endif 677be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 678d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 679be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value) 680be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 681be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outw_atomic(ahd, HNSCB_QOFF, value); 682be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 683be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 684d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenko#if 0 /* unused */ 685d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic u_int 686be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_get_hescb_qoff(struct ahd_softc *ahd) 687be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 688be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (ahd_inb(ahd, HESCB_QOFF)); 689be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 690d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenko#endif 691be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 692d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 693be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value) 694be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 695be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, HESCB_QOFF, value); 696be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 697be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 698d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic u_int 699be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_get_snscb_qoff(struct ahd_softc *ahd) 700be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 701be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko u_int oldvalue; 702be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 703be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 704be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko oldvalue = ahd_inw(ahd, SNSCB_QOFF); 705be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outw(ahd, SNSCB_QOFF, oldvalue); 706be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (oldvalue); 707be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 708be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 709d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 710be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value) 711be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 712be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 713be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outw(ahd, SNSCB_QOFF, value); 714be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 715be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 716d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenko#if 0 /* unused */ 717d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic u_int 718be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_get_sescb_qoff(struct ahd_softc *ahd) 719be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 720be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 721be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (ahd_inb(ahd, SESCB_QOFF)); 722be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 723d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenko#endif 724be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 725d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 726be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value) 727be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 728be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 729be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, SESCB_QOFF, value); 730be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 731be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 732d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenko#if 0 /* unused */ 733d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic u_int 734be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_get_sdscb_qoff(struct ahd_softc *ahd) 735be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 736be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 737be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8)); 738be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 739d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenko#endif 740be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 741d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 742be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value) 743be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 744be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 745be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, SDSCB_QOFF, value & 0xFF); 746be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF); 747be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 748be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 749be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkou_int 750be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_inb_scbram(struct ahd_softc *ahd, u_int offset) 751be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 752be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko u_int value; 753be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 754be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* 755be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Workaround PCI-X Rev A. hardware bug. 756be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * After a host read of SCB memory, the chip 757be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * may become confused into thinking prefetch 758be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * was required. This starts the discard timer 759be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * running and can cause an unexpected discard 760be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * timer interrupt. The work around is to read 761be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * a normal register prior to the exhaustion of 762be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * the discard timer. The mode pointer register 763be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * has no side effects and so serves well for 764be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * this purpose. 765be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * 766be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Razor #528 767be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 768be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko value = ahd_inb(ahd, offset); 769be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((ahd->bugs & AHD_PCIX_SCBRAM_RD_BUG) != 0) 770be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_inb(ahd, MODE_PTR); 771be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (value); 772be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 773be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 774be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkou_int 775be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_inw_scbram(struct ahd_softc *ahd, u_int offset) 776be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 777be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (ahd_inb_scbram(ahd, offset) 778be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko | (ahd_inb_scbram(ahd, offset+1) << 8)); 779be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 780be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 781d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic uint32_t 782be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_inl_scbram(struct ahd_softc *ahd, u_int offset) 783be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 784be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (ahd_inw_scbram(ahd, offset) 785be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko | (ahd_inw_scbram(ahd, offset+2) << 16)); 786be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 787be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 788d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic uint64_t 789be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_inq_scbram(struct ahd_softc *ahd, u_int offset) 790be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 791be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (ahd_inl_scbram(ahd, offset) 792be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko | ((uint64_t)ahd_inl_scbram(ahd, offset+4)) << 32); 793be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 794be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 795be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkostruct scb * 796be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_lookup_scb(struct ahd_softc *ahd, u_int tag) 797be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 798be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko struct scb* scb; 799be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 800be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (tag >= AHD_SCB_MAX) 801be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (NULL); 802be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb = ahd->scb_data.scbindex[tag]; 803be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (scb != NULL) 804be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_sync_scb(ahd, scb, 805be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 806be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (scb); 807be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 808be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 809d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 810be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb) 811be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 812be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko struct hardware_scb *q_hscb; 813be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko struct map_node *q_hscb_map; 814be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko uint32_t saved_hscb_busaddr; 815be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 816be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* 817be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Our queuing method is a bit tricky. The card 818be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * knows in advance which HSCB (by address) to download, 819be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * and we can't disappoint it. To achieve this, the next 820be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * HSCB to download is saved off in ahd->next_queued_hscb. 821be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * When we are called to queue "an arbitrary scb", 822be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * we copy the contents of the incoming HSCB to the one 823be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * the sequencer knows about, swap HSCB pointers and 824be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * finally assign the SCB to the tag indexed location 825be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * in the scb_array. This makes sure that we can still 826be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * locate the correct SCB by SCB_TAG. 827be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 828be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko q_hscb = ahd->next_queued_hscb; 829be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko q_hscb_map = ahd->next_queued_hscb_map; 830be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko saved_hscb_busaddr = q_hscb->hscb_busaddr; 831be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb)); 832be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko q_hscb->hscb_busaddr = saved_hscb_busaddr; 833be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr; 834be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 835be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* Now swap HSCB pointers. */ 836be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd->next_queued_hscb = scb->hscb; 837be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd->next_queued_hscb_map = scb->hscb_map; 838be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->hscb = q_hscb; 839be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko scb->hscb_map = q_hscb_map; 840be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 841be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* Now define the mapping from tag to SCB in the scbindex */ 842be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb; 843be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 844be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 845be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko/* 846be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Tell the sequencer about a new transaction to execute. 847be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 848be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkovoid 849be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_queue_scb(struct ahd_softc *ahd, struct scb *scb) 850be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 851be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_swap_with_next_hscb(ahd, scb); 852be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 853be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (SCBID_IS_NULL(SCB_GET_TAG(scb))) 854be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko panic("Attempt to queue invalid SCB tag %x\n", 855be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko SCB_GET_TAG(scb)); 856be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 857be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* 858be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Keep a history of SCBs we've downloaded in the qinfifo. 859be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 860be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb); 861be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd->qinfifonext++; 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 863be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (scb->sg_count != 0) 864be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_setup_data_scb(ahd, scb); 865be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko else 866be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_setup_noxfer_scb(ahd, scb); 867be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_setup_scb_common(ahd, scb); 868be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 869be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* 870be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Make sure our data is consistent from the 871be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * perspective of the adapter. 872be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 873be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 874be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 875be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#ifdef AHD_DEBUG 876be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((ahd_debug & AHD_SHOW_QUEUE) != 0) { 877be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko uint64_t host_dataptr; 878be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 879be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko host_dataptr = ahd_le64toh(scb->hscb->dataptr); 88048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n", 881be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_name(ahd), 882be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko SCB_GET_TAG(scb), scb->hscb->scsiid, 883be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_le32toh(scb->hscb->hscb_busaddr), 884be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko (u_int)((host_dataptr >> 32) & 0xFFFFFFFF), 885be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko (u_int)(host_dataptr & 0xFFFFFFFF), 886be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_le32toh(scb->hscb->datacnt)); 887be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } 888be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#endif 889be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* Tell the adapter about the newly queued SCB */ 890be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); 891be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 892be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 893be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko/************************** Interrupt Processing ******************************/ 894d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 895be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_sync_qoutfifo(struct ahd_softc *ahd, int op) 896be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 897be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap, 898be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /*offset*/0, 899be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /*len*/AHD_SCB_MAX * sizeof(struct ahd_completion), op); 900be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 901be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 902d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 903be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_sync_tqinfifo(struct ahd_softc *ahd, int op) 904be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 905be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#ifdef AHD_TARGET_MODE 906be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((ahd->flags & AHD_TARGETROLE) != 0) { 907be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_dmamap_sync(ahd, ahd->shared_data_dmat, 908be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd->shared_data_map.dmamap, 909be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_targetcmd_offset(ahd, 0), 910be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko sizeof(struct target_cmd) * AHD_TMODE_CMDS, 911be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko op); 912be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } 913be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#endif 914be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 915be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 916be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko/* 917be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * See if the firmware has posted any completed commands 918be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * into our in-core command complete fifos. 919be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 920be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#define AHD_RUN_QOUTFIFO 0x1 921be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#define AHD_RUN_TQINFIFO 0x2 922d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic u_int 923be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_check_cmdcmpltqueues(struct ahd_softc *ahd) 924be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 925be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko u_int retval; 926be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 927be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko retval = 0; 928be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap, 929be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /*offset*/ahd->qoutfifonext * sizeof(*ahd->qoutfifo), 930be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /*len*/sizeof(*ahd->qoutfifo), BUS_DMASYNC_POSTREAD); 931be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (ahd->qoutfifo[ahd->qoutfifonext].valid_tag 932be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko == ahd->qoutfifonext_valid_tag) 933be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko retval |= AHD_RUN_QOUTFIFO; 934be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#ifdef AHD_TARGET_MODE 935be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((ahd->flags & AHD_TARGETROLE) != 0 936be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) { 937be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_dmamap_sync(ahd, ahd->shared_data_dmat, 938be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd->shared_data_map.dmamap, 939be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_targetcmd_offset(ahd, ahd->tqinfifofnext), 940be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /*len*/sizeof(struct target_cmd), 941be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko BUS_DMASYNC_POSTREAD); 942be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0) 943be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko retval |= AHD_RUN_TQINFIFO; 944be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } 945be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#endif 946be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (retval); 947be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 948be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 949be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko/* 950be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Catch an interrupt from the adapter 951be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 952be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoint 953be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_intr(struct ahd_softc *ahd) 954be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 955be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko u_int intstat; 956be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 957be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((ahd->pause & INTEN) == 0) { 958be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* 959be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Our interrupt is not enabled on the chip 960be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * and may be disabled for re-entrancy reasons, 961be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * so just return. This is likely just a shared 962be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * interrupt. 963be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 964be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (0); 965be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } 966be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 967be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* 968be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Instead of directly reading the interrupt status register, 969be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * infer the cause of the interrupt by checking our in-core 970be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * completion queues. This avoids a costly PCI bus read in 971be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * most cases. 972be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 973be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0 974be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko && (ahd_check_cmdcmpltqueues(ahd) != 0)) 975be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko intstat = CMDCMPLT; 976be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko else 977be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko intstat = ahd_inb(ahd, INTSTAT); 978be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 979be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((intstat & INT_PEND) == 0) 980be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (0); 981be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 982be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (intstat & CMDCMPLT) { 983be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_outb(ahd, CLRINT, CLRCMDINT); 984be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 985be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* 986be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Ensure that the chip sees that we've cleared 987be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * this interrupt before we walk the output fifo. 988be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Otherwise, we may, due to posted bus writes, 989be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * clear the interrupt after we finish the scan, 990be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * and after the sequencer has added new entries 991be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * and asserted the interrupt again. 992be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 993be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { 994be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (ahd_is_paused(ahd)) { 995be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* 996be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Potentially lost SEQINT. 997be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * If SEQINTCODE is non-zero, 998be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * simulate the SEQINT. 999be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 1000be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (ahd_inb(ahd, SEQINTCODE) != NO_SEQINT) 1001be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko intstat |= SEQINT; 1002be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } 1003be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } else { 1004be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_flush_device_writes(ahd); 1005be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } 1006be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_run_qoutfifo(ahd); 1007be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]++; 1008be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd->cmdcmplt_total++; 1009be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#ifdef AHD_TARGET_MODE 1010be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((ahd->flags & AHD_TARGETROLE) != 0) 1011be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_run_tqinfifo(ahd, /*paused*/FALSE); 1012be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#endif 1013be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } 1014be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 1015be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* 1016be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * Handle statuses that may invalidate our cached 1017be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko * copy of INTSTAT separately. 1018be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko */ 1019be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) { 1020be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko /* Hot eject. Do nothing */ 1021be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } else if (intstat & HWERRINT) { 1022be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_handle_hwerrint(ahd); 1023be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } else if ((intstat & (PCIINT|SPLTINT)) != 0) { 1024be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd->bus_intr(ahd); 1025be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } else { 1026be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 1027be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((intstat & SEQINT) != 0) 1028be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_handle_seqint(ahd, intstat); 1029be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 1030be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko if ((intstat & SCSIINT) != 0) 1031be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd_handle_scsiint(ahd, intstat); 1032be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko } 1033be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko return (1); 1034be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 1035be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 1036be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko/******************************** Private Inlines *****************************/ 10371beb6fa85ca9afaee109811a3f4a984232a32a4fHarvey Harrisonstatic inline void 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_assert_atn(struct ahd_softc *ahd) 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISIGO, ATNO); 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Determine if the current connection has a packetized 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * agreement. This does not necessarily mean that we 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are currently in a packetized transfer. We could 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * just as easily be sending or receiving a message. 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1049be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkostatic int 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_currently_packetized(struct ahd_softc *ahd) 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mode_state saved_modes; 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int packetized; 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_modes = ahd_save_modes(ahd); 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_PKTIZED_STATUS_BUG) != 0) { 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The packetized bit refers to the last 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * connection, not the current one. Check 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for non-zero LQISTATE instead. 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds packetized = ahd_inb(ahd, LQISTATE) != 0; 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds packetized = ahd_inb(ahd, LQISTAT2) & PACKETIZED; 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restore_modes(ahd, saved_modes); 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (packetized); 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10721beb6fa85ca9afaee109811a3f4a984232a32a4fHarvey Harrisonstatic inline int 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_set_active_fifo(struct ahd_softc *ahd) 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int active_fifo; 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds active_fifo = ahd_inb(ahd, DFFSTAT) & CURRFIFO; 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (active_fifo) { 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, active_fifo, active_fifo); 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (1); 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10891beb6fa85ca9afaee109811a3f4a984232a32a4fHarvey Harrisonstatic inline void 1090289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl) 1091289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk{ 1092289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk ahd_busy_tcl(ahd, tcl, SCB_LIST_NULL); 1093289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk} 1094289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 1095289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk/* 1096289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk * Determine whether the sequencer reported a residual 1097289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk * for this SCB/transaction. 1098289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk */ 10991beb6fa85ca9afaee109811a3f4a984232a32a4fHarvey Harrisonstatic inline void 1100289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkahd_update_residual(struct ahd_softc *ahd, struct scb *scb) 1101289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk{ 1102289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk uint32_t sgptr; 1103289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 1104289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk sgptr = ahd_le32toh(scb->hscb->sgptr); 1105289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk if ((sgptr & SG_STATUS_VALID) != 0) 1106289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk ahd_calc_residual(ahd, scb); 1107289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk} 1108289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 11091beb6fa85ca9afaee109811a3f4a984232a32a4fHarvey Harrisonstatic inline void 1110289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkahd_complete_scb(struct ahd_softc *ahd, struct scb *scb) 1111289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk{ 1112289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk uint32_t sgptr; 1113289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 1114289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk sgptr = ahd_le32toh(scb->hscb->sgptr); 1115289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk if ((sgptr & SG_STATUS_VALID) != 0) 1116289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk ahd_handle_scb_status(ahd, scb); 1117289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk else 1118289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk ahd_done(ahd, scb); 1119289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk} 1120289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 1121289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************* Sequencer Execution Control ************************/ 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Restart the sequencer program from address zero 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1126289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_restart(struct ahd_softc *ahd) 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pause(ahd); 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* No more pending messages */ 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_clear_msg_state(ahd); 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISIGO, 0); /* De-assert BSY */ 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, MSG_OUT, MSG_NOOP); /* No message to send */ 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SXFRCTL1, ahd_inb(ahd, SXFRCTL1) & ~BITBUCKET); 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEQINTCTL, 0); 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LASTPHASE, P_BUSFREE); 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEQ_FLAGS, 0); 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SAVED_SCSIID, 0xFF); 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SAVED_LUN, 0xFF); 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ensure that the sequencer's idea of TQINPOS 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * matches our own. The sequencer increments TQINPOS 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * only after it sees a DMA complete and a reset could 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * occur before the increment leaving the kernel to believe 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the command arrived but the sequencer to not. 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, TQINPOS, ahd->tqinfifonext); 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Always allow reselection */ 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ1, 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SCSISEQ_TEMPLATE) & (ENSELI|ENRSELI|ENAUTOATNP)); 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); 115811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 115911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 116011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Clear any pending sequencer interrupt. It is no 116111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * longer relevant since we're resetting the Program 116211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Counter. 116311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 116411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, CLRINT, CLRSEQINT); 116511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEQCTL0, FASTMODE|SEQRESET); 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1170289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_clear_fifo(struct ahd_softc *ahd, u_int fifo) 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mode_state saved_modes; 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_FIFOS) != 0) 117748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Clearing FIFO %d\n", ahd_name(ahd), fifo); 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_modes = ahd_save_modes(ahd); 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, fifo, fifo); 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, DFFSXFRCTL, RSTCHN|CLRSHCNT); 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0) 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CCSGCTL, CCSGRESET); 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR); 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SG_STATE, 0); 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restore_modes(ahd, saved_modes); 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************* Input/Output Queues ********************************/ 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Flush and completed commands that are sitting in the command 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * complete queues down on the chip but have yet to be dma'ed back up. 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1194289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_flush_qoutfifo(struct ahd_softc *ahd) 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mode_state saved_modes; 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int saved_scbptr; 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int ccscbctl; 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int next_scbid; 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_modes = ahd_save_modes(ahd); 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 120711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Flush the good status FIFO for completed packetized commands. 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_scbptr = ahd_get_scbptr(ahd); 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((ahd_inb(ahd, LQISTAT2) & LQIGSAVAIL) != 0) { 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int fifo_mode; 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int i; 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1215ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke scbid = ahd_inw(ahd, GSFIFO); 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb == NULL) { 121848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Warning - GSFIFO SCB %d invalid\n", 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), scbid); 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Determine if this transaction is still active in 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * any FIFO. If it is, we must flush that FIFO to 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the host before completing the command. 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_mode = 0; 122811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reineckerescan_fifos: 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 2; i++) { 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Toggle to the other mode. */ 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_mode ^= 1; 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, fifo_mode, fifo_mode); 123311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_scb_active_in_fifo(ahd, scb) == 0) 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_run_data_fifo(ahd, scb); 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 124011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Running this FIFO may cause a CFG4DATA for 124111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * this same transaction to assert in the other 124211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * FIFO or a new snapshot SAVEPTRS interrupt 124311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * in this FIFO. Even running a FIFO may not 124411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * clear the transaction if we are still waiting 124511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * for data to drain to the host. We must loop 124611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * until the transaction is not active in either 124711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * FIFO just to be sure. Reset our loop counter 124811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * so we will visit both FIFOs again before 124911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * declaring this transaction finished. We 125011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * also delay a bit so that status has a chance 125111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * to change before we look at this FIFO again. 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 125311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_delay(200); 125411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke goto rescan_fifos; 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, scbid); 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_inb_scbram(ahd, SCB_SGPTR) & SG_LIST_NULL) == 0 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ((ahd_inb_scbram(ahd, SCB_SGPTR) & SG_FULL_RESID) != 0 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR) 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds & SG_LIST_NULL) != 0)) { 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int comp_head; 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The transfer completed with a residual. 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Place this SCB on the complete DMA list 126711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * so that we update our in-core copy of the 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCB before completing the command. 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCB_SCSI_STATUS, 0); 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCB_SGPTR, 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_SGPTR) 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | SG_STATUS_VALID); 127411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outw(ahd, SCB_TAG, scbid); 127511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outw(ahd, SCB_NEXT_COMPLETE, SCB_LIST_NULL); 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds comp_head = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD); 127711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if (SCBID_IS_NULL(comp_head)) { 127811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, scbid); 127911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, scbid); 128011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } else { 128111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke u_int tail; 128211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 128311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke tail = ahd_inw(ahd, COMPLETE_DMA_SCB_TAIL); 128411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_set_scbptr(ahd, tail); 128511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outw(ahd, SCB_NEXT_COMPLETE, scbid); 128611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, scbid); 128711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_set_scbptr(ahd, scbid); 128811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_complete_scb(ahd, scb); 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, saved_scbptr); 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Setup for command channel portion of flush. 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for any inprogress DMA to complete and clear DMA state 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if this if for an SCB in the qinfifo. 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (((ccscbctl = ahd_inb(ahd, CCSCBCTL)) & (CCARREN|CCSCBEN)) != 0) { 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ccscbctl & (CCSCBDIR|CCARREN)) == (CCSCBDIR|CCARREN)) { 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ccscbctl & ARRDONE) != 0) 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((ccscbctl & CCSCBDONE) != 0) 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_delay(200); 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 131211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 131311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * We leave the sequencer to cleanup in the case of DMA's to 131411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * update the qoutfifo. In all other cases (DMA's to the 131511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * chip or a push of an SCB from the COMPLETE_DMA_SCB list), 131611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * we disable the DMA engine so that the sequencer will not 131711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * attempt to handle the DMA completion. 131811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 131911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if ((ccscbctl & CCSCBDIR) != 0 || (ccscbctl & ARRDONE) != 0) 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CCSCBCTL, ccscbctl & ~(CCARREN|CCSCBEN)); 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 132211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 132311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Complete any SCBs that just finished 132411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * being DMA'ed into the qoutfifo. 132511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 132611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_run_qoutfifo(ahd); 132711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_scbptr = ahd_get_scbptr(ahd); 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Manually update/complete any completed SCBs that are waiting to be 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DMA'ed back up to the host. 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD); 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!SCBID_IS_NULL(scbid)) { 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t *hscb_ptr; 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int i; 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, scbid); 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb == NULL) { 134248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Warning - DMA-up and complete " 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "SCB %d invalid\n", ahd_name(ahd), scbid); 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb_ptr = (uint8_t *)scb->hscb; 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < sizeof(struct hardware_scb); i++) 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *hscb_ptr++ = ahd_inb_scbram(ahd, SCB_BASE + i); 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_complete_scb(ahd, scb); 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = next_scbid; 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, SCB_LIST_NULL); 135411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, SCB_LIST_NULL); 135511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 135611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke scbid = ahd_inw(ahd, COMPLETE_ON_QFREEZE_HEAD); 135711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke while (!SCBID_IS_NULL(scbid)) { 135811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 135911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_set_scbptr(ahd, scbid); 136011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); 136111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke scb = ahd_lookup_scb(ahd, scbid); 136211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if (scb == NULL) { 136348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Warning - Complete Qfrz SCB %d invalid\n", 136411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_name(ahd), scbid); 136511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke continue; 136611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } 136711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 136811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_complete_scb(ahd, scb); 136911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke scbid = next_scbid; 137011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } 137111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outw(ahd, COMPLETE_ON_QFREEZE_HEAD, SCB_LIST_NULL); 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_inw(ahd, COMPLETE_SCB_HEAD); 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!SCBID_IS_NULL(scbid)) { 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, scbid); 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb == NULL) { 138048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Warning - Complete SCB %d invalid\n", 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), scbid); 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_complete_scb(ahd, scb); 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = next_scbid; 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, COMPLETE_SCB_HEAD, SCB_LIST_NULL); 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Restore state. 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, saved_scbptr); 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restore_modes(ahd, saved_modes); 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags |= AHD_UPDATE_PEND_CMDS; 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Determine if an SCB for a packetized transaction 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is active in a FIFO. 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_scb_active_in_fifo(struct ahd_softc *ahd, struct scb *scb) 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The FIFO is only active for our transaction if 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the SCBPTR matches the SCB's ID and the firmware 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has installed a handler for the FIFO or we have 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a pending SAVEPTRS or CFG4DATA interrupt. 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_get_scbptr(ahd) != SCB_GET_TAG(scb) 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || ((ahd_inb(ahd, LONGJMP_ADDR+1) & INVALID_ADDR) != 0 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ahd_inb(ahd, SEQINTSRC) & (CFG4DATA|SAVEPTRS)) == 0)) 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (1); 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Run a data fifo to completion for a transaction we know 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has completed across the SCSI bus (good status has been 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * received). We are already set to the correct FIFO mode 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on entry to this routine. 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function attempts to operate exactly as the firmware 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * would when running this FIFO. Care must be taken to update 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine any time the firmware's FIFO algorithm is 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * changed. 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_run_data_fifo(struct ahd_softc *ahd, struct scb *scb) 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int seqintsrc; 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 143611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke seqintsrc = ahd_inb(ahd, SEQINTSRC); 143711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if ((seqintsrc & CFG4DATA) != 0) { 143811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke uint32_t datacnt; 143911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke uint32_t sgptr; 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 144111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 144211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Clear full residual flag. 144311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 144411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke sgptr = ahd_inl_scbram(ahd, SCB_SGPTR) & ~SG_FULL_RESID; 144511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, SCB_SGPTR, sgptr); 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 144711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 144811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Load datacnt and address. 144911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 145011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke datacnt = ahd_inl_scbram(ahd, SCB_DATACNT); 145111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if ((datacnt & AHD_DMA_LAST_SEG) != 0) { 145211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke sgptr |= LAST_SEG; 145311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, SG_STATE, 0); 145411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } else 145511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, SG_STATE, LOADING_NEEDED); 145611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outq(ahd, HADDR, ahd_inq_scbram(ahd, SCB_DATAPTR)); 145711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outl(ahd, HCNT, datacnt & AHD_SG_LEN_MASK); 145811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, SG_CACHE_PRE, sgptr); 145911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, DFCNTRL, PRELOADEN|SCSIEN|HDMAEN); 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 146111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 146211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Initialize Residual Fields. 146311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 146411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, SCB_RESIDUAL_DATACNT+3, datacnt >> 24); 146511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr & SG_PTR_MASK); 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 146711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 146811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Mark the SCB as having a FIFO in use. 146911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 147011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, SCB_FIFO_USE_COUNT, 147111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) + 1); 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 147311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 147411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Install a "fake" handler for this FIFO. 147511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 147611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outw(ahd, LONGJMP_ADDR, 0); 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 147811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 147911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Notify the hardware that we have satisfied 148011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * this sequencer interrupt. 148111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 148211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, CLRSEQINTSRC, CLRCFG4DATA); 148311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } else if ((seqintsrc & SAVEPTRS) != 0) { 148411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke uint32_t sgptr; 148511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke uint32_t resid; 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 148711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if ((ahd_inb(ahd, LONGJMP_ADDR+1)&INVALID_ADDR) != 0) { 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 148911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Snapshot Save Pointers. All that 149011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * is necessary to clear the snapshot 149111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * is a CLRCHN. 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 149311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke goto clrchn; 149411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 149611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 149711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Disable S/G fetch so the DMA engine 149811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * is available to future users. 149911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 150011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0) 150111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, CCSGCTL, 0); 150211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, SG_STATE, 0); 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 150411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 150511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Flush the data FIFO. Strickly only 150611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * necessary for Rev A parts. 150711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 150811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, DFCNTRL, ahd_inb(ahd, DFCNTRL) | FIFOFLUSH); 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 151011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 151111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Calculate residual. 151211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 151311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR); 151411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke resid = ahd_inl(ahd, SHCNT); 151511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke resid |= ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+3) << 24; 151611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outl(ahd, SCB_RESIDUAL_DATACNT, resid); 151711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if ((ahd_inb(ahd, SG_CACHE_SHADOW) & LAST_SEG) == 0) { 15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 151911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Must back up to the correct S/G element. 152011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Typically this just means resetting our 152111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * low byte to the offset in the SG_CACHE, 152211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * but if we wrapped, we have to correct 152311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * the other bytes of the sgptr too. 15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 152511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if ((ahd_inb(ahd, SG_CACHE_SHADOW) & 0x80) != 0 152611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke && (sgptr & 0x80) == 0) 152711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke sgptr -= 0x100; 152811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke sgptr &= ~0xFF; 152911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke sgptr |= ahd_inb(ahd, SG_CACHE_SHADOW) 153011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke & SG_ADDR_MASK; 153111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr); 153211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 3, 0); 153311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } else if ((resid & AHD_SG_LEN_MASK) == 0) { 153411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, SCB_RESIDUAL_SGPTR, 153511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke sgptr | SG_LIST_NULL); 153611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } 153711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 153811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Save Pointers. 153911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 154011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outq(ahd, SCB_DATAPTR, ahd_inq(ahd, SHADDR)); 154111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outl(ahd, SCB_DATACNT, resid); 154211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outl(ahd, SCB_SGPTR, sgptr); 154311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, CLRSEQINTSRC, CLRSAVEPTRS); 154411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, SEQIMODE, 154511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_inb(ahd, SEQIMODE) | ENSAVEPTRS); 154611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 154711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * If the data is to the SCSI bus, we are 154811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * done, otherwise wait for FIFOEMP. 154911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 155011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if ((ahd_inb(ahd, DFCNTRL) & DIRECTION) != 0) 155111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke goto clrchn; 155211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } else if ((ahd_inb(ahd, SG_STATE) & LOADING_NEEDED) != 0) { 155311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke uint32_t sgptr; 155411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke uint64_t data_addr; 155511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke uint32_t data_len; 155611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke u_int dfcntrl; 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 155811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 155911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Disable S/G fetch so the DMA engine 156011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * is available to future users. We won't 156111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * be using the DMA engine to load segments. 156211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 156311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0) { 156411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, CCSGCTL, 0); 156511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, SG_STATE, LOADING_NEEDED); 156611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } 156711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 156811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 156911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Wait for the DMA engine to notice that the 157011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * host transfer is enabled and that there is 157111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * space in the S/G FIFO for new segments before 157211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * loading more segments. 157311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 157411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if ((ahd_inb(ahd, DFSTATUS) & PRELOAD_AVAIL) != 0 157511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke && (ahd_inb(ahd, DFCNTRL) & HDMAENACK) != 0) { 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Determine the offset of the next S/G 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * element to load. 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR); 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgptr &= SG_PTR_MASK; 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_dma64_seg *sg; 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_addr = sg->addr; 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_len = sg->len; 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgptr += sizeof(*sg); 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_dma_seg *sg; 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_addr = sg->len & AHD_SG_HIGH_ADDR_MASK; 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_addr <<= 8; 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_addr |= sg->addr; 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_len = sg->len; 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgptr += sizeof(*sg); 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update residual information. 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCB_RESIDUAL_DATACNT+3, data_len >> 24); 16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr); 16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Load the S/G. 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data_len & AHD_DMA_LAST_SEG) { 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgptr |= LAST_SEG; 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SG_STATE, 0); 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outq(ahd, HADDR, data_addr); 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outl(ahd, HCNT, data_len & AHD_SG_LEN_MASK); 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SG_CACHE_PRE, sgptr & 0xFF); 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Advertise the segment to the hardware. 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dfcntrl = ahd_inb(ahd, DFCNTRL)|PRELOADEN|HDMAEN; 1622ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0) { 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Use SCSIENWRDIS so that SCSIEN 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is never modified by this 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * operation. 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dfcntrl |= SCSIENWRDIS; 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, DFCNTRL, dfcntrl); 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 163211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } else if ((ahd_inb(ahd, SG_CACHE_SHADOW) & LAST_SEG_DONE) != 0) { 163311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 163411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 163511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Transfer completed to the end of SG list 163611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * and has flushed to the host. 163711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 163811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, SCB_SGPTR, 163911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_inb_scbram(ahd, SCB_SGPTR) | SG_LIST_NULL); 164011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke goto clrchn; 164111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } else if ((ahd_inb(ahd, DFSTATUS) & FIFOEMP) != 0) { 164211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reineckeclrchn: 164311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 164411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Clear any handler for this FIFO, decrement 164511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * the FIFO use count for the SCB, and release 164611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * the FIFO. 164711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 164811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR); 164911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, SCB_FIFO_USE_COUNT, 165011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) - 1); 165111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, DFFSXFRCTL, CLRCHN); 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 165511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke/* 165611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Look for entries in the QoutFIFO that have completed. 165711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * The valid_tag completion field indicates the validity 165811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * of the entry - the valid value toggles each time through 165911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * the queue. We use the sg_status field in the completion 166011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * entry to avoid referencing the hscb if the completion 166111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * occurred with no errors and no residual. sg_status is 166211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * a copy of the first byte (little endian) of the sgptr 166311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * hscb field. 166411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 1665d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_run_qoutfifo(struct ahd_softc *ahd) 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 166811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke struct ahd_completion *completion; 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scb_index; 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->flags & AHD_RUNNING_QOUTFIFO) != 0) 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("ahd_run_qoutfifo recursion"); 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags |= AHD_RUNNING_QOUTFIFO; 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_sync_qoutfifo(ahd, BUS_DMASYNC_POSTREAD); 167611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke for (;;) { 167711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke completion = &ahd->qoutfifo[ahd->qoutfifonext]; 167811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 167911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if (completion->valid_tag != ahd->qoutfifonext_valid_tag) 168011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke break; 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 168211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke scb_index = ahd_le16toh(completion->tag); 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scb_index); 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb == NULL) { 168548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: WARNING no command for scb %d " 16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "(cmdcmplt)\nQOUTPOS = %d\n", 16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), scb_index, 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->qoutfifonext); 16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 169011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } else if ((completion->sg_status & SG_STATUS_VALID) != 0) { 169111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_handle_scb_status(ahd, scb); 169211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } else { 169311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_done(ahd, scb); 169411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } 16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->qoutfifonext = (ahd->qoutfifonext+1) & (AHD_QOUT_SIZE-1); 16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->qoutfifonext == 0) 169811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd->qoutfifonext_valid_tag ^= QOUTFIFO_ENTRY_VALID; 16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags &= ~AHD_RUNNING_QOUTFIFO; 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************* Interrupt Handling *********************************/ 1704d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_handle_hwerrint(struct ahd_softc *ahd) 17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Some catastrophic hardware error has occurred. 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Print it for the user and disable the controller. 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = ahd_inb(ahd, ERROR); 17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < num_errors; i++) { 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((error & ahd_hard_errors[i].errno) != 0) 171748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: hwerrint, %s\n", 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), ahd_hard_errors[i].errmesg); 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("BRKADRINT"); 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Tell everyone that this HBA is no longer available */ 17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_abort_scbs(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS, 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_UNKNOWN, 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CAM_NO_HBA); 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Tell the system that this controller has gone away. */ 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_free(ahd); 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1733289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk#ifdef AHD_DEBUG 1734289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void 1735289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkahd_dump_sglist(struct scb *scb) 1736289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk{ 1737289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk int i; 1738289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 1739289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk if (scb->sg_count > 0) { 1740289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk if ((scb->ahd_softc->flags & AHD_64BIT_ADDRESSING) != 0) { 1741289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk struct ahd_dma64_seg *sg_list; 1742289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 1743289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk sg_list = (struct ahd_dma64_seg*)scb->sg_list; 1744289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk for (i = 0; i < scb->sg_count; i++) { 1745289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk uint64_t addr; 1746289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk uint32_t len; 1747289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 1748289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk addr = ahd_le64toh(sg_list[i].addr); 1749289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk len = ahd_le32toh(sg_list[i].len); 175048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("sg[%d] - Addr 0x%x%x : Length %d%s\n", 1751289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk i, 1752289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk (uint32_t)((addr >> 32) & 0xFFFFFFFF), 1753289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk (uint32_t)(addr & 0xFFFFFFFF), 1754289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk sg_list[i].len & AHD_SG_LEN_MASK, 1755289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk (sg_list[i].len & AHD_DMA_LAST_SEG) 1756289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk ? " Last" : ""); 1757289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk } 1758289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk } else { 1759289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk struct ahd_dma_seg *sg_list; 1760289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 1761289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk sg_list = (struct ahd_dma_seg*)scb->sg_list; 1762289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk for (i = 0; i < scb->sg_count; i++) { 1763289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk uint32_t len; 1764289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 1765289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk len = ahd_le32toh(sg_list[i].len); 176648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("sg[%d] - Addr 0x%x%x : Length %d%s\n", 1767289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk i, 1768289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk (len & AHD_SG_HIGH_ADDR_MASK) >> 24, 1769289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk ahd_le32toh(sg_list[i].addr), 1770289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk len & AHD_SG_LEN_MASK, 1771289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk len & AHD_DMA_LAST_SEG ? " Last" : ""); 1772289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk } 1773289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk } 1774289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk } 1775289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk} 1776289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk#endif /* AHD_DEBUG */ 1777289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 1778d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int seqintcode; 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Save the sequencer interrupt code and clear the SEQINT 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit. We will unpause the sequencer, if appropriate, 17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * after servicing the request. 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seqintcode = ahd_inb(ahd, SEQINTCODE); 17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRINT, CLRSEQINT); 17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unpause the sequencer and let it clear 17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SEQINT by writing NO_SEQINT to it. This 17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will cause the sequencer to be paused again, 17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * which is the expected state of this routine. 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!ahd_is_paused(ahd)) 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; 18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRINT, CLRSEQINT); 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_update_modes(ahd); 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MISC) != 0) 180548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Handle Seqint Called for code %d\n", 18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), seqintcode); 18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (seqintcode) { 18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ENTERING_NONPACK: 18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_get_scbptr(ahd); 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb == NULL) { 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Somehow need to know if this 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is from a selection or reselection. 18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * From that, we can determine target 18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ID so we at least have an I_T nexus. 18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SAVED_SCSIID, scb->hscb->scsiid); 18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SAVED_LUN, scb->hscb->lun); 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEQ_FLAGS, 0x0); 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_inb(ahd, LQISTAT2) & LQIPHASE_OUTPKT) != 0 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ahd_inb(ahd, SCSISIGO) & ATNO) != 0) { 18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Phase change after read stream with 18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * CRC error with P0 asserted on last 18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * packet. 18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) 183948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Assuming LQIPHASE_NLQ with " 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "P0 assertion\n", ahd_name(ahd)); 18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) 184548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Entering NONPACK\n", ahd_name(ahd)); 18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case INVALID_SEQINT: 185048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Invalid Sequencer interrupt occurred, " 18519e691dfba56f7d7a38b09edc5252264bc1bab659Hannes Reinecke "resetting channel.\n", 18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd)); 18539e691dfba56f7d7a38b09edc5252264bc1bab659Hannes Reinecke#ifdef AHD_DEBUG 18549e691dfba56f7d7a38b09edc5252264bc1bab659Hannes Reinecke if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) 18559e691dfba56f7d7a38b09edc5252264bc1bab659Hannes Reinecke ahd_dump_card_state(ahd); 18569e691dfba56f7d7a38b09edc5252264bc1bab659Hannes Reinecke#endif 18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case STATUS_OVERRUN: 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_get_scbptr(ahd); 18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb != NULL) 18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 186948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: ", ahd_name(ahd)); 187048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("SCB %d Packetized Status Overrun", scbid); 18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CFG4ISTAT_INTR: 18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_get_scbptr(ahd); 18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb == NULL) { 18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 188448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("CFG4ISTAT: Free SCB %d referenced", scbid); 18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("For safety"); 18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outq(ahd, HADDR, scb->sense_busaddr); 18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, HCNT, AHD_SENSE_BUFSIZE); 18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, HCNT + 2, 0); 18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SG_CACHE_PRE, SG_LAST_SEG); 18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, DFCNTRL, PRELOADEN|SCSIEN|HDMAEN); 18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ILLEGAL_PHASE: 18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int bus_phase; 18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_phase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK; 189948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: ILLEGAL_PHASE 0x%x\n", 19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), bus_phase); 19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (bus_phase) { 19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case P_DATAOUT: 19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case P_DATAIN: 19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case P_DATAOUT_DT: 19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case P_DATAIN_DT: 19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case P_MESGOUT: 19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case P_STATUS: 19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case P_MESGIN: 19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 191148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Issued Bus Reset.\n", ahd_name(ahd)); 19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case P_COMMAND: 19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo devinfo; 19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_initiator_tinfo *targ_info; 19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_transinfo *tinfo; 19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If a target takes us into the command phase 19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assume that it has been externally reset and 19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has thus lost our previous packetized negotiation 19268883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * agreement. Since we have not sent an identify 19278883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * message and may not have fully qualified the 19288883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * connection, we change our command to TUR, assert 19298883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * ATN and ABORT the task when we go to message in 19308883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * phase. The OSM will see the REQUEUE_REQUEST 19318883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * status and retry the command. 19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_get_scbptr(ahd); 19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb == NULL) { 193648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Invalid phase with no valid SCB. " 19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Resetting bus.\n"); 19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_reset_channel(ahd, 'A', 19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*Initiate Reset*/TRUE); 19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_compile_devinfo(&devinfo, SCB_GET_OUR_ID(scb), 19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_TARGET(ahd, scb), 19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_LUN(scb), 19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_CHANNEL(ahd, scb), 19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ROLE_INITIATOR); 19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds targ_info = ahd_fetch_transinfo(ahd, 19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo.channel, 19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo.our_scsiid, 19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo.target, 19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &tstate); 19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo = &targ_info->curr; 19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, 19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_TRANS_ACTIVE, /*paused*/TRUE); 19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_syncrate(ahd, &devinfo, /*period*/0, 19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*offset*/0, /*ppr_options*/0, 19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_TRANS_ACTIVE, /*paused*/TRUE); 19588883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke /* Hand-craft TUR command */ 19598883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke ahd_outb(ahd, SCB_CDB_STORE, 0); 19608883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke ahd_outb(ahd, SCB_CDB_STORE+1, 0); 19618883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke ahd_outb(ahd, SCB_CDB_STORE+2, 0); 19628883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke ahd_outb(ahd, SCB_CDB_STORE+3, 0); 19638883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke ahd_outb(ahd, SCB_CDB_STORE+4, 0); 19648883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke ahd_outb(ahd, SCB_CDB_STORE+5, 0); 19658883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke ahd_outb(ahd, SCB_CDB_LEN, 6); 19668883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke scb->hscb->control &= ~(TAG_ENB|SCB_TAG_TYPE); 19678883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke scb->hscb->control |= MK_MESSAGE; 19688883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke ahd_outb(ahd, SCB_CONTROL, scb->hscb->control); 19698883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke ahd_outb(ahd, MSG_OUT, HOST_MSG); 19708883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke ahd_outb(ahd, SAVED_SCSIID, scb->hscb->scsiid); 19718883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke /* 19728883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * The lun is 0, regardless of the SCB's lun 19738883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * as we have not sent an identify message. 19748883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke */ 19758883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke ahd_outb(ahd, SAVED_LUN, 0); 19768883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke ahd_outb(ahd, SEQ_FLAGS, 0); 19778883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke ahd_assert_atn(ahd); 19788883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke scb->flags &= ~SCB_PACKETIZED; 19798883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke scb->flags |= SCB_ABORT|SCB_EXTERNAL_RESET; 19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_freeze_devq(ahd, scb); 19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); 19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_freeze_scb(scb); 19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1984b0d2364887e94c880680f1e17943cd660bcf8979Hannes Reinecke /* Notify XPT */ 1985b0d2364887e94c880680f1e17943cd660bcf8979Hannes Reinecke ahd_send_async(ahd, devinfo.channel, devinfo.target, 1986f89d0a4e1d01168f20f9e8273de7dfc094b2a430Hannes Reinecke CAM_LUN_WILDCARD, AC_SENT_BDR); 1987b0d2364887e94c880680f1e17943cd660bcf8979Hannes Reinecke 19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allow the sequencer to continue with 19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * non-pack processing. 19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRLQOINT1, CLRLQOPHACHGINPKT); 19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) { 19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRLQOINT1, 0); 19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { 19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 200048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Unexpected command phase from " 20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "packetized target\n"); 20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CFG4OVERRUN: 20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scb_index; 20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { 201648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: CFG4OVERRUN mode = %x\n", ahd_name(ahd), 20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, MODE_PTR)); 20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_index = ahd_get_scbptr(ahd); 20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scb_index); 20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb == NULL) { 20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Attempt to transfer to an SCB that is 20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not outstanding. 20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_assert_atn(ahd); 20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, MSG_OUT, HOST_MSG); 20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_buf[0] = MSG_ABORT_TASK; 20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len = 1; 20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; 20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear status received flag to prevent any 20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * attempt to complete this bogus SCB. 20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCB_CONTROL, 20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_CONTROL) 20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds & ~STATUS_RCVD); 20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DUMP_CARD_STATE: 20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PDATA_REINIT: 20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { 205248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: PDATA_REINIT - DFCNTRL = 0x%x " 20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "SG_CACHE_SHADOW = 0x%x\n", 20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), ahd_inb(ahd, DFCNTRL), 20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SG_CACHE_SHADOW)); 20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_reinitialize_dataptrs(ahd); 20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HOST_MSG_LOOP: 20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo devinfo; 20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The sequencer has encountered a message phase 20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that requires host assistance for completion. 20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * While handling the message phase(s), we will be 20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * notified by the sequencer after each byte is 207025985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * transferred so we can track bus phase changes. 20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If this is the first time we've seen a HOST_MSG_LOOP 20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupt, initialize the state of the host message 20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * loop. 20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_fetch_devinfo(ahd, &devinfo); 20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->msg_type == MSG_TYPE_NONE) { 20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scb_index; 20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int bus_phase; 20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_phase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK; 20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bus_phase != P_MESGIN 20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && bus_phase != P_MESGOUT) { 208548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("ahd_intr: HOST_MSG_LOOP bad " 20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "phase 0x%x\n", bus_phase); 20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Probably transitioned to bus free before 20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we got here. Just punt the message. 20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_clear_intstat(ahd); 20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restart(ahd); 20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_index = ahd_get_scbptr(ahd); 20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scb_index); 20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (devinfo.role == ROLE_INITIATOR) { 21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bus_phase == P_MESGOUT) 21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_setup_initiator_msgout(ahd, 21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &devinfo, 21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb); 21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_type = 21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MSG_TYPE_INITIATOR_MSGIN; 21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgin_index = 0; 21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_TARGET_MODE 21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bus_phase == P_MESGOUT) { 21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_type = 21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MSG_TYPE_TARGET_MSGOUT; 21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgin_index = 0; 21161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_setup_target_msgin(ahd, 21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &devinfo, 21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb); 21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_handle_message_phase(ahd); 21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NO_MATCH: 21291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Ensure we don't leave the selection hardware on */ 21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO); 21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 213448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s:%c:%d: no active SCB for reconnecting " 21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "target - issuing BUS DEVICE RESET\n", 21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), 'A', ahd_inb(ahd, SELID) >> 4); 213748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " 21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "REG0 == 0x%x ACCUM = 0x%x\n", 21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SAVED_SCSIID), ahd_inb(ahd, SAVED_LUN), 21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inw(ahd, REG0), ahd_inb(ahd, ACCUM)); 214148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " 21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "SINDEX == 0x%x\n", 21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SEQ_FLAGS), ahd_get_scbptr(ahd), 21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_find_busy_tcl(ahd, 21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUILD_TCL(ahd_inb(ahd, SAVED_SCSIID), 21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SAVED_LUN))), 21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inw(ahd, SINDEX)); 214848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("SELID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " 21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "SCB_CONTROL == 0x%x\n", 21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SELID), ahd_inb_scbram(ahd, SCB_SCSIID), 21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_LUN), 21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_CONTROL)); 215348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("SCSIBUS[0] == 0x%x, SCSISIGI == 0x%x\n", 21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SCSIBUS), ahd_inb(ahd, SCSISIGI)); 215548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("SXFRCTL0 == 0x%x\n", ahd_inb(ahd, SXFRCTL0)); 215648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("SEQCTL0 == 0x%x\n", ahd_inb(ahd, SEQCTL0)); 21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_buf[0] = MSG_BUS_DEV_RESET; 21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len = 1; 21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; 21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, MSG_OUT, HOST_MSG); 21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_assert_atn(ahd); 21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PROTO_VIOLATION: 21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_handle_proto_violation(ahd); 21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IGN_WIDE_RES: 21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo devinfo; 21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_fetch_devinfo(ahd, &devinfo); 21761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_handle_ign_wide_residue(ahd, &devinfo); 21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BAD_PHASE: 21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lastphase; 21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lastphase = ahd_inb(ahd, LASTPHASE); 218448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s:%c:%d: unknown scsi bus phase %x, " 21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "lastphase = 0x%x. Attempting to continue\n", 21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), 'A', 21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCSIID_TARGET(ahd, ahd_inb(ahd, SAVED_SCSIID)), 21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lastphase, ahd_inb(ahd, SCSISIGI)); 21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MISSED_BUSFREE: 21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lastphase; 21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lastphase = ahd_inb(ahd, LASTPHASE); 219648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s:%c:%d: Missed busfree. " 21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Lastphase = 0x%x, Curphase = 0x%x\n", 21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), 'A', 21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCSIID_TARGET(ahd, ahd_inb(ahd, SAVED_SCSIID)), 22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lastphase, ahd_inb(ahd, SCSISIGI)); 22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restart(ahd); 22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DATA_OVERRUN: 22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When the sequencer detects an overrun, it 22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * places the controller in "BITBUCKET" mode 22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and allows the target to complete its transfer. 22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unfortunately, none of the counters get updated 22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when the controller is in this mode, so we have 22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * no way of knowing how large the overrun was. 22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbindex; 22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lastphase; 22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbindex = ahd_get_scbptr(ahd); 22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbindex); 22221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lastphase = ahd_inb(ahd, LASTPHASE); 22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { 22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 222648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("data overrun detected %s. Tag == 0x%x.\n", 22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lookup_phase_entry(lastphase)->phasemsg, 22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_TAG(scb)); 22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 223048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s seen Data Phase. Length = %ld. " 22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "NumSGs = %d.\n", 22321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SEQ_FLAGS) & DPHASE 22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? "Have" : "Haven't", 22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_get_transfer_length(scb), scb->sg_count); 22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_sglist(scb); 22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set this and it will take effect when the 22411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * target does a command complete. 22421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_freeze_devq(ahd, scb); 22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR); 22451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_freeze_scb(scb); 22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MKMSG_FAILED: 22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo devinfo; 22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_fetch_devinfo(ahd, &devinfo); 225548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s:%c:%d:%d: Attempt to issue message failed\n", 22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo.channel, devinfo.target, 22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo.lun); 22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_get_scbptr(ahd); 22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb != NULL 22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (scb->flags & SCB_RECOVERY_SCB) != 0) 22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ensure that we didn't put a second instance of this 22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCB into the QINFIFO. 22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_search_qinfifo(ahd, SCB_GET_TARGET(ahd, scb), 22671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_CHANNEL(ahd, scb), 22681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_LUN(scb), SCB_GET_TAG(scb), 22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ROLE_INITIATOR, /*status*/0, 22701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SEARCH_REMOVE); 22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCB_CONTROL, 22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_CONTROL) & ~MK_MESSAGE); 22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TASKMGMT_FUNC_COMPLETE: 22761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 22771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_get_scbptr(ahd); 22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb != NULL) { 22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lun; 22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int tag; 22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cam_status error; 22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 228848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Task Management Func 0x%x Complete\n", 22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->hscb->task_management); 22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lun = CAM_LUN_WILDCARD; 22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tag = SCB_LIST_NULL; 22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (scb->hscb->task_management) { 22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIU_TASKMGMT_ABORT_TASK: 22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tag = SCB_GET_TAG(scb); 22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIU_TASKMGMT_ABORT_TASK_SET: 22971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIU_TASKMGMT_CLEAR_TASK_SET: 22981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lun = scb->hscb->lun; 22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = CAM_REQ_ABORTED; 23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), 23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 'A', lun, tag, ROLE_INITIATOR, 23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error); 23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIU_TASKMGMT_LUN_RESET: 23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lun = scb->hscb->lun; 23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIU_TASKMGMT_TARGET_RESET: 23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 23081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo devinfo; 23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_scb_devinfo(ahd, &devinfo, scb); 23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = CAM_BDR_SENT; 23121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_handle_devreset(ahd, &devinfo, lun, 23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CAM_BDR_SENT, 23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lun != CAM_LUN_WILDCARD 23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? "Lun Reset" 23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds : "Target Reset", 23171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*verbose_level*/0); 23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 23191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("Unexpected TaskMgmt Func\n"); 23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 23261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TASKMGMT_CMD_CMPLT_OKAY: 23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 23291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 23301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 23331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * An ABORT TASK TMF failed to be delivered before 23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the targeted command completed normally. 23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_get_scbptr(ahd); 23371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb != NULL) { 23391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 23401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Remove the second instance of this SCB from 23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the QINFIFO if it is still there. 23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 234448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("SCB completes before TMF\n"); 23451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle losing the race. Wait until any 23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * current selection completes. We will then 23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set the TMF back to zero in this SCB so that 23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the sequencer doesn't bother to issue another 23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sequencer interrupt for its completion. 23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((ahd_inb(ahd, SCSISEQ0) & ENSELO) != 0 23531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ahd_inb(ahd, SSTAT0) & SELDO) == 0 23541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ahd_inb(ahd, SSTAT1) & SELTO) == 0) 23551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; 23561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCB_TASK_MANAGEMENT, 0); 23571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_search_qinfifo(ahd, SCB_GET_TARGET(ahd, scb), 23581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_CHANNEL(ahd, scb), 23591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_LUN(scb), SCB_GET_TAG(scb), 23601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ROLE_INITIATOR, /*status*/0, 23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SEARCH_REMOVE); 23621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TRACEPOINT0: 23661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TRACEPOINT1: 23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TRACEPOINT2: 23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TRACEPOINT3: 236948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Tracepoint %d\n", ahd_name(ahd), 23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seqintcode - TRACEPOINT0); 23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NO_SEQINT: 23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SAW_HWERR: 23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_handle_hwerrint(ahd); 23761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 23771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 237848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Unexpected SEQINTCODE %d\n", ahd_name(ahd), 23791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seqintcode); 23801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 23811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The sequencer is paused immediately on 23841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a SEQINT, so we should restart it when 23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we're done. 23861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 23881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2390d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) 23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int status0; 23951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int status3; 23961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int status; 23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lqistat1; 23981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lqostat0; 23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 24001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int busfreetime; 24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_update_modes(ahd); 24031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status3 = ahd_inb(ahd, SSTAT3) & (NTRAMPERR|OSRAMPERR); 24061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status0 = ahd_inb(ahd, SSTAT0) & (IOERR|OVERRUN|SELDI|SELDO); 24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = ahd_inb(ahd, SSTAT1) & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR); 24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lqistat1 = ahd_inb(ahd, LQISTAT1); 24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lqostat0 = ahd_inb(ahd, LQOSTAT0); 24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME; 2411f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke 2412f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke /* 2413f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke * Ignore external resets after a bus reset. 2414f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke */ 24158883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke if (((status & SCSIRSTI) != 0) && (ahd->flags & AHD_BUS_RESET_ACTIVE)) { 24168883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI); 2417f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke return; 24188883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke } 2419f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke 2420f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke /* 2421f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke * Clear bus reset flag 2422f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke */ 2423f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke ahd->flags &= ~AHD_BUS_RESET_ACTIVE; 2424f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke 24251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status0 & (SELDI|SELDO)) != 0) { 24261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int simode0; 24271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 24291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds simode0 = ahd_inb(ahd, SIMODE0); 24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status0 &= simode0 & (IOERR|OVERRUN|SELDI|SELDO); 24311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 24321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_get_scbptr(ahd); 24341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 24351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb != NULL 24361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) != 0) 24371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = NULL; 24381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status0 & IOERR) != 0) { 24401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int now_lvd; 24411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds now_lvd = ahd_inb(ahd, SBLKCTL) & ENAB40; 244348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Transceiver State Has Changed to %s mode\n", 24441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), now_lvd ? "LVD" : "SE"); 24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT0, CLRIOERR); 24461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 24471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A change in I/O mode is equivalent to a bus reset. 24481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 24491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 24501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pause(ahd); 24511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_setup_iocell_workaround(ahd); 24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 24531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((status0 & OVERRUN) != 0) { 245411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 245548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: SCSI offset overrun detected. Resetting bus.\n", 24561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd)); 24571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 24581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((status & SCSIRSTI) != 0) { 245911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 246048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Someone reset channel A\n", ahd_name(ahd)); 24611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_reset_channel(ahd, 'A', /*Initiate Reset*/FALSE); 24621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((status & SCSIPERR) != 0) { 246311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 246411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* Make sure the sequencer is in a safe location. */ 246511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_clear_critical_section(ahd); 246611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 24671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_handle_transmission_error(ahd); 24681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (lqostat0 != 0) { 246911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 247048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: lqostat0 == 0x%x!\n", ahd_name(ahd), lqostat0); 24711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRLQOINT0, lqostat0); 247211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) 24731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRLQOINT1, 0); 24741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((status & SELTO) != 0) { 24751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Stop the selection */ 24761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ0, 0); 24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 247811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* Make sure the sequencer is in a safe location. */ 247911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_clear_critical_section(ahd); 248011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 24811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* No more pending messages */ 24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_clear_msg_state(ahd); 24831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear interrupt state */ 24851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR); 24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 24881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Although the driver does not care about the 24891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 'Selection in Progress' status bit, the busy 249025985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * LED does. SELINGO is only cleared by a successful 24911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * selection, so we must manually clear it to insure 24921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the LED turns off just incase no future successful 24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * selections occur (e.g. no devices on the bus). 24941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 24951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT0, CLRSELINGO); 24961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_inw(ahd, WAITING_TID_HEAD); 24981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 24991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb == NULL) { 250048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: ahd_intr - referenced scb not " 25011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "valid during SELTO scb(0x%x)\n", 25021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), scbid); 25031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 25041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 25051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo devinfo; 25061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 25071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_SELTO) != 0) { 25081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 250948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Saw Selection Timeout for SCB 0x%x\n", 25101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid); 25111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 25131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_scb_devinfo(ahd, &devinfo, scb); 25141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_transaction_status(scb, CAM_SEL_TIMEOUT); 25151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_freeze_devq(ahd, scb); 251611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 251711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 251811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Cancel any pending transactions on the device 251911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * now that it seems to be missing. This will 252011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * also revert us to async/narrow transfers until 252111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * we can renegotiate with the device. 252211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 252311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_handle_devreset(ahd, &devinfo, 252411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke CAM_LUN_WILDCARD, 252511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke CAM_SEL_TIMEOUT, 252611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke "Selection Timeout", 252711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /*verbose_level*/1); 25281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRINT, CLRSCSIINT); 25301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_iocell_first_selection(ahd); 25311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 25321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((status0 & (SELDI|SELDO)) != 0) { 253311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 25341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_iocell_first_selection(ahd); 25351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 25361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (status3 != 0) { 253748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: SCSI Cell parity error SSTAT3 == 0x%x\n", 25381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), status3); 25391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT3, status3); 25401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((lqistat1 & (LQIPHASE_LQ|LQIPHASE_NLQ)) != 0) { 254111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 254211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* Make sure the sequencer is in a safe location. */ 254311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_clear_critical_section(ahd); 254411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 25451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_handle_lqiphase_error(ahd, lqistat1); 25461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((lqistat1 & LQICRCI_NLQ) != 0) { 25471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 25481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This status can be delayed during some 25491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * streaming operations. The SCSIPHASE 25501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handler has already dealt with this case 25511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so just clear the error. 25521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 25531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRLQIINT1, CLRLQICRCI_NLQ); 255453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke } else if ((status & BUSFREE) != 0 255553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke || (lqistat1 & LQOBUSFREE) != 0) { 25561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lqostat1; 25571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int restart; 25581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int clear_fifo; 25591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int packetized; 25601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int mode; 25611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 25631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear our selection hardware as soon as possible. 25641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We may have an entry in the waiting Q for this target, 25651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that is affected by this busfree and we don't want to 25661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * go about selecting the target while we handle the event. 25671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 25681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ0, 0); 25691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 257011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* Make sure the sequencer is in a safe location. */ 257111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_clear_critical_section(ahd); 257211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 25731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 25741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Determine what we were up to at the time of 25751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the busfree. 25761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 25771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mode = AHD_MODE_SCSI; 25781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME; 25791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lqostat1 = ahd_inb(ahd, LQOSTAT1); 25801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (busfreetime) { 25811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BUSFREE_DFF0: 25821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BUSFREE_DFF1: 25831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 25841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mode = busfreetime == BUSFREE_DFF0 25851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? AHD_MODE_DFF0 : AHD_MODE_DFF1; 25861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, mode, mode); 25871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_get_scbptr(ahd); 25881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 25891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb == NULL) { 259048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Invalid SCB %d in DFF%d " 25911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "during unexpected busfree\n", 25921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), scbid, mode); 25931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds packetized = 0; 25941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 25951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds packetized = (scb->flags & SCB_PACKETIZED) != 0; 25961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_fifo = 1; 25971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 25981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BUSFREE_LQO: 26001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_fifo = 0; 26011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds packetized = 1; 26021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 26031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 26041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_fifo = 0; 26051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds packetized = (lqostat1 & LQOBUSFREE) != 0; 26061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!packetized 260711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke && ahd_inb(ahd, LASTPHASE) == P_BUSFREE 260811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke && (ahd_inb(ahd, SSTAT0) & SELDI) == 0 260911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke && ((ahd_inb(ahd, SSTAT0) & SELDO) == 0 261011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke || (ahd_inb(ahd, SCSISEQ0) & ENSELO) == 0)) 261111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 261211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Assume packetized if we are not 261311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * on the bus in a non-packetized 261411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * capacity and any pending selection 261511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * was a packetized selection. 261611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 26171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds packetized = 1; 26181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 26191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 26221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MISC) != 0) 262348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Saw Busfree. Busfreetime = 0x%x.\n", 26241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds busfreetime); 26251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 26261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 26271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Busfrees that occur in non-packetized phases are 26281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handled by the nonpkt_busfree handler. 26291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 26301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (packetized && ahd_inb(ahd, LASTPHASE) == P_BUSFREE) { 26311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds restart = ahd_handle_pkt_busfree(ahd, busfreetime); 26321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 26331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds packetized = 0; 26341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds restart = ahd_handle_nonpkt_busfree(ahd); 26351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 26371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear the busfree interrupt status. The setting of 26381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the interrupt is a pulse, so in a perfect world, we 26391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * would not need to muck with the ENBUSFREE logic. This 26401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * would ensure that if the bus moves on to another 26411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * connection, busfree protection is still in force. If 26421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * BUSFREEREV is broken, however, we must manually clear 26431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the ENBUSFREE if the busfree occurred during a non-pack 26441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * connection so that we don't get false positives during 26451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * future, packetized, connections. 26461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 26471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT1, CLRBUSFREE); 26481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (packetized == 0 26491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ahd->bugs & AHD_BUSFREEREV_BUG) != 0) 26501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SIMODE1, 26511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SIMODE1) & ~ENBUSFREE); 26521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clear_fifo) 26541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_clear_fifo(ahd, mode); 26551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_clear_msg_state(ahd); 26571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRINT, CLRSCSIINT); 26581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (restart) { 26591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restart(ahd); 26601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 26611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 26621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 266448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Missing case in ahd_handle_scsiint. status = %x\n", 26651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), status); 26661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 26671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_clear_intstat(ahd); 26681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 26691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 26731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_handle_transmission_error(struct ahd_softc *ahd) 26741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 26751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 26761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 26771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lqistat1; 26781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lqistat2; 26791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int msg_out; 26801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int curphase; 26811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lastphase; 26821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int perrdiag; 26831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int cur_col; 26841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int silent; 26851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = NULL; 26871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 26881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lqistat1 = ahd_inb(ahd, LQISTAT1) & ~(LQIPHASE_LQ|LQIPHASE_NLQ); 26891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lqistat2 = ahd_inb(ahd, LQISTAT2); 26901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((lqistat1 & (LQICRCI_NLQ|LQICRCI_LQ)) == 0 26911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ahd->bugs & AHD_NLQICRC_DELAYED_BUG) != 0) { 26921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lqistate; 26931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 26951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lqistate = ahd_inb(ahd, LQISTATE); 26961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((lqistate >= 0x1E && lqistate <= 0x24) 26971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || (lqistate == 0x29)) { 26981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 26991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { 270048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: NLQCRC found via LQISTATE\n", 27011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd)); 27021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 27041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lqistat1 |= LQICRCI_NLQ; 27051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 27071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRLQIINT1, lqistat1); 27101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lastphase = ahd_inb(ahd, LASTPHASE); 27111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curphase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK; 27121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds perrdiag = ahd_inb(ahd, PERRDIAG); 27131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg_out = MSG_INITIATOR_DET_ERR; 27141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT1, CLRSCSIPERR); 27151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 27171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to find the SCB associated with this error. 27181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 27191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds silent = FALSE; 27201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lqistat1 == 0 27211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || (lqistat1 & LQICRCI_NLQ) != 0) { 27221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((lqistat1 & (LQICRCI_NLQ|LQIOVERI_NLQ)) != 0) 27231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_active_fifo(ahd); 27241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_get_scbptr(ahd); 27251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 27261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb != NULL && SCB_IS_SILENT(scb)) 27271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds silent = TRUE; 27281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_col = 0; 27311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (silent == FALSE) { 273248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Transmission error detected\n", ahd_name(ahd)); 27331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lqistat1_print(lqistat1, &cur_col, 50); 27341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lastphase_print(lastphase, &cur_col, 50); 27351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_scsisigi_print(curphase, &cur_col, 50); 27361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_perrdiag_print(perrdiag, &cur_col, 50); 273748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\n"); 27381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 27391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((lqistat1 & (LQIOVERI_LQ|LQIOVERI_NLQ)) != 0) { 27421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (silent == FALSE) { 274348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Gross protocol error during incoming " 27441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "packet. lqistat1 == 0x%x. Resetting bus.\n", 27451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), lqistat1); 27461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 27481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 27491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((lqistat1 & LQICRCI_LQ) != 0) { 27501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 27511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A CRC error has been detected on an incoming LQ. 27521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The bus is currently hung on the last ACK. 27531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Hit LQIRETRY to release the last ack, and 27541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * wait for the sequencer to determine that ATNO 27551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is asserted while in message out to take us 27561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to our host message loop. No NONPACKREQ or 27571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * LQIPHASE type errors will occur in this 27581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scenario. After this first LQIRETRY, the LQI 27591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * manager will be in ISELO where it will 27601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * happily sit until another packet phase begins. 27611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unexpected bus free detection is enabled 27621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * through any phases that occur after we release 27631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this last ack until the LQI manager sees a 27641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * packet phase. This implies we may have to 27651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ignore a perfectly valid "unexected busfree" 27661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * after our "initiator detected error" message is 27671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sent. A busfree is the expected response after 27681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we tell the target that it's L_Q was corrupted. 27691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (SPI4R09 10.7.3.3.3) 27701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 27711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQCTL2, LQIRETRY); 277248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("LQIRetry for LQICRCI_LQ to release ACK\n"); 27731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((lqistat1 & LQICRCI_NLQ) != 0) { 27741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 27751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We detected a CRC error in a NON-LQ packet. 27761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The hardware has varying behavior in this situation 27771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * depending on whether this packet was part of a 27781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stream or not. 27791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 27801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PKT by PKT mode: 27811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The hardware has already acked the complete packet. 27821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the target honors our outstanding ATN condition, 27831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we should be (or soon will be) in MSGOUT phase. 27841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This will trigger the LQIPHASE_LQ status bit as the 27851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware was expecting another LQ. Unexpected 27861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * busfree detection is enabled. Once LQIPHASE_LQ is 27871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * true (first entry into host message loop is much 27881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the same), we must clear LQIPHASE_LQ and hit 27891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * LQIRETRY so the hardware is ready to handle 27901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a future LQ. NONPACKREQ will not be asserted again 27911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * once we hit LQIRETRY until another packet is 27921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * processed. The target may either go busfree 27931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or start another packet in response to our message. 27941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 27951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read Streaming P0 asserted: 27961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we raise ATN and the target completes the entire 27971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stream (P0 asserted during the last packet), the 27981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware will ack all data and return to the ISTART 27991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * state. When the target reponds to our ATN condition, 28001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * LQIPHASE_LQ will be asserted. We should respond to 28011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this with an LQIRETRY to prepare for any future 28021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * packets. NONPACKREQ will not be asserted again 28031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * once we hit LQIRETRY until another packet is 28041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * processed. The target may either go busfree or 28051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * start another packet in response to our message. 28061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Busfree detection is enabled. 28071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 28081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read Streaming P0 not asserted: 28091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we raise ATN and the target transitions to 28101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MSGOUT in or after a packet where P0 is not 28111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * asserted, the hardware will assert LQIPHASE_NLQ. 28121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We should respond to the LQIPHASE_NLQ with an 28131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * LQIRETRY. Should the target stay in a non-pkt 28141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * phase after we send our message, the hardware 28151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will assert LQIPHASE_LQ. Recovery is then just as 28161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * listed above for the read streaming with P0 asserted. 28171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Busfree detection is enabled. 28181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 28191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (silent == FALSE) 282048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("LQICRC_NLQ\n"); 28211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb == NULL) { 282248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: No SCB valid for LQICRC_NLQ. " 28231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Resetting bus\n", ahd_name(ahd)); 28241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 28251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 28261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((lqistat1 & LQIBADLQI) != 0) { 282848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Need to handle BADLQI!\n"); 28291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 28301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 28311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((perrdiag & (PARITYERR|PREVPHASE)) == PARITYERR) { 28321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((curphase & ~P_DATAIN_DT) != 0) { 28331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Ack the byte. So we can continue. */ 28341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (silent == FALSE) 283548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Acking %s to clear perror\n", 28361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lookup_phase_entry(curphase)->phasemsg); 28371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SCSIDAT); 28381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curphase == P_MESGIN) 28411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg_out = MSG_PARITY_ERROR; 28421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 28451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We've set the hardware to assert ATN if we 28461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get a parity error on "in" phases, so all we 28471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * need to do is stuff the message buffer with 28481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the appropriate message. "In" phases have set 28491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mesg_out to something other than MSG_NOP. 28501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 28511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->send_msg_perror = msg_out; 28521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb != NULL && msg_out == MSG_INITIATOR_DET_ERR) 28531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->flags |= SCB_TRANSMISSION_ERROR; 28541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, MSG_OUT, HOST_MSG); 28551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRINT, CLRSCSIINT); 28561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 28571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 28581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 28601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_handle_lqiphase_error(struct ahd_softc *ahd, u_int lqistat1) 28611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 28621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 28631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear the sources of the interrupts. 28641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 28651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 28661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRLQIINT1, lqistat1); 28671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 28691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the "illegal" phase changes were in response 28701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to our ATN to flag a CRC error, AND we ended up 28711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on packet boundaries, clear the error, restart the 28721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * LQI manager as appropriate, and go on our merry 28731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * way toward sending the message. Otherwise, reset 28741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the bus to clear the error. 28751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 28761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_active_fifo(ahd); 28771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_inb(ahd, SCSISIGO) & ATNO) != 0 28781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ahd_inb(ahd, MDFFSTAT) & DLZERO) != 0) { 28791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((lqistat1 & LQIPHASE_LQ) != 0) { 288048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("LQIRETRY for LQIPHASE_LQ\n"); 28811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQCTL2, LQIRETRY); 28821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((lqistat1 & LQIPHASE_NLQ) != 0) { 288348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("LQIRETRY for LQIPHASE_NLQ\n"); 28841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQCTL2, LQIRETRY); 28851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 28861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("ahd_handle_lqiphase_error: No phase errors\n"); 28871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 28881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRINT, CLRSCSIINT); 28891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 28901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 289148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Reseting Channel for LQI Phase error\n"); 28921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 28931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); 28941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 28961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 28981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Packetized unexpected or expected busfree. 28991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Entered in mode based on busfreetime. 29001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 29021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime) 29031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 29041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lqostat1; 29051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 29071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 29081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lqostat1 = ahd_inb(ahd, LQOSTAT1); 29091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((lqostat1 & LQOBUSFREE) != 0) { 29101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 29111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 29121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int saved_scbptr; 29131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int waiting_h; 29141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int waiting_t; 29151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int next; 29161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 29181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The LQO manager detected an unexpected busfree 29191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * either: 29201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 29211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1) During an outgoing LQ. 29221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2) After an outgoing LQ but before the first 29231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * REQ of the command packet. 29241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3) During an outgoing command packet. 29251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 29261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In all cases, CURRSCB is pointing to the 29271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCB that encountered the failure. Clean 29281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * up the queue, clear SELDO and LQOBUSFREE, 29291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and allow the sequencer to restart the select 29301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * out at its lesure. 29311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 29331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_inw(ahd, CURRSCB); 29341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 29351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb == NULL) 29361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("SCB not valid during LQOBUSFREE"); 29371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 29381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear the status. 29391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRLQOINT1, CLRLQOBUSFREE); 29411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) 29421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRLQOINT1, 0); 29431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO); 29441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_flush_device_writes(ahd); 29451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT0, CLRSELDO); 29461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 29481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return the LQO manager to its idle loop. It will 29491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not do this automatically if the busfree occurs 29501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * after the first REQ of either the LQ or command 29511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * packet or between the LQ and command packet. 29521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQCTL2, ahd_inb(ahd, LQCTL2) | LQOTOIDLE); 29541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 29561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update the waiting for selection queue so 29571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we restart on the correct SCB. 29581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds waiting_h = ahd_inw(ahd, WAITING_TID_HEAD); 29601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_scbptr = ahd_get_scbptr(ahd); 29611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (waiting_h != scbid) { 29621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, WAITING_TID_HEAD, scbid); 29641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds waiting_t = ahd_inw(ahd, WAITING_TID_TAIL); 29651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (waiting_t == waiting_h) { 29661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, WAITING_TID_TAIL, scbid); 29671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next = SCB_LIST_NULL; 29681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 29691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, waiting_h); 29701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next = ahd_inw_scbram(ahd, SCB_NEXT2); 29711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, scbid); 29731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, SCB_NEXT2, next); 29741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, saved_scbptr); 29761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb->crc_retry_count < AHD_MAX_LQ_CRC_ERRORS) { 29771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (SCB_IS_SILENT(scb) == FALSE) { 29781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 297948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Probable outgoing LQ CRC error. " 29801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Retrying command\n"); 29811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->crc_retry_count++; 29831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 29841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_transaction_status(scb, CAM_UNCOR_PARITY); 29851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_freeze_scb(scb); 29861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_freeze_devq(ahd, scb); 29871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Return unpausing the sequencer. */ 29891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 29901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((ahd_inb(ahd, PERRDIAG) & PARITYERR) != 0) { 29911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 29921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ignore what are really parity errors that 29931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * occur on the last REQ of a free running 29941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * clock prior to going busfree. Some drives 29951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * do not properly active negate just before 29961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * going busfree resulting in a parity glitch. 29971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT1, CLRSCSIPERR|CLRBUSFREE); 29991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 30001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MASKED_ERRORS) != 0) 300148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Parity on last REQ detected " 30021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "during busfree phase.\n", 30031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd)); 30041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 30051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Return unpausing the sequencer. */ 30061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 30071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->src_mode != AHD_MODE_SCSI) { 30091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 30101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 30111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_get_scbptr(ahd); 30131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 30141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 301548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Unexpected PKT busfree condition\n"); 30161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 30171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), 'A', 30181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_LUN(scb), SCB_GET_TAG(scb), 30191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ROLE_INITIATOR, CAM_UNEXP_BUSFREE); 30201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Return restarting the sequencer. */ 30221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (1); 30231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 302448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Unexpected PKT busfree condition\n", ahd_name(ahd)); 30251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 30261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Restart the sequencer. */ 30271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (1); 30281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 30291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 30311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Non-packetized unexpected or expected busfree. 30321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 30331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 30341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_handle_nonpkt_busfree(struct ahd_softc *ahd) 30351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 30361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo devinfo; 30371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 30381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lastphase; 30391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int saved_scsiid; 30401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int saved_lun; 30411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int target; 30421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int initiator_role_id; 30431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 30441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int ppr_busfree; 30451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int printerror; 30461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 30481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Look at what phase we were last in. If its message out, 30491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chances are pretty good that the busfree was in response 30501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to one of our abort requests. 30511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 30521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lastphase = ahd_inb(ahd, LASTPHASE); 30531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_scsiid = ahd_inb(ahd, SAVED_SCSIID); 30541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_lun = ahd_inb(ahd, SAVED_LUN); 30551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target = SCSIID_TARGET(ahd, saved_scsiid); 30561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds initiator_role_id = SCSIID_OUR_ID(saved_scsiid); 30571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_compile_devinfo(&devinfo, initiator_role_id, 30581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target, saved_lun, 'A', ROLE_INITIATOR); 30591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printerror = 1; 30601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_get_scbptr(ahd); 30621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 30631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb != NULL 30641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) != 0) 30651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = NULL; 30661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppr_busfree = (ahd->msg_flags & MSG_FLAG_EXPECT_PPR_BUSFREE) != 0; 30681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lastphase == P_MESGOUT) { 30691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int tag; 30701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tag = SCB_LIST_NULL; 30721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_sent_msg(ahd, AHDMSG_1B, MSG_ABORT_TAG, TRUE) 30731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || ahd_sent_msg(ahd, AHDMSG_1B, MSG_ABORT, TRUE)) { 30741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int found; 30751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int sent_msg; 30761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb == NULL) { 30781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_devinfo(ahd, &devinfo); 307948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Abort for unidentified " 30801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "connection completed.\n"); 30811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* restart the sequencer. */ 30821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (1); 30831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sent_msg = ahd->msgout_buf[ahd->msgout_index - 1]; 30851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 308648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("SCB %d - Abort%s Completed.\n", 30871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_TAG(scb), 30881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sent_msg == MSG_ABORT_TAG ? "" : " Tag"); 30891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sent_msg == MSG_ABORT_TAG) 30911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tag = SCB_GET_TAG(scb); 30921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30938883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke if ((scb->flags & SCB_EXTERNAL_RESET) != 0) { 30948883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke /* 30958883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * This abort is in response to an 30968883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * unexpected switch to command phase 30978883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * for a packetized connection. Since 30988883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * the identify message was never sent, 30998883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * "saved lun" is 0. We really want to 31008883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * abort only the SCB that encountered 31018883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * this error, which could have a different 31028883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * lun. The SCB will be retried so the OS 31038883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * will see the UA after renegotiating to 31048883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * packetized. 31058883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke */ 31068883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke tag = SCB_GET_TAG(scb); 31078883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke saved_lun = scb->hscb->lun; 31088883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke } 31091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found = ahd_abort_scbs(ahd, target, 'A', saved_lun, 31101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tag, ROLE_INITIATOR, 31111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CAM_REQ_ABORTED); 311248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("found == 0x%x\n", found); 31131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printerror = 0; 31141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (ahd_sent_msg(ahd, AHDMSG_1B, 31151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MSG_BUS_DEV_RESET, TRUE)) { 31161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __FreeBSD__ 31171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 31181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Don't mark the user's request for this BDR 31191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as completing with CAM_BDR_SENT. CAM3 31201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * specifies CAM_REQ_CMP. 31211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 31221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb != NULL 31231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && scb->io_ctx->ccb_h.func_code== XPT_RESET_DEV 31241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ahd_match_scb(ahd, scb, target, 'A', 31251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CAM_LUN_WILDCARD, SCB_LIST_NULL, 31261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ROLE_INITIATOR)) 31271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_transaction_status(scb, CAM_REQ_CMP); 31281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 31291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_handle_devreset(ahd, &devinfo, CAM_LUN_WILDCARD, 31301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CAM_BDR_SENT, "Bus Device Reset", 31311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*verbose_level*/0); 31321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printerror = 0; 31331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, FALSE) 31341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ppr_busfree == 0) { 31351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_initiator_tinfo *tinfo; 31361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 31371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 313953467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * PPR Rejected. 314053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * 314153467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * If the previous negotiation was packetized, 314253467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * this could be because the device has been 314353467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * reset without our knowledge. Force our 314453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * current negotiation to async and retry the 314553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * negotiation. Otherwise retry the command 314653467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * with non-ppr negotiation. 31471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 31481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 31491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 315048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("PPR negotiation rejected busfree.\n"); 31511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 31521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo = ahd_fetch_transinfo(ahd, devinfo.channel, 31531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo.our_scsiid, 31541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo.target, &tstate); 315553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ)!=0) { 315653467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_set_width(ahd, &devinfo, 315753467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke MSG_EXT_WDTR_BUS_8_BIT, 315853467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke AHD_TRANS_CUR, 315953467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke /*paused*/TRUE); 316053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_set_syncrate(ahd, &devinfo, 316153467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke /*period*/0, /*offset*/0, 316253467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke /*ppr_options*/0, 316353467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke AHD_TRANS_CUR, 316453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke /*paused*/TRUE); 316553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke /* 316653467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * The expect PPR busfree handler below 316753467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * will effect the retry and necessary 316853467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * abort. 316953467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke */ 317053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke } else { 317153467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke tinfo->curr.transport_version = 2; 317253467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke tinfo->goal.transport_version = 2; 317353467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke tinfo->goal.ppr_options = 0; 3174534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke if (scb != NULL) { 3175534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke /* 3176534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke * Remove any SCBs in the waiting 3177534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke * for selection queue that may 3178534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke * also be for this target so that 3179534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke * command ordering is preserved. 3180534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke */ 3181534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke ahd_freeze_devq(ahd, scb); 3182534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke ahd_qinfifo_requeue_tail(ahd, scb); 3183534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke } 318453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke printerror = 0; 318553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke } 31861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, FALSE) 31871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ppr_busfree == 0) { 31881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 31891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Negotiation Rejected. Go-narrow and 31901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * retry command. 31911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 31921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 31931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 319448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("WDTR negotiation rejected busfree.\n"); 31951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 31961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_width(ahd, &devinfo, 31971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MSG_EXT_WDTR_BUS_8_BIT, 31981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_TRANS_CUR|AHD_TRANS_GOAL, 31991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*paused*/TRUE); 3200534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke if (scb != NULL) { 3201534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke /* 3202534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke * Remove any SCBs in the waiting for 3203534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke * selection queue that may also be for 3204534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke * this target so that command ordering 3205534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke * is preserved. 3206534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke */ 3207534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke ahd_freeze_devq(ahd, scb); 3208534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke ahd_qinfifo_requeue_tail(ahd, scb); 3209534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke } 32101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printerror = 0; 32111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, FALSE) 32121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ppr_busfree == 0) { 32131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 32141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Negotiation Rejected. Go-async and 32151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * retry command. 32161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 32171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 32181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 321948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("SDTR negotiation rejected busfree.\n"); 32201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 32211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_syncrate(ahd, &devinfo, 32221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*period*/0, /*offset*/0, 32231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*ppr_options*/0, 32241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_TRANS_CUR|AHD_TRANS_GOAL, 32251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*paused*/TRUE); 3226534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke if (scb != NULL) { 3227534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke /* 3228534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke * Remove any SCBs in the waiting for 3229534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke * selection queue that may also be for 3230534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke * this target so that command ordering 3231534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke * is preserved. 3232534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke */ 3233534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke ahd_freeze_devq(ahd, scb); 3234534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke ahd_qinfifo_requeue_tail(ahd, scb); 3235534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke } 32361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printerror = 0; 32371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((ahd->msg_flags & MSG_FLAG_EXPECT_IDE_BUSFREE) != 0 32381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ahd_sent_msg(ahd, AHDMSG_1B, 32391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MSG_INITIATOR_DET_ERR, TRUE)) { 32401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 32421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 324348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Expected IDE Busfree\n"); 32441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 32451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printerror = 0; 32461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((ahd->msg_flags & MSG_FLAG_EXPECT_QASREJ_BUSFREE) 32471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ahd_sent_msg(ahd, AHDMSG_1B, 32481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MSG_MESSAGE_REJECT, TRUE)) { 32491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 32511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 325248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Expected QAS Reject Busfree\n"); 32531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 32541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printerror = 0; 32551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 32591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The busfree required flag is honored at the end of 32601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the message phases. We check it last in case we 32611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * had to send some other message that caused a busfree. 32621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3263534ef056db8a8fb6b9d50188d88ed5d1fbc66673Hannes Reinecke if (scb != NULL && printerror != 0 32641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (lastphase == P_MESGIN || lastphase == P_MESGOUT) 32651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ((ahd->msg_flags & MSG_FLAG_EXPECT_PPR_BUSFREE) != 0)) { 32661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_freeze_devq(ahd, scb); 32681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); 32691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_freeze_scb(scb); 32701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->msg_flags & MSG_FLAG_IU_REQ_CHANGED) != 0) { 32711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), 32721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_CHANNEL(ahd, scb), 32731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_LUN(scb), SCB_LIST_NULL, 32741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ROLE_INITIATOR, CAM_REQ_ABORTED); 32751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 32761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 32771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 327848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("PPR Negotiation Busfree.\n"); 32791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 32801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_done(ahd, scb); 32811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printerror = 0; 32831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (printerror != 0) { 32851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int aborted; 32861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aborted = 0; 32881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb != NULL) { 32891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int tag; 32901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((scb->hscb->control & TAG_ENB) != 0) 32921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tag = SCB_GET_TAG(scb); 32931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 32941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tag = SCB_LIST_NULL; 32951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 32961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aborted = ahd_abort_scbs(ahd, target, 'A', 32971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_LUN(scb), tag, 32981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ROLE_INITIATOR, 32991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CAM_UNEXP_BUSFREE); 33001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 33011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 33021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We had not fully identified this connection, 33031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so we cannot abort anything. 33041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 330548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: ", ahd_name(ahd)); 33061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 330748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Unexpected busfree %s, %d SCBs aborted, " 33081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "PRGMCNT == 0x%x\n", 33091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lookup_phase_entry(lastphase)->phasemsg, 33101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aborted, 3311ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke ahd_inw(ahd, PRGMCNT)); 33121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 331353467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke if (lastphase != P_BUSFREE) 331453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_force_renegotiation(ahd, &devinfo); 33151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Always restart the sequencer. */ 33171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (1); 33181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 33191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 33211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_handle_proto_violation(struct ahd_softc *ahd) 33221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 33231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo devinfo; 33241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 33251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 33261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int seq_flags; 33271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int curphase; 33281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lastphase; 33291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int found; 33301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_fetch_devinfo(ahd, &devinfo); 33321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_get_scbptr(ahd); 33331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 33341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_flags = ahd_inb(ahd, SEQ_FLAGS); 33351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curphase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK; 33361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lastphase = ahd_inb(ahd, LASTPHASE); 33371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((seq_flags & NOT_IDENTIFIED) != 0) { 33381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 33401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The reconnecting target either did not send an 33411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * identify message, or did, but we didn't find an SCB 33421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to match. 33431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 33441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_devinfo(ahd, &devinfo); 334548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Target did not send an IDENTIFY message. " 33461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "LASTPHASE = 0x%x.\n", lastphase); 33471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = NULL; 33481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (scb == NULL) { 33491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 33501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We don't seem to have an SCB active for this 33511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transaction. Print an error and reset the bus. 33521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 33531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_devinfo(ahd, &devinfo); 335448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("No SCB found during protocol violation\n"); 33551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto proto_violation_reset; 33561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 33571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_transaction_status(scb, CAM_SEQUENCE_FAIL); 33581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((seq_flags & NO_CDB_SENT) != 0) { 33591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 336048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("No or incomplete CDB sent to device.\n"); 33611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((ahd_inb_scbram(ahd, SCB_CONTROL) 33621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds & STATUS_RCVD) == 0) { 33631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 33641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The target never bothered to provide status to 33651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * us prior to completing the command. Since we don't 33661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * know the disposition of this command, we must attempt 33671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to abort it. Assert ATN and prepare to send an abort 33681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * message. 33691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 33701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 337148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Completed command without status.\n"); 33721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 33731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 337448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Unknown protocol violation.\n"); 33751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 33761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((lastphase & ~P_DATAIN_DT) == 0 33791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || lastphase == P_COMMAND) { 33801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsproto_violation_reset: 33811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 33821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Target either went directly to data 33831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * phase or didn't respond to our ATN. 33841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The only safe thing to do is to blow 33851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it away with a bus reset. 33861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 33871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found = ahd_reset_channel(ahd, 'A', TRUE); 338848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Issued Channel %c Bus Reset. " 33891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%d SCBs aborted\n", ahd_name(ahd), 'A', found); 33901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 33911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 33921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Leave the selection hardware off in case 33931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this abort attempt will affect yet to 33941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * be sent commands. 33951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 33961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ0, 33971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SCSISEQ0) & ~ENSELO); 33981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_assert_atn(ahd); 33991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, MSG_OUT, HOST_MSG); 34001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb == NULL) { 34011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_devinfo(ahd, &devinfo); 34021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_buf[0] = MSG_ABORT_TASK; 34031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len = 1; 34041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 34051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; 34061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 34071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 34081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->flags |= SCB_ABORT; 34091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 341048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Protocol violation %s. Attempting to abort.\n", 34111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lookup_phase_entry(curphase)->phasemsg); 34121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 34141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 34161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Force renegotiation to occur the next time we initiate 34171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a command to the current device. 34181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 34191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 34201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_force_renegotiation(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) 34211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 34221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_initiator_tinfo *targ_info; 34231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 34241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 34261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { 34271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_devinfo(ahd, devinfo); 342848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Forcing renegotiation\n"); 34291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 34311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds targ_info = ahd_fetch_transinfo(ahd, 34321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->channel, 34331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->our_scsiid, 34341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, 34351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &tstate); 34361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_update_neg_request(ahd, devinfo, tstate, 34371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds targ_info, AHD_NEG_IF_NON_ASYNC); 34381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 34391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AHD_MAX_STEPS 2000 3441289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void 34421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_clear_critical_section(struct ahd_softc *ahd) 34431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 34441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mode_state saved_modes; 34451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int stepping; 34461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int steps; 34471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int first_instr; 34481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int simode0; 34491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int simode1; 34501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int simode3; 34511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lqimode0; 34521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lqimode1; 34531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lqomode0; 34541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lqomode1; 34551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->num_critical_sections == 0) 34571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 34581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stepping = FALSE; 34601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds steps = 0; 34611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds first_instr = 0; 34621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds simode0 = 0; 34631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds simode1 = 0; 34641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds simode3 = 0; 34651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lqimode0 = 0; 34661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lqimode1 = 0; 34671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lqomode0 = 0; 34681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lqomode1 = 0; 34691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_modes = ahd_save_modes(ahd); 34701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 34711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cs *cs; 34721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int seqaddr; 34731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int i; 34741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 3476ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke seqaddr = ahd_inw(ahd, CURADDR); 34771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cs = ahd->critical_sections; 34791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ahd->num_critical_sections; i++, cs++) { 34801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cs->begin < seqaddr && cs->end >= seqaddr) 34821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 34831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i == ahd->num_critical_sections) 34861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 34871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (steps > AHD_MAX_STEPS) { 348948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Infinite loop in critical section\n" 34901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%s: First Instruction 0x%x now 0x%x\n", 34911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), ahd_name(ahd), first_instr, 34921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seqaddr); 34931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 34941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("critical section loop"); 34951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds steps++; 34981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 34991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MISC) != 0) 350048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Single stepping at 0x%x\n", ahd_name(ahd), 35011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seqaddr); 35021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 35031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (stepping == FALSE) { 35041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds first_instr = seqaddr; 35061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 35071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds simode0 = ahd_inb(ahd, SIMODE0); 35081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds simode3 = ahd_inb(ahd, SIMODE3); 35091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lqimode0 = ahd_inb(ahd, LQIMODE0); 35101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lqimode1 = ahd_inb(ahd, LQIMODE1); 35111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lqomode0 = ahd_inb(ahd, LQOMODE0); 35121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lqomode1 = ahd_inb(ahd, LQOMODE1); 35131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SIMODE0, 0); 35141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SIMODE3, 0); 35151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQIMODE0, 0); 35161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQIMODE1, 0); 35171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQOMODE0, 0); 35181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQOMODE1, 0); 35191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 35201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds simode1 = ahd_inb(ahd, SIMODE1); 35211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 35221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We don't clear ENBUSFREE. Unfortunately 35231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we cannot re-enable busfree detection within 35241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the current connection, so we must leave it 35251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on while single stepping. 35261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 35271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SIMODE1, simode1 & ENBUSFREE); 35281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEQCTL0, ahd_inb(ahd, SEQCTL0) | STEP); 35291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stepping = TRUE; 35301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT1, CLRBUSFREE); 35321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRINT, CLRSCSIINT); 35331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); 35341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, HCNTRL, ahd->unpause); 35351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!ahd_is_paused(ahd)) 35361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_delay(200); 35371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_update_modes(ahd); 35381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (stepping) { 35401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 35411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SIMODE0, simode0); 35421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SIMODE3, simode3); 35431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQIMODE0, lqimode0); 35441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQIMODE1, lqimode1); 35451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQOMODE0, lqomode0); 35461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQOMODE1, lqomode1); 35471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 35481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEQCTL0, ahd_inb(ahd, SEQCTL0) & ~STEP); 35491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SIMODE1, simode1); 35501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 355125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * SCSIINT seems to glitch occasionally when 35521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the interrupt masks are restored. Clear SCSIINT 35531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * one more time so that only persistent errors 35541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are seen as a real interrupt. 35551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 35561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRINT, CLRSCSIINT); 35571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restore_modes(ahd, saved_modes); 35591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 35601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 35621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear any pending interrupt status. 35631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3564289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void 35651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_clear_intstat(struct ahd_softc *ahd) 35661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 35671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 35681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 35691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear any interrupt conditions this may have caused */ 35701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRLQIINT0, CLRLQIATNQAS|CLRLQICRCT1|CLRLQICRCT2 35711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds |CLRLQIBADLQT|CLRLQIATNLQ|CLRLQIATNCMD); 35721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRLQIINT1, CLRLQIPHASE_LQ|CLRLQIPHASE_NLQ|CLRLIQABORT 35731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds |CLRLQICRCI_LQ|CLRLQICRCI_NLQ|CLRLQIBADLQI 35741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds |CLRLQIOVERI_LQ|CLRLQIOVERI_NLQ|CLRNONPACKREQ); 35751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRLQOINT0, CLRLQOTARGSCBPERR|CLRLQOSTOPT2|CLRLQOATNLQ 35761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds |CLRLQOATNPKT|CLRLQOTCRC); 35771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRLQOINT1, CLRLQOINITSCBPERR|CLRLQOSTOPI2|CLRLQOBADQAS 35781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds |CLRLQOBUSFREE|CLRLQOPHACHGINPKT); 35791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) { 35801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRLQOINT0, 0); 35811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRLQOINT1, 0); 35821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT3, CLRNTRAMPERR|CLROSRAMPERR); 35841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI 35851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds |CLRBUSFREE|CLRSCSIPERR|CLRREQINIT); 35861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO 35871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds |CLRIOERR|CLROVERRUN); 35881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRINT, CLRSCSIINT); 35891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 35901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**************************** Debugging Routines ******************************/ 35921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 35931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuint32_t ahd_debug = AHD_DEBUG_OPTS; 35941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3595289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 3596289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk#if 0 35971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 35981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_print_scb(struct scb *scb) 35991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hardware_scb *hscb; 36011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 36021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb = scb->hscb; 360448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n", 36051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void *)scb, 36061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb->control, 36071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb->scsiid, 36081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb->lun, 36091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb->cdb_len); 361048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Shared Data: "); 36111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < sizeof(hscb->shared_data.idata.cdb); i++) 361248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%#02x", hscb->shared_data.idata.cdb[i]); 361348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk(" dataptr:%#x%x datacnt:%#x sgptr:%#x tag:%#x\n", 36141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (uint32_t)((ahd_le64toh(hscb->dataptr) >> 32) & 0xFFFFFFFF), 36151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (uint32_t)(ahd_le64toh(hscb->dataptr) & 0xFFFFFFFF), 36161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_le32toh(hscb->datacnt), 36171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_le32toh(hscb->sgptr), 36181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_TAG(scb)); 36191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_sglist(scb); 36201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3621289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk#endif /* 0 */ 36221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************* Transfer Negotiation *******************************/ 36241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 36251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate per target mode instance (ID we respond to as a target) 36261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transfer negotiation data structures. 36271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 36281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ahd_tmode_tstate * 36291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_alloc_tstate(struct ahd_softc *ahd, u_int scsi_id, char channel) 36301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *master_tstate; 36321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 36331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 36341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds master_tstate = ahd->enabled_targets[ahd->our_id]; 36361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->enabled_targets[scsi_id] != NULL 36371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ahd->enabled_targets[scsi_id] != master_tstate) 36381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("%s: ahd_alloc_tstate - Target already allocated", 36391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd)); 364048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg tstate = kmalloc(sizeof(*tstate), GFP_ATOMIC); 36411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tstate == NULL) 36421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (NULL); 36431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 36451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we have allocated a master tstate, copy user settings from 36461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the master tstate (taken from SRAM or the EEPROM) for this 36471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * channel, but reset our current and goal settings to async/narrow 36481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * until an initiator talks to us. 36491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 36501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (master_tstate != NULL) { 36511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(tstate, master_tstate, sizeof(*tstate)); 36521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns)); 36531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 16; i++) { 36541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&tstate->transinfo[i].curr, 0, 36551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(tstate->transinfo[i].curr)); 36561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&tstate->transinfo[i].goal, 0, 36571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(tstate->transinfo[i].goal)); 36581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 36601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(tstate, 0, sizeof(*tstate)); 36611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->enabled_targets[scsi_id] = tstate; 36621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (tstate); 36631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_TARGET_MODE 36661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 36671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free per target mode instance (ID we respond to as a target) 36681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transfer negotiation data structures. 36691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 36701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 36711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_free_tstate(struct ahd_softc *ahd, u_int scsi_id, char channel, int force) 36721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 36741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 36761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Don't clean up our "master" tstate. 36771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It has our default user settings. 36781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 36791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scsi_id == ahd->our_id 36801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && force == FALSE) 36811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 36821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tstate = ahd->enabled_targets[scsi_id]; 36841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tstate != NULL) 368548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(tstate); 36861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->enabled_targets[scsi_id] = NULL; 36871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 36891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 36911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called when we have an active connection to a target on the bus, 36921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this function finds the nearest period to the input period limited 36931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by the capabilities of the bus connectivity of and sync settings for 36941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the target. 36951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3696678e80a32fcce02323bbd753ed8944ea92d0a2d5Harvey Harrisonstatic void 36971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_devlimited_syncrate(struct ahd_softc *ahd, 36981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_initiator_tinfo *tinfo, 36991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int *period, u_int *ppr_options, role_t role) 37001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 37011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_transinfo *transinfo; 37021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int maxsync; 37031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_inb(ahd, SBLKCTL) & ENAB40) != 0 37051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ahd_inb(ahd, SSTAT2) & EXP_ACTIVE) == 0) { 37061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxsync = AHD_SYNCRATE_PACED; 37071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 37081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxsync = AHD_SYNCRATE_ULTRA; 37091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Can't do DT related options on an SE bus */ 37101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *ppr_options &= MSG_EXT_PPR_QAS_REQ; 37111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 37131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Never allow a value higher than our current goal 37141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * period otherwise we may allow a target initiated 37151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * negotiation to go above the limit as set by the 37161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * user. In the case of an initiator initiated 37171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sync negotiation, we limit based on the user 37181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * setting. This allows the system to still accept 37191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * incoming negotiations even if target initiated 37201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * negotiation is not performed. 37211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (role == ROLE_TARGET) 37231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds transinfo = &tinfo->user; 37241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 37251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds transinfo = &tinfo->goal; 37261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *ppr_options &= (transinfo->ppr_options|MSG_EXT_PPR_PCOMP_EN); 37271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transinfo->width == MSG_EXT_WDTR_BUS_8_BIT) { 37286d07cb71fdacc710fd9816cddb5c2df0f7bd96b4Amol Lad maxsync = max(maxsync, (u_int)AHD_SYNCRATE_ULTRA2); 37291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *ppr_options &= ~MSG_EXT_PPR_DT_REQ; 37301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transinfo->period == 0) { 37321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *period = 0; 37331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *ppr_options = 0; 37341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 37356d07cb71fdacc710fd9816cddb5c2df0f7bd96b4Amol Lad *period = max(*period, (u_int)transinfo->period); 37361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_find_syncrate(ahd, period, ppr_options, maxsync); 37371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 37391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 37411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Look up the valid period to SCSIRATE conversion in our table. 37421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return the period and offset that should be sent to the target 37431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if this was the beginning of an SDTR. 37441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 37461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_find_syncrate(struct ahd_softc *ahd, u_int *period, 37471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int *ppr_options, u_int maxsync) 37481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 37491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*period < maxsync) 37501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *period = maxsync; 37511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((*ppr_options & MSG_EXT_PPR_DT_REQ) != 0 37531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && *period > AHD_SYNCRATE_MIN_DT) 37541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *ppr_options &= ~MSG_EXT_PPR_DT_REQ; 37551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*period > AHD_SYNCRATE_MIN) 37571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *period = 0; 37581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Honor PPR option conformance rules. */ 37601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*period > AHD_SYNCRATE_PACED) 37611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *ppr_options &= ~MSG_EXT_PPR_RTI; 37621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((*ppr_options & MSG_EXT_PPR_IU_REQ) == 0) 37641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *ppr_options &= (MSG_EXT_PPR_DT_REQ|MSG_EXT_PPR_QAS_REQ); 37651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0) 37671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *ppr_options &= MSG_EXT_PPR_QAS_REQ; 37681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Skip all PACED only entries if IU is not available */ 37701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((*ppr_options & MSG_EXT_PPR_IU_REQ) == 0 37711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && *period < AHD_SYNCRATE_DT) 37721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *period = AHD_SYNCRATE_DT; 37731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Skip all DT only entries if DT is not available */ 37751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0 37761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && *period < AHD_SYNCRATE_ULTRA2) 37771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *period = AHD_SYNCRATE_ULTRA2; 37781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 37791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 37811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Truncate the given synchronous offset to a value the 37821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * current adapter type and syncrate are capable of. 37831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3784289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void 37851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_validate_offset(struct ahd_softc *ahd, 37861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_initiator_tinfo *tinfo, 37871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int period, u_int *offset, int wide, 37881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds role_t role) 37891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 37901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int maxoffset; 37911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Limit offset to what we can do */ 37931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (period == 0) 37941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxoffset = 0; 37951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (period <= AHD_SYNCRATE_PACED) { 37961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) 37971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxoffset = MAX_OFFSET_PACED_BUG; 37981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 37991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxoffset = MAX_OFFSET_PACED; 38001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 38011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxoffset = MAX_OFFSET_NON_PACED; 38026d07cb71fdacc710fd9816cddb5c2df0f7bd96b4Amol Lad *offset = min(*offset, maxoffset); 38031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tinfo != NULL) { 38041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (role == ROLE_TARGET) 38056d07cb71fdacc710fd9816cddb5c2df0f7bd96b4Amol Lad *offset = min(*offset, (u_int)tinfo->user.offset); 38061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 38076d07cb71fdacc710fd9816cddb5c2df0f7bd96b4Amol Lad *offset = min(*offset, (u_int)tinfo->goal.offset); 38081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 38101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 38121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Truncate the given transfer width parameter to a value the 38131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * current adapter type is capable of. 38141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3815289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void 38161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_validate_width(struct ahd_softc *ahd, struct ahd_initiator_tinfo *tinfo, 38171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int *bus_width, role_t role) 38181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 38191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (*bus_width) { 38201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 38211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->features & AHD_WIDE) { 38221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Respond Wide */ 38231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *bus_width = MSG_EXT_WDTR_BUS_16_BIT; 38241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 38251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 38271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_EXT_WDTR_BUS_8_BIT: 38281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *bus_width = MSG_EXT_WDTR_BUS_8_BIT; 38291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 38301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tinfo != NULL) { 38321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (role == ROLE_TARGET) 38336d07cb71fdacc710fd9816cddb5c2df0f7bd96b4Amol Lad *bus_width = min((u_int)tinfo->user.width, *bus_width); 38341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 38356d07cb71fdacc710fd9816cddb5c2df0f7bd96b4Amol Lad *bus_width = min((u_int)tinfo->goal.width, *bus_width); 38361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 38381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 38401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update the bitmask of targets for which the controller should 384125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * negotiate with at the next convenient opportunity. This currently 38421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * means the next time we send the initial identify messages for 38431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a new transaction. 38441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 38451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 38461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_update_neg_request(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 38471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate, 38481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_initiator_tinfo *tinfo, ahd_neg_type neg_type) 38491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 38501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int auto_negotiate_orig; 38511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds auto_negotiate_orig = tstate->auto_negotiate; 38531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (neg_type == AHD_NEG_ALWAYS) { 38541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 38551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Force our "current" settings to be 38561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * unknown so that unless a bus reset 38571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * occurs the need to renegotiate is 38581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * recorded persistently. 38591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 38601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_WIDE) != 0) 38611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->curr.width = AHD_WIDTH_UNKNOWN; 38621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->curr.period = AHD_PERIOD_UNKNOWN; 38631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->curr.offset = AHD_OFFSET_UNKNOWN; 38641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tinfo->curr.period != tinfo->goal.period 38661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || tinfo->curr.width != tinfo->goal.width 38671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || tinfo->curr.offset != tinfo->goal.offset 38681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || tinfo->curr.ppr_options != tinfo->goal.ppr_options 38691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || (neg_type == AHD_NEG_IF_NON_ASYNC 38701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (tinfo->goal.offset != 0 38711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT 38721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || tinfo->goal.ppr_options != 0))) 38731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tstate->auto_negotiate |= devinfo->target_mask; 38741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 38751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tstate->auto_negotiate &= ~devinfo->target_mask; 38761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (auto_negotiate_orig != tstate->auto_negotiate); 38781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 38791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 38811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update the user/goal/curr tables of synchronous negotiation 38821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parameters as well as, in the case of a current or active update, 38831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * any data structures on the host controller. In the case of an 38841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * active update, the specified target is currently talking to us on 38851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the bus, so the transfer parameter update must take effect 38861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * immediately. 38871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 38881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 38891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 38901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int period, u_int offset, u_int ppr_options, 38911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int type, int paused) 38921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 38931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_initiator_tinfo *tinfo; 38941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 38951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int old_period; 38961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int old_offset; 38971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int old_ppr; 38981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int active; 38991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int update_needed; 39001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds active = (type & AHD_TRANS_ACTIVE) == AHD_TRANS_ACTIVE; 39021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_needed = 0; 39031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (period == 0 || offset == 0) { 39051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds period = 0; 39061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = 0; 39071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid, 39101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, &tstate); 39111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((type & AHD_TRANS_USER) != 0) { 39131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->user.period = period; 39141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->user.offset = offset; 39151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->user.ppr_options = ppr_options; 39161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((type & AHD_TRANS_GOAL) != 0) { 39191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->goal.period = period; 39201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->goal.offset = offset; 39211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->goal.ppr_options = ppr_options; 39221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old_period = tinfo->curr.period; 39251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old_offset = tinfo->curr.offset; 39261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old_ppr = tinfo->curr.ppr_options; 39271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((type & AHD_TRANS_CUR) != 0 39291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (old_period != period 39301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || old_offset != offset 39311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || old_ppr != ppr_options)) { 39321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_needed++; 39341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->curr.period = period; 39361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->curr.offset = offset; 39371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->curr.ppr_options = ppr_options; 39381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_send_async(ahd, devinfo->channel, devinfo->target, 3940f89d0a4e1d01168f20f9e8273de7dfc094b2a430Hannes Reinecke CAM_LUN_WILDCARD, AC_TRANSFER_NEG); 39411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bootverbose) { 39421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (offset != 0) { 39431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int options; 39441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 394548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: target %d synchronous with " 39461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "period = 0x%x, offset = 0x%x", 39471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->target, 39481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds period, offset); 39491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds options = 0; 39501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ppr_options & MSG_EXT_PPR_RD_STRM) != 0) { 395148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(RDSTRM"); 39521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds options++; 39531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) { 395548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s", options ? "|DT" : "(DT"); 39561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds options++; 39571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { 395948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s", options ? "|IU" : "(IU"); 39601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds options++; 39611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ppr_options & MSG_EXT_PPR_RTI) != 0) { 396348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s", options ? "|RTI" : "(RTI"); 39641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds options++; 39651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ppr_options & MSG_EXT_PPR_QAS_REQ) != 0) { 396748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s", options ? "|QAS" : "(QAS"); 39681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds options++; 39691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (options != 0) 397148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk(")\n"); 39721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 397348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\n"); 39741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 397548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: target %d using " 39761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "asynchronous transfers%s\n", 39771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->target, 39781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ppr_options & MSG_EXT_PPR_QAS_REQ) != 0 39791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? "(QAS)" : ""); 39801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 39841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Always refresh the neg-table to handle the case of the 39851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sequencer setting the ENATNO bit for a MK_MESSAGE request. 39861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We will always renegotiate in that case if this is a 39871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * packetized request. Also manage the busfree expected flag 39881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from this common routine so that we catch changes due to 39891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WDTR or SDTR messages. 39901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 39911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((type & AHD_TRANS_CUR) != 0) { 39921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!paused) 39931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pause(ahd); 39941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_update_neg_table(ahd, devinfo, &tinfo->curr); 39951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!paused) 39961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 39971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->msg_type != MSG_TYPE_NONE) { 39981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((old_ppr & MSG_EXT_PPR_IU_REQ) 39991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds != (ppr_options & MSG_EXT_PPR_IU_REQ)) { 40001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 40011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { 40021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_devinfo(ahd, devinfo); 400348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Expecting IU Change busfree\n"); 40041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 40061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE 40071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | MSG_FLAG_IU_REQ_CHANGED; 40081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((old_ppr & MSG_EXT_PPR_IU_REQ) != 0) { 40101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 40111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 401248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("PPR with IU_REQ outstanding\n"); 40131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 40141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE; 40151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_needed += ahd_update_neg_request(ahd, devinfo, tstate, 40201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo, AHD_NEG_TO_GOAL); 40211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (update_needed && active) 40231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_update_pending_scbs(ahd); 40241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 40251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 40271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update the user/goal/curr tables of wide negotiation 40281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parameters as well as, in the case of a current or active update, 40291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * any data structures on the host controller. In the case of an 40301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * active update, the specified target is currently talking to us on 40311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the bus, so the transfer parameter update must take effect 40321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * immediately. 40331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 40341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 40351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 40361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int width, u_int type, int paused) 40371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 40381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_initiator_tinfo *tinfo; 40391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 40401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int oldwidth; 40411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int active; 40421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int update_needed; 40431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds active = (type & AHD_TRANS_ACTIVE) == AHD_TRANS_ACTIVE; 40451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_needed = 0; 40461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid, 40471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, &tstate); 40481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((type & AHD_TRANS_USER) != 0) 40501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->user.width = width; 40511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((type & AHD_TRANS_GOAL) != 0) 40531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->goal.width = width; 40541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds oldwidth = tinfo->curr.width; 40561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((type & AHD_TRANS_CUR) != 0 && oldwidth != width) { 40571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_needed++; 40591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->curr.width = width; 40611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_send_async(ahd, devinfo->channel, devinfo->target, 4062f89d0a4e1d01168f20f9e8273de7dfc094b2a430Hannes Reinecke CAM_LUN_WILDCARD, AC_TRANSFER_NEG); 40631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bootverbose) { 406448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: target %d using %dbit transfers\n", 40651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->target, 40661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8 * (0x01 << width)); 40671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((type & AHD_TRANS_CUR) != 0) { 40711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!paused) 40721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pause(ahd); 40731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_update_neg_table(ahd, devinfo, &tinfo->curr); 40741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!paused) 40751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 40761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_needed += ahd_update_neg_request(ahd, devinfo, tstate, 40791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo, AHD_NEG_TO_GOAL); 40801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (update_needed && active) 40811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_update_pending_scbs(ahd); 40821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 40841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 40861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update the current state of tagged queuing for a given target. 40871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4088ca3c3323931ef925497a9ffcb61c5eebe55f8e2bAdrian Bunkstatic void 4089f89d0a4e1d01168f20f9e8273de7dfc094b2a430Hannes Reineckeahd_set_tags(struct ahd_softc *ahd, struct scsi_cmnd *cmd, 4090f89d0a4e1d01168f20f9e8273de7dfc094b2a430Hannes Reinecke struct ahd_devinfo *devinfo, ahd_queue_alg alg) 40911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4092f89d0a4e1d01168f20f9e8273de7dfc094b2a430Hannes Reinecke struct scsi_device *sdev = cmd->device; 4093f89d0a4e1d01168f20f9e8273de7dfc094b2a430Hannes Reinecke 4094f89d0a4e1d01168f20f9e8273de7dfc094b2a430Hannes Reinecke ahd_platform_set_tags(ahd, sdev, devinfo, alg); 40951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_send_async(ahd, devinfo->channel, devinfo->target, 4096f89d0a4e1d01168f20f9e8273de7dfc094b2a430Hannes Reinecke devinfo->lun, AC_TRANSFER_NEG); 40971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 40981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 41001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_update_neg_table(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 41011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_transinfo *tinfo) 41021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 41031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mode_state saved_modes; 41041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int period; 41051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int ppr_opts; 41061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int con_opts; 41071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int offset; 41081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int saved_negoaddr; 41091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t iocell_opts[sizeof(ahd->iocell_opts)]; 41101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_modes = ahd_save_modes(ahd); 41121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 41131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_negoaddr = ahd_inb(ahd, NEGOADDR); 41151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, NEGOADDR, devinfo->target); 41161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds period = tinfo->period; 41171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = tinfo->offset; 41181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(iocell_opts, ahd->iocell_opts, sizeof(ahd->iocell_opts)); 41191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppr_opts = tinfo->ppr_options & (MSG_EXT_PPR_QAS_REQ|MSG_EXT_PPR_DT_REQ 41201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds |MSG_EXT_PPR_IU_REQ|MSG_EXT_PPR_RTI); 41211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds con_opts = 0; 41221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (period == 0) 41231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds period = AHD_SYNCRATE_ASYNC; 41241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (period == AHD_SYNCRATE_160) { 41251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) { 41271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 41281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When the SPI4 spec was finalized, PACE transfers 41291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * was not made a configurable option in the PPR 41301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * message. Instead it is assumed to be enabled for 41311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * any syncrate faster than 80MHz. Nevertheless, 41321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Harpoon2A4 allows this to be configurable. 41331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Harpoon2A4 also assumes at most 2 data bytes per 41351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * negotiated REQ/ACK offset. Paced transfers take 41361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4, so we must adjust our offset. 41371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppr_opts |= PPROPT_PACE; 41391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset *= 2; 41401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 41421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Harpoon2A assumed that there would be a 4143d91ab4e7df0c0c9f98c830e04e875f39d41b21f6Alan Cox * fallback rate between 160MHz and 80MHz, 41441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so 7 is used as the period factor rather 41451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * than 8 for 160MHz. 41461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds period = AHD_SYNCRATE_REVA_160; 41481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((tinfo->ppr_options & MSG_EXT_PPR_PCOMP_EN) == 0) 41501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= 41511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ~AHD_PRECOMP_MASK; 41521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 41531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 41541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Precomp should be disabled for non-paced transfers. 41551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= ~AHD_PRECOMP_MASK; 41571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_NEW_IOCELL_OPTS) != 0 415911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke && (ppr_opts & MSG_EXT_PPR_DT_REQ) != 0 416011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke && (ppr_opts & MSG_EXT_PPR_IU_REQ) == 0) { 41611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 41621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Slow down our CRC interval to be 416311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * compatible with non-packetized 416411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * U160 devices that can't handle a 416511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * CRC at full speed. 41661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds con_opts |= ENSLOWCRC; 41681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 416911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 417011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) { 417111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 417211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * On H2A4, revert to a slower slewrate 417311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * on non-paced transfers. 417411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 417511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= 417611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ~AHD_SLEWRATE_MASK; 417711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } 41781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PRECOMP_SLEW); 41811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, ANNEXDAT, iocell_opts[AHD_PRECOMP_SLEW_INDEX]); 41821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_AMPLITUDE); 41831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, ANNEXDAT, iocell_opts[AHD_AMPLITUDE_INDEX]); 41841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, NEGPERIOD, period); 41861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, NEGPPROPTS, ppr_opts); 41871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, NEGOFFSET, offset); 41881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tinfo->width == MSG_EXT_WDTR_BUS_16_BIT) 41901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds con_opts |= WIDEXFER; 41911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 41933fb086126462c2de06dddaec58981d8827be100dHannes Reinecke * Slow down our CRC interval to be 41943fb086126462c2de06dddaec58981d8827be100dHannes Reinecke * compatible with packetized U320 devices 41953fb086126462c2de06dddaec58981d8827be100dHannes Reinecke * that can't handle a CRC at full speed 41963fb086126462c2de06dddaec58981d8827be100dHannes Reinecke */ 41973fb086126462c2de06dddaec58981d8827be100dHannes Reinecke if (ahd->features & AHD_AIC79XXB_SLOWCRC) { 41983fb086126462c2de06dddaec58981d8827be100dHannes Reinecke con_opts |= ENSLOWCRC; 41993fb086126462c2de06dddaec58981d8827be100dHannes Reinecke } 42003fb086126462c2de06dddaec58981d8827be100dHannes Reinecke 42013fb086126462c2de06dddaec58981d8827be100dHannes Reinecke /* 42021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * During packetized transfers, the target will 420325985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * give us the opportunity to send command packets 42041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * without us asserting attention. 42051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((tinfo->ppr_options & MSG_EXT_PPR_IU_REQ) == 0) 42071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds con_opts |= ENAUTOATNO; 42081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, NEGCONOPTS, con_opts); 42091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, NEGOADDR, saved_negoaddr); 42101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restore_modes(ahd, saved_modes); 42111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 42121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 42141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When the transfer settings for a connection change, setup for 42151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * negotiation in pending SCBs to effect the change as quickly as 42161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * possible. We also cancel any negotiations that are scheduled 42171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for inflight SCBs that have not been started yet. 42181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 42201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_update_pending_scbs(struct ahd_softc *ahd) 42211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 42221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *pending_scb; 42231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pending_scb_count; 42241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int paused; 42251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int saved_scbptr; 42261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mode_state saved_modes; 42271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 42291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Traverse the pending SCB list and ensure that all of the 42301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCBs there have the proper settings. We can only safely 42311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * clear the negotiation required flag (setting requires the 42321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * execution queue to be modified) and this is only possible 42331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if we are not already attempting to select out for this 42341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCB. For this reason, all callers only call this routine 42351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if we are changing the negotiation settings for the currently 42361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * active transaction on the bus. 42371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pending_scb_count = 0; 42391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) { 42401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo devinfo; 42411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_initiator_tinfo *tinfo; 42421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 42431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_scb_devinfo(ahd, &devinfo, pending_scb); 42451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo = ahd_fetch_transinfo(ahd, devinfo.channel, 42461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo.our_scsiid, 42471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo.target, &tstate); 42481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((tstate->auto_negotiate & devinfo.target_mask) == 0 42491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (pending_scb->flags & SCB_AUTO_NEGOTIATE) != 0) { 42501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pending_scb->flags &= ~SCB_AUTO_NEGOTIATE; 425153467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke pending_scb->hscb->control &= ~MK_MESSAGE; 42521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 42531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_sync_scb(ahd, pending_scb, 42541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 42551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pending_scb_count++; 42561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 42571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pending_scb_count == 0) 42591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 42601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_is_paused(ahd)) { 42621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds paused = 1; 42631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 42641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds paused = 0; 42651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pause(ahd); 42661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 42671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 42691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Force the sequencer to reinitialize the selection for 42701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the command at the head of the execution queue if it 42711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has already been setup. The negotiation changes may 427211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * effect whether we select-out with ATN. It is only 427311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * safe to clear ENSELO when the bus is not free and no 427411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * selection is in progres or completed. 42751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_modes = ahd_save_modes(ahd); 42771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 427811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if ((ahd_inb(ahd, SCSISIGI) & BSYI) != 0 427911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke && (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) == 0) 428011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO); 42811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_scbptr = ahd_get_scbptr(ahd); 42821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Ensure that the hscbs down on the card match the new information */ 428353467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) { 428453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke u_int scb_tag; 42851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int control; 42861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 428753467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke scb_tag = SCB_GET_TAG(pending_scb); 42881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, scb_tag); 42891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control = ahd_inb_scbram(ahd, SCB_CONTROL); 42901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control &= ~MK_MESSAGE; 429153467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke control |= pending_scb->hscb->control & MK_MESSAGE; 42921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCB_CONTROL, control); 42931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 42941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, saved_scbptr); 42951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restore_modes(ahd, saved_modes); 42961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (paused == 0) 42981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 42991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 43001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**************************** Pathing Information *****************************/ 43021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 43031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_fetch_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) 43041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 43051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mode_state saved_modes; 43061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int saved_scsiid; 43071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds role_t role; 43081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int our_id; 43091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_modes = ahd_save_modes(ahd); 43111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 43121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_inb(ahd, SSTAT0) & TARGET) 43141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds role = ROLE_TARGET; 43151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 43161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds role = ROLE_INITIATOR; 43171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (role == ROLE_TARGET 43191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ahd_inb(ahd, SEQ_FLAGS) & CMDPHASE_PENDING) != 0) { 43201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We were selected, so pull our id from TARGIDIN */ 43211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds our_id = ahd_inb(ahd, TARGIDIN) & OID; 43221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (role == ROLE_TARGET) 43231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds our_id = ahd_inb(ahd, TOWNID); 43241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 43251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds our_id = ahd_inb(ahd, IOWNID); 43261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_scsiid = ahd_inb(ahd, SAVED_SCSIID); 43281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_compile_devinfo(devinfo, 43291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds our_id, 43301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCSIID_TARGET(ahd, saved_scsiid), 43311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SAVED_LUN), 43321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCSIID_CHANNEL(ahd, saved_scsiid), 43331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds role); 43341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restore_modes(ahd, saved_modes); 43351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 43361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 43381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_print_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) 43391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 434048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s:%c:%d:%d: ", ahd_name(ahd), 'A', 43411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, devinfo->lun); 43421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 43431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4344980b306a297725d4f25c779ca15086de757acadfDenys Vlasenkostatic const struct ahd_phase_table_entry* 43451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_lookup_phase_entry(int phase) 43461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4347980b306a297725d4f25c779ca15086de757acadfDenys Vlasenko const struct ahd_phase_table_entry *entry; 4348980b306a297725d4f25c779ca15086de757acadfDenys Vlasenko const struct ahd_phase_table_entry *last_entry; 43491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 43511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * num_phases doesn't include the default entry which 43521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will be returned if the phase doesn't match. 43531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 43541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last_entry = &ahd_phase_table[num_phases]; 43551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (entry = ahd_phase_table; entry < last_entry; entry++) { 43561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (phase == entry->phase) 43571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 43581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 43591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (entry); 43601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 43611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 43631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_compile_devinfo(struct ahd_devinfo *devinfo, u_int our_id, u_int target, 43641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lun, char channel, role_t role) 43651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 43661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->our_scsiid = our_id; 43671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target = target; 43681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->lun = lun; 43691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target_offset = target; 43701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->channel = channel; 43711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->role = role; 43721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (channel == 'B') 43731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target_offset += 8; 43741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target_mask = (0x01 << devinfo->target_offset); 43751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 43761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 43781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_scb_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 43791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb) 43801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 43811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds role_t role; 43821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int our_id; 43831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds our_id = SCSIID_OUR_ID(scb->hscb->scsiid); 43851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds role = ROLE_INITIATOR; 43861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((scb->hscb->control & TARGET_SCB) != 0) 43871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds role = ROLE_TARGET; 43881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_compile_devinfo(devinfo, our_id, SCB_GET_TARGET(ahd, scb), 43891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_LUN(scb), SCB_GET_CHANNEL(ahd, scb), role); 43901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 43911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************ Message Phase Processing ****************************/ 43941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 43951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When an initiator transaction with the MK_MESSAGE flag either reconnects 43961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or enters the initial message out phase, we are interrupted. Fill our 43971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * outgoing message buffer with the appropriate message and beging handing 43981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the message phase(s) manually. 43991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 44011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_setup_initiator_msgout(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 44021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb) 44031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 44041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 44051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * To facilitate adding multiple messages together, 44061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * each routine should increment the index and len 44071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * variables instead of setting them explicitly. 44081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 44101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len = 0; 44111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_currently_packetized(ahd)) 44131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_flags |= MSG_FLAG_PACKETIZED; 44141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->send_msg_perror 44161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ahd_inb(ahd, MSG_OUT) == HOST_MSG) { 44171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_buf[ahd->msgout_index++] = ahd->send_msg_perror; 44181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len++; 44191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; 44201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 44211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 442248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Setting up for Parity Error delivery\n"); 44231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 44241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 44251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (scb == NULL) { 442648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: WARNING. No pending message for " 44271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "I_T msgin. Issuing NO-OP\n", ahd_name(ahd)); 44281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_buf[ahd->msgout_index++] = MSG_NOOP; 44291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len++; 44301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; 44311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 44321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 44331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((scb->flags & SCB_DEVICE_RESET) == 0 44351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (scb->flags & SCB_PACKETIZED) == 0 44361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ahd_inb(ahd, MSG_OUT) == MSG_IDENTIFYFLAG) { 44371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int identify_msg; 44381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds identify_msg = MSG_IDENTIFYFLAG | SCB_GET_LUN(scb); 44401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((scb->hscb->control & DISCENB) != 0) 44411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds identify_msg |= MSG_IDENTIFY_DISCFLAG; 44421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_buf[ahd->msgout_index++] = identify_msg; 44431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len++; 44441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((scb->hscb->control & TAG_ENB) != 0) { 44461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_buf[ahd->msgout_index++] = 44471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->hscb->control & (TAG_ENB|SCB_TAG_TYPE); 44481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_buf[ahd->msgout_index++] = SCB_GET_TAG(scb); 44491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len += 2; 44501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 44511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 44521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb->flags & SCB_DEVICE_RESET) { 44541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_buf[ahd->msgout_index++] = MSG_BUS_DEV_RESET; 44551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len++; 44561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 445748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Bus Device Reset Message Sent\n"); 44581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 44591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear our selection hardware in advance of 44601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the busfree. We may have an entry in the waiting 44611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Q for this target, and we don't want to go about 44621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * selecting while we handle the busfree and blow it 44631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * away. 44641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ0, 0); 44661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((scb->flags & SCB_ABORT) != 0) { 44671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((scb->hscb->control & TAG_ENB) != 0) { 44691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_buf[ahd->msgout_index++] = MSG_ABORT_TAG; 44701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 44711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_buf[ahd->msgout_index++] = MSG_ABORT; 44721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 44731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len++; 44741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 447548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Abort%s Message Sent\n", 44761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (scb->hscb->control & TAG_ENB) != 0 ? " Tag" : ""); 44771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 44781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear our selection hardware in advance of 44791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the busfree. We may have an entry in the waiting 44801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Q for this target, and we don't want to go about 44811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * selecting while we handle the busfree and blow it 44821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * away. 44831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ0, 0); 44851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((scb->flags & (SCB_AUTO_NEGOTIATE|SCB_NEGOTIATE)) != 0) { 44861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_build_transfer_msg(ahd, devinfo); 44871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 44881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear our selection hardware in advance of potential 44891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PPR IU status change busfree. We may have an entry in 44901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the waiting Q for this target, and we don't want to go 44911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * about selecting while we handle the busfree and blow 44921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it away. 44931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ0, 0); 44951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 449648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("ahd_intr: AWAITING_MSG for an SCB that " 44971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "does not have a waiting message\n"); 449848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid, 44991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target_mask); 45001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("SCB = %d, SCB Control = %x:%x, MSG_OUT = %x " 45011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "SCB flags = %x", SCB_GET_TAG(scb), scb->hscb->control, 45021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_CONTROL), ahd_inb(ahd, MSG_OUT), 45031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->flags); 45041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 45051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 45071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear the MK_MESSAGE flag from the SCB so we aren't 45081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * asked to send this message again. 45091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 45101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCB_CONTROL, 45111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_CONTROL) & ~MK_MESSAGE); 45121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->hscb->control &= ~MK_MESSAGE; 45131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 45141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; 45151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 45161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 45181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Build an appropriate transfer negotiation message for the 45191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * currently active target. 45201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 45211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 45221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_build_transfer_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) 45231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 45241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 45251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We need to initiate transfer negotiations. 45261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If our current and goal settings are identical, 45271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we want to renegotiate due to a check condition. 45281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 45291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_initiator_tinfo *tinfo; 45301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 45311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dowide; 45321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dosync; 45331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int doppr; 45341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int period; 45351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int ppr_options; 45361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int offset; 45371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid, 45391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, &tstate); 45401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 45411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Filter our period based on the current connection. 45421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we can't perform DT transfers on this segment (not in LVD 45431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mode for instance), then our decision to issue a PPR message 45441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * may change. 45451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 45461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds period = tinfo->goal.period; 45471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = tinfo->goal.offset; 45481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppr_options = tinfo->goal.ppr_options; 45491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Target initiated PPR is not allowed in the SCSI spec */ 45501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (devinfo->role == ROLE_TARGET) 45511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppr_options = 0; 45521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_devlimited_syncrate(ahd, tinfo, &period, 45531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &ppr_options, devinfo->role); 45541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dowide = tinfo->curr.width != tinfo->goal.width; 45551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dosync = tinfo->curr.offset != offset || tinfo->curr.period != period; 45561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 45571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Only use PPR if we have options that need it, even if the device 45581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * claims to support it. There might be an expander in the way 45591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that doesn't. 45601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 45611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds doppr = ppr_options != 0; 45621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dowide && !dosync && !doppr) { 45641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT; 45651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dosync = tinfo->goal.offset != 0; 45661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 45671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dowide && !dosync && !doppr) { 45691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 45701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Force async with a WDTR message if we have a wide bus, 45711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or just issue an SDTR with a 0 offset. 45721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 45731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_WIDE) != 0) 45741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dowide = 1; 45751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 45761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dosync = 1; 45771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bootverbose) { 45791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_devinfo(ahd, devinfo); 458048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Ensuring async\n"); 45811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 45821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 45831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Target initiated PPR is not allowed in the SCSI spec */ 45841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (devinfo->role == ROLE_TARGET) 45851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds doppr = 0; 45861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 45881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Both the PPR message and SDTR message require the 45891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * goal syncrate to be limited to what the target device 45901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is capable of handling (based on whether an LVD->SE 45911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * expander is on the bus), so combine these two cases. 45921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Regardless, guarantee that if we are using WDTR and SDTR 45931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * messages that WDTR comes first. 45941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 45951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (doppr || (dosync && !dowide)) { 45961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = tinfo->goal.offset; 45981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_validate_offset(ahd, tinfo, period, &offset, 45991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds doppr ? tinfo->goal.width 46001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds : tinfo->curr.width, 46011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->role); 46021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (doppr) { 46031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_construct_ppr(ahd, devinfo, period, offset, 46041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->goal.width, ppr_options); 46051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 46061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_construct_sdtr(ahd, devinfo, period, offset); 46071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 46081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 46091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_construct_wdtr(ahd, devinfo, tinfo->goal.width); 46101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 46111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 46121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 46141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Build a synchronous negotiation message in our message 46151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buffer based on the input parameters. 46161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 46181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_construct_sdtr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 46191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int period, u_int offset) 46201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 46211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (offset == 0) 46221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds period = AHD_ASYNC_XFER_PERIOD; 46236ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox ahd->msgout_index += spi_populate_sync_msg( 46246ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox ahd->msgout_buf + ahd->msgout_index, period, offset); 46251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len += 5; 46261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bootverbose) { 462748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n", 46281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->channel, devinfo->target, 46291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->lun, period, offset); 46301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 46311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 46321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 46341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Build a wide negotiateion message in our message 46351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buffer based on the input parameters. 46361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 46381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_construct_wdtr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 46391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int bus_width) 46401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 46416ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox ahd->msgout_index += spi_populate_width_msg( 46426ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox ahd->msgout_buf + ahd->msgout_index, bus_width); 46431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len += 4; 46441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bootverbose) { 464548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%s:%c:%d:%d): Sending WDTR %x\n", 46461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->channel, devinfo->target, 46471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->lun, bus_width); 46481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 46491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 46501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 46521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Build a parallel protocol request message in our message 46531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buffer based on the input parameters. 46541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 46561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_construct_ppr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 46571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int period, u_int offset, u_int bus_width, 46581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int ppr_options) 46591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 46601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 46611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Always request precompensation from 46621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the other target if we are running 46631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * at paced syncrates. 46641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (period <= AHD_SYNCRATE_PACED) 46661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppr_options |= MSG_EXT_PPR_PCOMP_EN; 46671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (offset == 0) 46681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds period = AHD_ASYNC_XFER_PERIOD; 46696ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox ahd->msgout_index += spi_populate_ppr_msg( 46706ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox ahd->msgout_buf + ahd->msgout_index, period, offset, 46716ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox bus_width, ppr_options); 46721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len += 8; 46731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bootverbose) { 467448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, " 46751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "offset %x, ppr_options %x\n", ahd_name(ahd), 46761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->channel, devinfo->target, devinfo->lun, 46771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_width, period, offset, ppr_options); 46781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 46791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 46801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 46821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear any active message state. 46831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 46851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_clear_msg_state(struct ahd_softc *ahd) 46861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 46871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mode_state saved_modes; 46881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_modes = ahd_save_modes(ahd); 46901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 46911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->send_msg_perror = 0; 46921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_flags = MSG_FLAG_NONE; 46931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len = 0; 46941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgin_index = 0; 46951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_type = MSG_TYPE_NONE; 46961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_inb(ahd, SCSISIGO) & ATNO) != 0) { 46971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 46981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The target didn't care to respond to our 46991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * message request, so clear ATN. 47001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 47011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT1, CLRATNO); 47021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 47031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, MSG_OUT, MSG_NOOP); 47041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEQ_FLAGS2, 47051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SEQ_FLAGS2) & ~TARGET_MSG_PENDING); 47061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restore_modes(ahd, saved_modes); 47071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 47081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 47101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Manual message loop handler. 47111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 47121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 47131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_handle_message_phase(struct ahd_softc *ahd) 4714be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 47151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo devinfo; 47161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int bus_phase; 47171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int end_session; 47181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_fetch_devinfo(ahd, &devinfo); 47201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end_session = FALSE; 47211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_phase = ahd_inb(ahd, LASTPHASE); 47221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_inb(ahd, LQISTAT2) & LQIPHASE_OUTPKT) != 0) { 472448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("LQIRETRY for LQIPHASE_OUTPKT\n"); 47251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQCTL2, LQIRETRY); 47261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 47271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreswitch: 47281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ahd->msg_type) { 47291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_TYPE_INITIATOR_MSGOUT: 47301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 47311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int lastbyte; 47321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int phasemis; 47331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int msgdone; 47341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->msgout_len == 0 && ahd->send_msg_perror == 0) 47361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("HOST_MSG_LOOP interrupt with no active message"); 47371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 47391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { 47401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_devinfo(ahd, &devinfo); 474148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("INITIATOR_MSG_OUT"); 47421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 47431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 47441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds phasemis = bus_phase != P_MESGOUT; 47451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (phasemis) { 47461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 47471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { 474848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk(" PHASEMIS %s\n", 47491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lookup_phase_entry(bus_phase) 47501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ->phasemsg); 47511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 47521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 47531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bus_phase == P_MESGIN) { 47541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 47551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Change gears and see if 47561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this messages is of interest to 47571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * us or should be passed back to 47581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the sequencer. 47591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 47601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT1, CLRATNO); 47611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->send_msg_perror = 0; 47621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_type = MSG_TYPE_INITIATOR_MSGIN; 47631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgin_index = 0; 47641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reswitch; 47651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 47661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end_session = TRUE; 47671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 47681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 47691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->send_msg_perror) { 47711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT1, CLRATNO); 47721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT1, CLRREQINIT); 47731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 47741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 477548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk(" byte 0x%x\n", ahd->send_msg_perror); 47761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 47771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 47781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we are notifying the target of a CRC error 47791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * during packetized operations, the target is 47801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * within its rights to acknowledge our message 47811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with a busfree. 47821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 47831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->msg_flags & MSG_FLAG_PACKETIZED) != 0 47841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ahd->send_msg_perror == MSG_INITIATOR_DET_ERR) 47851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_flags |= MSG_FLAG_EXPECT_IDE_BUSFREE; 47861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, RETURN_2, ahd->send_msg_perror); 47881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_WRITE); 47891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 47901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 47911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msgdone = ahd->msgout_index == ahd->msgout_len; 47931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (msgdone) { 47941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 47951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The target has requested a retry. 47961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Re-assert ATN, reset our message index to 47971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0, and try again. 47981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 47991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 48001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_assert_atn(ahd); 48011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 48021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lastbyte = ahd->msgout_index == (ahd->msgout_len - 1); 48041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lastbyte) { 48051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Last byte is signified by dropping ATN */ 48061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT1, CLRATNO); 48071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 48081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 48101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear our interrupt status and present 48111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the next byte on the bus. 48121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 48131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT1, CLRREQINIT); 48141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 48151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 481648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk(" byte 0x%x\n", 48171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_buf[ahd->msgout_index]); 48181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 48191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, RETURN_2, ahd->msgout_buf[ahd->msgout_index++]); 48201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_WRITE); 48211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 48221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 48231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_TYPE_INITIATOR_MSGIN: 48241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 48251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int phasemis; 48261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int message_done; 48271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 48291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { 48301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_devinfo(ahd, &devinfo); 483148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("INITIATOR_MSG_IN"); 48321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 48331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 48341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds phasemis = bus_phase != P_MESGIN; 48351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (phasemis) { 48361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 48371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { 483848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk(" PHASEMIS %s\n", 48391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lookup_phase_entry(bus_phase) 48401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ->phasemsg); 48411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 48421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 48431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgin_index = 0; 48441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bus_phase == P_MESGOUT 48451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ahd->send_msg_perror != 0 48461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || (ahd->msgout_len != 0 48471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ahd->msgout_index == 0))) { 48481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; 48491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reswitch; 48501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 48511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end_session = TRUE; 48521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 48531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 48541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Pull the byte in without acking it */ 48561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgin_buf[ahd->msgin_index] = ahd_inb(ahd, SCSIBUS); 48571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 48581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 485948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk(" byte 0x%x\n", 48601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgin_buf[ahd->msgin_index]); 48611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 48621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds message_done = ahd_parse_msg(ahd, &devinfo); 48641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (message_done) { 48661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 48671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear our incoming message buffer in case there 48681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is another message following this one. 48691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 48701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgin_index = 0; 48711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 48731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If this message illicited a response, 48741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assert ATN so the target takes us to the 48751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * message out phase. 48761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 48771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->msgout_len != 0) { 48781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 48791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { 48801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_devinfo(ahd, &devinfo); 488148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Asserting ATN for response\n"); 48821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 48831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 48841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_assert_atn(ahd); 48851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 48861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 48871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgin_index++; 48881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (message_done == MSGLOOP_TERMINATED) { 48901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end_session = TRUE; 48911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 48921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Ack the byte */ 48931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT1, CLRREQINIT); 48941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_READ); 48951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 48961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 48971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 48981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_TYPE_TARGET_MSGIN: 48991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 49001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int msgdone; 49011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int msgout_request; 49021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 49041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * By default, the message loop will continue. 49051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG); 49071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->msgout_len == 0) 49091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("Target MSGIN with no active message"); 49101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 49121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we interrupted a mesgout session, the initiator 49131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will not know this until our first REQ. So, we 49141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * only honor mesgout requests after we've sent our 49151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * first byte. 49161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_inb(ahd, SCSISIGI) & ATNI) != 0 49181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ahd->msgout_index > 0) 49191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msgout_request = TRUE; 49201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 49211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msgout_request = FALSE; 49221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (msgout_request) { 49241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 49261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Change gears and see if 49271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this messages is of interest to 49281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * us or should be passed back to 49291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the sequencer. 49301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_type = MSG_TYPE_TARGET_MSGOUT; 49321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISIGO, P_MESGOUT | BSYO); 49331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgin_index = 0; 49341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Dummy read to REQ for first byte */ 49351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SCSIDAT); 49361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SXFRCTL0, 49371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SXFRCTL0) | SPIOEN); 49381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 49391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 49401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msgdone = ahd->msgout_index == ahd->msgout_len; 49421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (msgdone) { 49431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SXFRCTL0, 49441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SXFRCTL0) & ~SPIOEN); 49451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end_session = TRUE; 49461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 49471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 49481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 49501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Present the next byte on the bus. 49511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SXFRCTL0, ahd_inb(ahd, SXFRCTL0) | SPIOEN); 49531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSIDAT, ahd->msgout_buf[ahd->msgout_index++]); 49541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 49551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 49561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_TYPE_TARGET_MSGOUT: 49571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 49581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int lastbyte; 49591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int msgdone; 49601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 49621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * By default, the message loop will continue. 49631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG); 49651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 49671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The initiator signals that this is 49681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the last byte by dropping ATN. 49691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lastbyte = (ahd_inb(ahd, SCSISIGI) & ATNI) == 0; 49711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 49731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read the latched byte, but turn off SPIOEN first 49741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so that we don't inadvertently cause a REQ for the 49751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * next byte. 49761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SXFRCTL0, ahd_inb(ahd, SXFRCTL0) & ~SPIOEN); 49781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgin_buf[ahd->msgin_index] = ahd_inb(ahd, SCSIDAT); 49791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msgdone = ahd_parse_msg(ahd, &devinfo); 49801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (msgdone == MSGLOOP_TERMINATED) { 49811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 49821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The message is *really* done in that it caused 49831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * us to go to bus free. The sequencer has already 49841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * been reset at this point, so pull the ejection 49851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handle. 49861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 49881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 49891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgin_index++; 49911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 49931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX Read spec about initiator dropping ATN too soon 49941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and use msgdone to detect it. 49951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (msgdone == MSGLOOP_MSGCOMPLETE) { 49971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgin_index = 0; 49981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 50001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If this message illicited a response, transition 50011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to the Message in phase and send it. 50021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 50031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->msgout_len != 0) { 50041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISIGO, P_MESGIN | BSYO); 50051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SXFRCTL0, 50061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SXFRCTL0) | SPIOEN); 50071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_type = MSG_TYPE_TARGET_MSGIN; 50081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgin_index = 0; 50091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 50101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 50111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 50121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lastbyte) 50141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end_session = TRUE; 50151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 50161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Ask for the next byte. */ 50171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SXFRCTL0, 50181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, SXFRCTL0) | SPIOEN); 50191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 50201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 50221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 50231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 50241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("Unknown REQINIT message type"); 50251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 50261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (end_session) { 50281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->msg_flags & MSG_FLAG_PACKETIZED) != 0) { 502948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Returning to Idle Loop\n", 50301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd)); 50311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_clear_msg_state(ahd); 50321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 50341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Perform the equivalent of a clear_target_state. 50351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 50361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LASTPHASE, P_BUSFREE); 50371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT); 50381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEQCTL0, FASTMODE|SEQRESET); 50391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 50401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_clear_msg_state(ahd); 50411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, RETURN_1, EXIT_MSG_LOOP); 50421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 50431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 50441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 50451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 50471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * See if we sent a particular extended message to the target. 50481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If "full" is true, return true only if the target saw the full 50491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * message. If "full" is false, return true if the target saw at 50501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * least the first byte of the message. 50511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 50521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 50531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_sent_msg(struct ahd_softc *ahd, ahd_msgtype type, u_int msgval, int full) 50541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 50551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int found; 50561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int index; 50571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found = FALSE; 50591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index = 0; 50601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (index < ahd->msgout_len) { 50621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->msgout_buf[index] == MSG_EXTENDED) { 50631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int end_index; 50641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end_index = index + 1 + ahd->msgout_buf[index + 1]; 50661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->msgout_buf[index+2] == msgval 50671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && type == AHDMSG_EXT) { 50681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (full) { 50701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->msgout_index > end_index) 50711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found = TRUE; 50721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (ahd->msgout_index > index) 50731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found = TRUE; 50741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 50751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index = end_index; 50761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (ahd->msgout_buf[index] >= MSG_SIMPLE_TASK 50771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ahd->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) { 50781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Skip tag type and tag id or residue param*/ 50801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index += 2; 50811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 50821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Single byte message */ 50831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (type == AHDMSG_1B 50841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ahd->msgout_index > index 50851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ahd->msgout_buf[index] == msgval 50861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || ((ahd->msgout_buf[index] & MSG_IDENTIFYFLAG) != 0 50871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && msgval == MSG_IDENTIFYFLAG))) 50881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found = TRUE; 50891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index++; 50901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 50911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (found) 50931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 50941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 50951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (found); 50961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 50971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 50991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for a complete incoming message, parse it, and respond accordingly. 51001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 51011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 51021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) 51031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 51041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_initiator_tinfo *tinfo; 51051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 51061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int reject; 51071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int done; 51081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int response; 51091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds done = MSGLOOP_IN_PROG; 51111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds response = FALSE; 51121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reject = FALSE; 51131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid, 51141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, &tstate); 51151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 51171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Parse as much of the message as is available, 51181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * rejecting it if we don't support it. When 51191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the entire message is available and has been 51201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handled, return MSGLOOP_MSGCOMPLETE, indicating 51211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that we have parsed an entire message. 51221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In the case of extended messages, we accept the length 51241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte outright and perform more checking once we know the 51251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * extended message type. 51261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 51271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ahd->msgin_buf[0]) { 51281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_DISCONNECT: 51291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_SAVEDATAPOINTER: 51301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_CMDCOMPLETE: 51311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_RESTOREPOINTERS: 51321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_IGN_WIDE_RESIDUE: 51331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 51341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * End our message loop as these are messages 51351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the sequencer handles on its own. 51361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 51371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds done = MSGLOOP_TERMINATED; 51381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 51391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_MESSAGE_REJECT: 51401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds response = ahd_handle_msg_reject(ahd, devinfo); 51411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 51421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_NOOP: 51431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds done = MSGLOOP_MSGCOMPLETE; 51441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 51451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_EXTENDED: 51461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 51471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for enough of the message to begin validation */ 51481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->msgin_index < 2) 51491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 51501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ahd->msgin_buf[2]) { 51511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_EXT_SDTR: 51521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 51531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int period; 51541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int ppr_options; 51551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int offset; 51561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int saved_offset; 51571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->msgin_buf[1] != MSG_EXT_SDTR_LEN) { 51591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reject = TRUE; 51601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 51611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 51621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 51641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait until we have both args before validating 51651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and acting on this message. 51661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Add one to MSG_EXT_SDTR_LEN to account for 51681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the extended message preamble. 51691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 51701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->msgin_index < (MSG_EXT_SDTR_LEN + 1)) 51711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 51721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds period = ahd->msgin_buf[3]; 51741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppr_options = 0; 51751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_offset = offset = ahd->msgin_buf[4]; 51761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_devlimited_syncrate(ahd, tinfo, &period, 51771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &ppr_options, devinfo->role); 51781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_validate_offset(ahd, tinfo, period, &offset, 51791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->curr.width, devinfo->role); 51801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bootverbose) { 518148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%s:%c:%d:%d): Received " 51821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "SDTR period %x, offset %x\n\t" 51831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Filtered to period %x, offset %x\n", 51841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->channel, 51851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, devinfo->lun, 51861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgin_buf[3], saved_offset, 51871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds period, offset); 51881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 51891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_syncrate(ahd, devinfo, period, 51901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset, ppr_options, 51911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, 51921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*paused*/TRUE); 51931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 51951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * See if we initiated Sync Negotiation 51961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and didn't have to fall down to async 51971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transfers. 51981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 51991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, TRUE)) { 52001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We started it */ 52011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (saved_offset != offset) { 52021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Went too low - force async */ 52031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reject = TRUE; 52041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 52051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 52061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 52071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send our own SDTR in reply 52081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 52091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bootverbose 52101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && devinfo->role == ROLE_INITIATOR) { 521148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%s:%c:%d:%d): Target " 52121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Initiated SDTR\n", 52131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->channel, 52141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, devinfo->lun); 52151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 52161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 52171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len = 0; 52181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_construct_sdtr(ahd, devinfo, 52191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds period, offset); 52201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 52211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds response = TRUE; 52221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 52231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds done = MSGLOOP_MSGCOMPLETE; 52241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 52251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 52261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_EXT_WDTR: 52271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 52281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int bus_width; 52291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int saved_width; 52301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int sending_reply; 52311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sending_reply = FALSE; 52331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->msgin_buf[1] != MSG_EXT_WDTR_LEN) { 52341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reject = TRUE; 52351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 52361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 52371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 52391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait until we have our arg before validating 52401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and acting on this message. 52411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 52421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Add one to MSG_EXT_WDTR_LEN to account for 52431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the extended message preamble. 52441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 52451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->msgin_index < (MSG_EXT_WDTR_LEN + 1)) 52461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 52471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_width = ahd->msgin_buf[3]; 52491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_width = bus_width; 52501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_validate_width(ahd, tinfo, &bus_width, 52511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->role); 52521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bootverbose) { 525348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%s:%c:%d:%d): Received WDTR " 52541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%x filtered to %x\n", 52551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->channel, 52561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, devinfo->lun, 52571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_width, bus_width); 52581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 52591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, TRUE)) { 52611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 52621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Don't send a WDTR back to the 52631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * target, since we asked first. 52641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the width went higher than our 52651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * request, reject it. 52661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 52671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (saved_width > bus_width) { 52681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reject = TRUE; 526948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%s:%c:%d:%d): requested %dBit " 52701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "transfers. Rejecting...\n", 52711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->channel, 52721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, devinfo->lun, 52731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8 * (0x01 << bus_width)); 52741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_width = 0; 52751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 52761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 52771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 52781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send our own WDTR in reply 52791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 52801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bootverbose 52811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && devinfo->role == ROLE_INITIATOR) { 528248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%s:%c:%d:%d): Target " 52831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Initiated WDTR\n", 52841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->channel, 52851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, devinfo->lun); 52861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 52871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 52881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len = 0; 52891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_construct_wdtr(ahd, devinfo, bus_width); 52901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 52911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds response = TRUE; 52921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sending_reply = TRUE; 52931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 52941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 52951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * After a wide message, we are async, but 52961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * some devices don't seem to honor this portion 52971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the spec. Force a renegotiation of the 52981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sync component of our transfer agreement even 52991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if our goal is async. By updating our width 53001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * after forcing the negotiation, we avoid 53011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * renegotiating for width. 53021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_update_neg_request(ahd, devinfo, tstate, 53041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo, AHD_NEG_ALWAYS); 53051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_width(ahd, devinfo, bus_width, 53061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, 53071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*paused*/TRUE); 53081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sending_reply == FALSE && reject == FALSE) { 53091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 53111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We will always have an SDTR to send. 53121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 53141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len = 0; 53151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_build_transfer_msg(ahd, devinfo); 53161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 53171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds response = TRUE; 53181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 53191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds done = MSGLOOP_MSGCOMPLETE; 53201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 53211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 53221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_EXT_PPR: 53231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 53241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int period; 53251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int offset; 53261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int bus_width; 53271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int ppr_options; 53281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int saved_width; 53291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int saved_offset; 53301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int saved_ppr_options; 53311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->msgin_buf[1] != MSG_EXT_PPR_LEN) { 53331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reject = TRUE; 53341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 53351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 53361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 53381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait until we have all args before validating 53391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and acting on this message. 53401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 53411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Add one to MSG_EXT_PPR_LEN to account for 53421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the extended message preamble. 53431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->msgin_index < (MSG_EXT_PPR_LEN + 1)) 53451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 53461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds period = ahd->msgin_buf[3]; 53481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = ahd->msgin_buf[5]; 53491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_width = ahd->msgin_buf[6]; 53501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_width = bus_width; 53511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppr_options = ahd->msgin_buf[7]; 53521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 53531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * According to the spec, a DT only 53541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * period factor with no DT option 53551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set implies async. 53561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ppr_options & MSG_EXT_PPR_DT_REQ) == 0 53581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && period <= 9) 53591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = 0; 53601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_ppr_options = ppr_options; 53611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_offset = offset; 53621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 53641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Transfer options are only available if we 53651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are negotiating wide. 53661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bus_width == 0) 53681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppr_options &= MSG_EXT_PPR_QAS_REQ; 53691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_validate_width(ahd, tinfo, &bus_width, 53711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->role); 53721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_devlimited_syncrate(ahd, tinfo, &period, 53731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &ppr_options, devinfo->role); 53741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_validate_offset(ahd, tinfo, period, &offset, 53751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_width, devinfo->role); 53761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, TRUE)) { 53781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 53791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we are unable to do any of the 53801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * requested options (we went too low), 53811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * then we'll have to reject the message. 53821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (saved_width > bus_width 53841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || saved_offset != offset 53851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || saved_ppr_options != ppr_options) { 53861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reject = TRUE; 53871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds period = 0; 53881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = 0; 53891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_width = 0; 53901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppr_options = 0; 53911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 53921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 53931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (devinfo->role != ROLE_TARGET) 539448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%s:%c:%d:%d): Target " 53951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Initiated PPR\n", 53961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->channel, 53971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, devinfo->lun); 53981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 539948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%s:%c:%d:%d): Initiator " 54001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Initiated PPR\n", 54011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->channel, 54021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, devinfo->lun); 54031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 54041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len = 0; 54051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_construct_ppr(ahd, devinfo, period, offset, 54061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_width, ppr_options); 54071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 54081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds response = TRUE; 54091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 54101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bootverbose) { 541148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%s:%c:%d:%d): Received PPR width %x, " 54121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "period %x, offset %x,options %x\n" 54131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "\tFiltered to width %x, period %x, " 54141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "offset %x, options %x\n", 54151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->channel, 54161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, devinfo->lun, 54171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_width, ahd->msgin_buf[3], 54181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_offset, saved_ppr_options, 54191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_width, period, offset, ppr_options); 54201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 54211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_width(ahd, devinfo, bus_width, 54221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, 54231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*paused*/TRUE); 54241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_syncrate(ahd, devinfo, period, 54251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset, ppr_options, 54261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, 54271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*paused*/TRUE); 54281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds done = MSGLOOP_MSGCOMPLETE; 54301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 54311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 54321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 54331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Unknown extended message. Reject it. */ 54341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reject = TRUE; 54351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 54361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 54371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 54381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 54391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_TARGET_MODE 54401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_BUS_DEV_RESET: 54411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_handle_devreset(ahd, devinfo, CAM_LUN_WILDCARD, 54421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CAM_BDR_SENT, 54431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Bus Device Reset Received", 54441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*verbose_level*/0); 54451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restart(ahd); 54461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds done = MSGLOOP_TERMINATED; 54471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 54481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_ABORT_TAG: 54491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_ABORT: 54501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_CLEAR_QUEUE: 54511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 54521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tag; 54531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Target mode messages */ 54551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (devinfo->role != ROLE_TARGET) { 54561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reject = TRUE; 54571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 54581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 54591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tag = SCB_LIST_NULL; 54601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->msgin_buf[0] == MSG_ABORT_TAG) 54611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tag = ahd_inb(ahd, INITIATOR_TAG); 54621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_abort_scbs(ahd, devinfo->target, devinfo->channel, 54631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->lun, tag, ROLE_TARGET, 54641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CAM_REQ_ABORTED); 54651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tstate = ahd->enabled_targets[devinfo->our_scsiid]; 54671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tstate != NULL) { 54681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_lstate* lstate; 54691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate = tstate->enabled_luns[devinfo->lun]; 54711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lstate != NULL) { 54721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_queue_lstate_event(ahd, lstate, 54731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->our_scsiid, 54741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgin_buf[0], 54751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*arg*/tag); 54761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_send_lstate_events(ahd, lstate); 54771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 54781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 54791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restart(ahd); 54801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds done = MSGLOOP_TERMINATED; 54811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 54821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 54831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 54841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_QAS_REQUEST: 54851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 54861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) 548748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: QAS request. SCSISIGI == 0x%x\n", 54881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), ahd_inb(ahd, SCSISIGI)); 54891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 54901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_flags |= MSG_FLAG_EXPECT_QASREJ_BUSFREE; 54911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 54921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MSG_TERM_IO_PROC: 54931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 54941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reject = TRUE; 54951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 54961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 54971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reject) { 54991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 55001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Setup to reject the message. 55011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 55031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len = 1; 55041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_buf[0] = MSG_MESSAGE_REJECT; 55051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds done = MSGLOOP_MSGCOMPLETE; 55061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds response = TRUE; 55071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 55081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (done != MSGLOOP_IN_PROG && !response) 55101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear the outgoing message buffer */ 55111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len = 0; 55121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (done); 55141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 55151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 55171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Process a message reject message. 55181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 55201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) 55211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 55221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 55231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * What we care about here is if we had an 55241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * outstanding SDTR or WDTR message for this 55251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * target. If we did, this is a signal that 55261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the target is refusing negotiation. 55271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 55291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_initiator_tinfo *tinfo; 55301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 55311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scb_index; 55321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int last_msg; 55331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int response = 0; 55341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_index = ahd_get_scbptr(ahd); 55361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scb_index); 55371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, 55381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->our_scsiid, 55391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, &tstate); 55401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Might be necessary */ 55411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last_msg = ahd_inb(ahd, LAST_MSG); 55421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, /*full*/FALSE)) { 55441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, /*full*/TRUE) 55451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && tinfo->goal.period <= AHD_SYNCRATE_PACED) { 55461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 55471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Target may not like our SPI-4 PPR Options. 55481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Attempt to negotiate 80MHz which will turn 55491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * off these options. 55501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bootverbose) { 555248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%s:%c:%d:%d): PPR Rejected. " 55531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Trying simple U160 PPR\n", 55541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->channel, 55551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, devinfo->lun); 55561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 55571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->goal.period = AHD_SYNCRATE_DT; 55581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->goal.ppr_options &= MSG_EXT_PPR_IU_REQ 55591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | MSG_EXT_PPR_QAS_REQ 55601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | MSG_EXT_PPR_DT_REQ; 55611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 55621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 55631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Target does not support the PPR message. 55641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Attempt to negotiate SPI-2 style. 55651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bootverbose) { 556748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%s:%c:%d:%d): PPR Rejected. " 55681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Trying WDTR/SDTR\n", 55691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->channel, 55701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, devinfo->lun); 55711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 55721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->goal.ppr_options = 0; 55731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->curr.transport_version = 2; 55741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->goal.transport_version = 2; 55751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 55761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 55771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len = 0; 55781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_build_transfer_msg(ahd, devinfo); 55791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 55801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds response = 1; 55811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, /*full*/FALSE)) { 55821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* note 8bit xfers */ 558448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%s:%c:%d:%d): refuses WIDE negotiation. Using " 55851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "8bit transfers\n", ahd_name(ahd), 55861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->channel, devinfo->target, devinfo->lun); 55871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_width(ahd, devinfo, MSG_EXT_WDTR_BUS_8_BIT, 55881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, 55891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*paused*/TRUE); 55901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 55911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * No need to clear the sync rate. If the target 55921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * did not accept the command, our syncrate is 55931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * unaffected. If the target started the negotiation, 55941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but rejected our response, we already cleared the 55951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sync rate before sending our WDTR. 55961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tinfo->goal.offset != tinfo->curr.offset) { 55981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start the sync negotiation */ 56001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 56011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len = 0; 56021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_build_transfer_msg(ahd, devinfo); 56031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 56041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds response = 1; 56051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 56061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, /*full*/FALSE)) { 56071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* note asynch xfers and clear flag */ 56081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_syncrate(ahd, devinfo, /*period*/0, 56091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*offset*/0, /*ppr_options*/0, 56101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, 56111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*paused*/TRUE); 561248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%s:%c:%d:%d): refuses synchronous negotiation. " 56131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Using asynchronous transfers\n", 56141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->channel, 56151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->target, devinfo->lun); 56161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((scb->hscb->control & MSG_SIMPLE_TASK) != 0) { 56171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tag_type; 56181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mask; 56191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tag_type = (scb->hscb->control & MSG_SIMPLE_TASK); 56211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tag_type == MSG_SIMPLE_TASK) { 562348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%s:%c:%d:%d): refuses tagged commands. " 56241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Performing non-tagged I/O\n", ahd_name(ahd), 56251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->channel, devinfo->target, devinfo->lun); 5626f89d0a4e1d01168f20f9e8273de7dfc094b2a430Hannes Reinecke ahd_set_tags(ahd, scb->io_ctx, devinfo, AHD_QUEUE_NONE); 56271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask = ~0x23; 56281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 562948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%s:%c:%d:%d): refuses %s tagged commands. " 56301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Performing simple queue tagged I/O only\n", 56311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->channel, devinfo->target, 56321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo->lun, tag_type == MSG_ORDERED_TASK 56331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? "ordered" : "head of queue"); 5634f89d0a4e1d01168f20f9e8273de7dfc094b2a430Hannes Reinecke ahd_set_tags(ahd, scb->io_ctx, devinfo, AHD_QUEUE_BASIC); 56351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask = ~0x03; 56361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 56371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 56391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Resend the identify for this CCB as the target 56401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * may believe that the selection is invalid otherwise. 56411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 56421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCB_CONTROL, 56431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_CONTROL) & mask); 56441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->hscb->control &= mask; 56451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_transaction_tag(scb, /*enabled*/FALSE, 56461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*type*/MSG_SIMPLE_TASK); 56471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, MSG_OUT, MSG_IDENTIFYFLAG); 56481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_assert_atn(ahd); 56491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_busy_tcl(ahd, BUILD_TCL(scb->hscb->scsiid, devinfo->lun), 56501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_TAG(scb)); 56511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 56531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Requeue all tagged commands for this target 565425985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * currently in our possession so they can be 56551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * converted to untagged commands. 56561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 56571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_search_qinfifo(ahd, SCB_GET_TARGET(ahd, scb), 56581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_CHANNEL(ahd, scb), 56591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_LUN(scb), /*tag*/SCB_LIST_NULL, 56601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ROLE_INITIATOR, CAM_REQUEUE_REQ, 56611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SEARCH_COMPLETE); 56621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (ahd_sent_msg(ahd, AHDMSG_1B, MSG_IDENTIFYFLAG, TRUE)) { 56631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 56641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Most likely the device believes that we had 56651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * previously negotiated packetized. 56661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 56671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE 56681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | MSG_FLAG_IU_REQ_CHANGED; 56691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_force_renegotiation(ahd, devinfo); 56711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 56721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len = 0; 56731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_build_transfer_msg(ahd, devinfo); 56741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 56751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds response = 1; 56761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 56771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 56781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Otherwise, we ignore it. 56791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 568048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s:%c:%d: Message reject for %x -- ignored\n", 56811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), devinfo->channel, devinfo->target, 56821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last_msg); 56831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 56841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (response); 56851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 56861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 56881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Process an ingnore wide residue message. 56891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 56901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 56911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_handle_ign_wide_residue(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) 56921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 56931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scb_index; 56941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 56951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_index = ahd_get_scbptr(ahd); 56971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scb_index); 56981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 56991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX Actually check data direction in the sequencer? 57001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Perhaps add datadir to some spare bits in the hscb? 57011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_inb(ahd, SEQ_FLAGS) & DPHASE) == 0 57031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || ahd_get_transfer_dir(scb) != CAM_DIR_IN) { 57041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 57051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ignore the message if we haven't 57061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * seen an appropriate data phase yet. 57071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 57091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 57101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the residual occurred on the last 57111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transfer and the transfer request was 57121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * expected to end on an odd count, do 57131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * nothing. Otherwise, subtract a byte 57141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and update the residual count accordingly. 57151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t sgptr; 57171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgptr = ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR); 57191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((sgptr & SG_LIST_NULL) != 0 57201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ahd_inb_scbram(ahd, SCB_TASK_ATTRIBUTE) 57211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds & SCB_XFERLEN_ODD) != 0) { 57221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 57231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the residual occurred on the last 57241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transfer and the transfer request was 57251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * expected to end on an odd count, do 57261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * nothing. 57271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 57291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t data_cnt; 57301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint64_t data_addr; 57311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t sglen; 57321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Pull in the rest of the sgptr */ 57341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR); 57351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_cnt = ahd_inl_scbram(ahd, SCB_RESIDUAL_DATACNT); 57361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((sgptr & SG_LIST_NULL) != 0) { 57371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 57381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The residual data count is not updated 57391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for the command run to completion case. 57401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Explicitly zero the count. 57411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_cnt &= ~AHD_SG_LEN_MASK; 57431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 57441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_addr = ahd_inq(ahd, SHADDR); 57451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_cnt += 1; 57461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_addr -= 1; 57471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgptr &= SG_PTR_MASK; 57481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 57491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_dma64_seg *sg; 57501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); 57521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 57541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The residual sg ptr points to the next S/G 57551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to load so we must go back one. 57561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg--; 57581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sglen = ahd_le32toh(sg->len) & AHD_SG_LEN_MASK; 57591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sg != scb->sg_list 57601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && sglen < (data_cnt & AHD_SG_LEN_MASK)) { 57611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg--; 57631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sglen = ahd_le32toh(sg->len); 57641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 57651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Preserve High Address and SG_LIST 57661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bits while setting the count to 1. 57671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_cnt = 1|(sglen&(~AHD_SG_LEN_MASK)); 57691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_addr = ahd_le64toh(sg->addr) 57701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds + (sglen & AHD_SG_LEN_MASK) 57711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - 1; 57721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 57741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Increment sg so it points to the 57751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "next" sg. 57761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg++; 57781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgptr = ahd_sg_virt_to_bus(ahd, scb, 57791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg); 57801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 57811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 57821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_dma_seg *sg; 57831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); 57851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 57871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The residual sg ptr points to the next S/G 57881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to load so we must go back one. 57891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg--; 57911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sglen = ahd_le32toh(sg->len) & AHD_SG_LEN_MASK; 57921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sg != scb->sg_list 57931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && sglen < (data_cnt & AHD_SG_LEN_MASK)) { 57941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg--; 57961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sglen = ahd_le32toh(sg->len); 57971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 57981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Preserve High Address and SG_LIST 57991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bits while setting the count to 1. 58001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 58011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_cnt = 1|(sglen&(~AHD_SG_LEN_MASK)); 58021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_addr = ahd_le32toh(sg->addr) 58031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds + (sglen & AHD_SG_LEN_MASK) 58041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - 1; 58051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 58071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Increment sg so it points to the 58081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "next" sg. 58091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 58101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg++; 58111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgptr = ahd_sg_virt_to_bus(ahd, scb, 58121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg); 58131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 58141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 58151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 58161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Toggle the "oddness" of the transfer length 58171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to handle this mid-transfer ignore wide 58181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * residue. This ensures that the oddness is 58191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * correct for subsequent data transfers. 58201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 58211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCB_TASK_ATTRIBUTE, 58221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_TASK_ATTRIBUTE) 58231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ^ SCB_XFERLEN_ODD); 58241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr); 58261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outl(ahd, SCB_RESIDUAL_DATACNT, data_cnt); 58271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 58281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The FIFO's pointers will be updated if/when the 58291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sequencer re-enters a data phase. 58301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 58311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 58321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 58331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 58341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 58371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reinitialize the data pointers for the active transfer 58381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * based on its current residual. 58391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 58401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 58411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_reinitialize_dataptrs(struct ahd_softc *ahd) 58421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 58431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 58441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mode_state saved_modes; 58451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scb_index; 58461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int wait; 58471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t sgptr; 58481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t resid; 58491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint64_t dataptr; 58501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_DFF0_MSK|AHD_MODE_DFF1_MSK, 58521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_MODE_DFF0_MSK|AHD_MODE_DFF1_MSK); 58531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_index = ahd_get_scbptr(ahd); 58551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scb_index); 58561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 58581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Release and reacquire the FIFO so we 58591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * have a clean slate. 58601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 58611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, DFFSXFRCTL, CLRCHN); 58621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait = 1000; 58631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (--wait && !(ahd_inb(ahd, MDFFSTAT) & FIFOFREE)) 58641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_delay(100); 58651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wait == 0) { 58661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 586748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("ahd_reinitialize_dataptrs: Forcing FIFO free.\n"); 58681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, DFFSXFRCTL, RSTCHN|CLRSHCNT); 58691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 58701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_modes = ahd_save_modes(ahd); 58711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 58721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, DFFSTAT, 58731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, DFFSTAT) 58741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | (saved_modes == 0x11 ? CURRFIFO_1 : CURRFIFO_0)); 58751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 58771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Determine initial values for data_addr and data_cnt 58781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for resuming the data phase. 58791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5880ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR); 58811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgptr &= SG_PTR_MASK; 58821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resid = (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT + 2) << 16) 58841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT + 1) << 8) 58851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT); 58861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 58881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_dma64_seg *sg; 58891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); 58911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The residual sg_ptr always points to the next sg */ 58931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg--; 58941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dataptr = ahd_le64toh(sg->addr) 58961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds + (ahd_le32toh(sg->len) & AHD_SG_LEN_MASK) 58971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - resid; 5898ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke ahd_outl(ahd, HADDR + 4, dataptr >> 32); 58991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 59001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_dma_seg *sg; 59011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); 59031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The residual sg_ptr always points to the next sg */ 59051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg--; 59061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dataptr = ahd_le32toh(sg->addr) 59081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds + (ahd_le32toh(sg->len) & AHD_SG_LEN_MASK) 59091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - resid; 59101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, HADDR + 4, 59111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ahd_le32toh(sg->len) & ~AHD_SG_LEN_MASK) >> 24); 59121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5913ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke ahd_outl(ahd, HADDR, dataptr); 59141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, HCNT + 2, resid >> 16); 59151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, HCNT + 1, resid >> 8); 59161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, HCNT, resid); 59171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 59181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 59201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle the effects of issuing a bus device reset message. 59211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 59221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 59231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_handle_devreset(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 59241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lun, cam_status status, char *message, 59251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int verbose_level) 59261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 59271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_TARGET_MODE 59281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate* tstate; 59291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 59301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int found; 59311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found = ahd_abort_scbs(ahd, devinfo->target, devinfo->channel, 59331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lun, SCB_LIST_NULL, devinfo->role, 59341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status); 59351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_TARGET_MODE 59371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 59381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send an immediate notify ccb to all target mord peripheral 59391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers affected by this action. 59401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 59411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tstate = ahd->enabled_targets[devinfo->our_scsiid]; 59421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tstate != NULL) { 59431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int cur_lun; 59441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int max_lun; 59451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lun != CAM_LUN_WILDCARD) { 59471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_lun = 0; 59481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max_lun = AHD_NUM_LUNS - 1; 59491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 59501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_lun = lun; 59511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max_lun = lun; 59521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5953632155e659449685b719995d7e7081cff7b01abaYoann Padioleau for (;cur_lun <= max_lun; cur_lun++) { 59541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_lstate* lstate; 59551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate = tstate->enabled_luns[cur_lun]; 59571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lstate == NULL) 59581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 59591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_queue_lstate_event(ahd, lstate, devinfo->our_scsiid, 59611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MSG_BUS_DEV_RESET, /*arg*/0); 59621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_send_lstate_events(ahd, lstate); 59631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 59641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 59651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 59661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 59681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Go back to async/narrow transfers and renegotiate. 59691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 59701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_width(ahd, devinfo, MSG_EXT_WDTR_BUS_8_BIT, 59711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_TRANS_CUR, /*paused*/TRUE); 59721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_syncrate(ahd, devinfo, /*period*/0, /*offset*/0, 597311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /*ppr_options*/0, AHD_TRANS_CUR, 597411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /*paused*/TRUE); 59751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 597611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if (status != CAM_SEL_TIMEOUT) 597711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_send_async(ahd, devinfo->channel, devinfo->target, 5978f89d0a4e1d01168f20f9e8273de7dfc094b2a430Hannes Reinecke CAM_LUN_WILDCARD, AC_SENT_BDR); 59791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 598011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if (message != NULL && bootverbose) 598148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: %s on %c:%d. %d SCBs aborted\n", ahd_name(ahd), 59821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds message, devinfo->channel, devinfo->target, found); 59831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 59841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_TARGET_MODE 59861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 59871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_setup_target_msgin(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, 59881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb) 59891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 59901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 59921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * To facilitate adding multiple messages together, 59931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * each routine should increment the index and len 59941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * variables instead of setting them explicitly. 59951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 59961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 59971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_len = 0; 59981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb != NULL && (scb->flags & SCB_AUTO_NEGOTIATE) != 0) 60001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_build_transfer_msg(ahd, devinfo); 60011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 60021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("ahd_intr: AWAITING target message with no message"); 60031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msgout_index = 0; 60051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->msg_type = MSG_TYPE_TARGET_MSGIN; 60061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 60071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 60081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**************************** Initialization **********************************/ 60091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int 60101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_sglist_size(struct ahd_softc *ahd) 60111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 60121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_size_t list_size; 60131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_size = sizeof(struct ahd_dma_seg) * AHD_NSEG; 60151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) 60161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_size = sizeof(struct ahd_dma64_seg) * AHD_NSEG; 60171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (list_size); 60181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 60191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 60211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calculate the optimum S/G List allocation size. S/G elements used 60221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for a given transaction must be physically contiguous. Assume the 60231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OS will allocate full pages to us, so it doesn't make sense to request 60241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * less than a page. 60251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 60261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int 60271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_sglist_allocsize(struct ahd_softc *ahd) 60281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 60291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_size_t sg_list_increment; 60301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_size_t sg_list_size; 60311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_size_t max_list_size; 60321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_size_t best_list_size; 60331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start out with the minimum required for AHD_NSEG. */ 60351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_list_increment = ahd_sglist_size(ahd); 60361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_list_size = sg_list_increment; 60371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get us as close as possible to a page in size. */ 60391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((sg_list_size + sg_list_increment) <= PAGE_SIZE) 60401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_list_size += sg_list_increment; 60411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 60431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to reduce the amount of wastage by allocating 60441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * multiple pages. 60451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 60461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds best_list_size = sg_list_size; 60471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max_list_size = roundup(sg_list_increment, PAGE_SIZE); 60481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max_list_size < 4 * PAGE_SIZE) 60491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max_list_size = 4 * PAGE_SIZE; 60501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max_list_size > (AHD_SCB_MAX_ALLOC * sg_list_increment)) 60511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max_list_size = (AHD_SCB_MAX_ALLOC * sg_list_increment); 60521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((sg_list_size + sg_list_increment) <= max_list_size 60531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (sg_list_size % PAGE_SIZE) != 0) { 60541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_size_t new_mod; 60551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_size_t best_mod; 60561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_list_size += sg_list_increment; 60581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_mod = sg_list_size % PAGE_SIZE; 60591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds best_mod = best_list_size % PAGE_SIZE; 60601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (new_mod > best_mod || new_mod == 0) { 60611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds best_list_size = sg_list_size; 60621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 60631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 60641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (best_list_size); 60651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 60661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 60681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate a controller structure for a new device 60691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and perform initial initializion. 60701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 60711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ahd_softc * 60721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_alloc(void *platform_arg, char *name) 60731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 60741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_softc *ahd; 60751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef __FreeBSD__ 607748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg ahd = kmalloc(sizeof(*ahd), GFP_ATOMIC); 60781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ahd) { 607948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("aic7xxx: cannot malloc softc!\n"); 608048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(name); 60811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 60821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 60831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 60841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd = device_get_softc((device_t)platform_arg); 60851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 60861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(ahd, 0, sizeof(*ahd)); 608748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg ahd->seep_config = kmalloc(sizeof(*ahd->seep_config), GFP_ATOMIC); 60881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->seep_config == NULL) { 60891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef __FreeBSD__ 609048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(ahd); 60911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 609248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(name); 60931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (NULL); 60941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 60951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_INIT(&ahd->pending_scbs); 60961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We don't know our unit number until the OSM sets it */ 60971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->name = name; 60981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->unit = -1; 60991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->description = NULL; 61001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->bus_description = NULL; 61011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->channel = 'A'; 61021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->chip = AHD_NONE; 61031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->features = AHD_FENONE; 61041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->bugs = AHD_BUGNONE; 61051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags = AHD_SPCHK_ENB_A|AHD_RESET_BUS_A|AHD_TERM_ENB_A 61061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | AHD_EXTENDED_TRANS_A|AHD_STPWLEVEL_A; 61071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_timer_init(&ahd->reset_timer); 61081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_timer_init(&ahd->stat_timer); 61091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->int_coalescing_timer = AHD_INT_COALESCING_TIMER_DEFAULT; 61101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->int_coalescing_maxcmds = AHD_INT_COALESCING_MAXCMDS_DEFAULT; 61111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->int_coalescing_mincmds = AHD_INT_COALESCING_MINCMDS_DEFAULT; 61121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->int_coalescing_threshold = AHD_INT_COALESCING_THRESHOLD_DEFAULT; 61131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->int_coalescing_stop_threshold = 61141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_INT_COALESCING_STOP_THRESHOLD_DEFAULT; 61151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_platform_alloc(ahd, platform_arg) != 0) { 61171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_free(ahd); 61181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd = NULL; 61191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 61201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 61211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MEMORY) != 0) { 612248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: scb size = 0x%x, hscb size = 0x%x\n", 61231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), (u_int)sizeof(struct scb), 61241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (u_int)sizeof(struct hardware_scb)); 61251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 61261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 61271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (ahd); 61281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 61291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 61311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_softc_init(struct ahd_softc *ahd) 61321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 61331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->unpause = 0; 61351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->pause = PAUSE; 61361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 61371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 61381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 61401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_set_unit(struct ahd_softc *ahd, int unit) 61411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 61421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->unit = unit; 61431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 61441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 61461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_set_name(struct ahd_softc *ahd, char *name) 61471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 61481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->name != NULL) 614948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(ahd->name); 61501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->name = name; 61511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 61521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 61541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_free(struct ahd_softc *ahd) 61551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 61561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 61571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ahd->init_level) { 61591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 61601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 5: 61611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_shutdown(ahd); 61621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 61631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 4: 61641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dmamap_unload(ahd, ahd->shared_data_dmat, 616566a0683e4620f087e41e79d4d2be6c5a06bb206bHannes Reinecke ahd->shared_data_map.dmamap); 61661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 61671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 3: 61681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dmamem_free(ahd, ahd->shared_data_dmat, ahd->qoutfifo, 616966a0683e4620f087e41e79d4d2be6c5a06bb206bHannes Reinecke ahd->shared_data_map.dmamap); 61701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dmamap_destroy(ahd, ahd->shared_data_dmat, 617166a0683e4620f087e41e79d4d2be6c5a06bb206bHannes Reinecke ahd->shared_data_map.dmamap); 61721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 61731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: 61741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dma_tag_destroy(ahd, ahd->shared_data_dmat); 61751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: 61761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef __linux__ 61771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dma_tag_destroy(ahd, ahd->buffer_dmat); 61781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 61791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 61801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 61811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 61821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 61831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef __linux__ 61851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dma_tag_destroy(ahd, ahd->parent_dmat); 61861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 61871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_platform_free(ahd); 61881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_fini_scbdata(ahd); 61891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < AHD_NUM_TARGETS; i++) { 61901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 61911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tstate = ahd->enabled_targets[i]; 61931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tstate != NULL) { 61941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_TARGET_MODE 61951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int j; 61961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = 0; j < AHD_NUM_LUNS; j++) { 61981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_lstate *lstate; 61991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate = tstate->enabled_luns[j]; 62011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lstate != NULL) { 62021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_free_path(lstate->path); 620348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(lstate); 62041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 62051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 62061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 620748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(tstate); 62081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 62091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 62101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_TARGET_MODE 62111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->black_hole != NULL) { 62121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_free_path(ahd->black_hole->path); 621348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(ahd->black_hole); 62141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 62151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 62161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->name != NULL) 621748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(ahd->name); 62181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->seep_config != NULL) 621948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(ahd->seep_config); 62201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->saved_stack != NULL) 622148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(ahd->saved_stack); 62221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef __FreeBSD__ 622348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(ahd); 62241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 62251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 62261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 62271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6228289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void 62291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_shutdown(void *arg) 62301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 62311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_softc *ahd; 62321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd = (struct ahd_softc *)arg; 62341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 62361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Stop periodic timer callbacks. 62371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 62381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_timer_stop(&ahd->reset_timer); 62391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_timer_stop(&ahd->stat_timer); 62401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This will reset most registers to 0, but not all */ 62421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_reset(ahd, /*reinit*/FALSE); 62431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 62441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 62461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset the controller and record some information about it 62471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that is only available just after a reset. If "reinit" is 624825985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * non-zero, this reset occurred after initial configuration 62491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and the caller requests that the chip be fully reinitialized 62501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to a runable state. Chip interrupts are *not* enabled after 62511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a reinitialization. The caller must enable interrupts via 62521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ahd_intr_enable(). 62531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 62541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 62551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_reset(struct ahd_softc *ahd, int reinit) 62561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 62571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int sxfrctl1; 62581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int wait; 62591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t cmd; 62601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 62621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Preserve the value of the SXFRCTL1 register for all channels. 62631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It contains settings that affect termination and we don't want 62641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to disturb the integrity of the bus. 62651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 62661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pause(ahd); 62671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_update_modes(ahd); 62681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 62691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sxfrctl1 = ahd_inb(ahd, SXFRCTL1); 62701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2); 62721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_PCIX_CHIPRST_BUG) != 0) { 62731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t mod_cmd; 62741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 62761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A4 Razor #632 62771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * During the assertion of CHIPRST, the chip 62781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does not disable its parity logic prior to 62791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the start of the reset. This may cause a 62801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parity error to be detected and thus a 62811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * spurious SERR or PERR assertion. Disble 62821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PERR and SERR responses during the CHIPRST. 62831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 62841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_cmd = cmd & ~(PCIM_CMD_PERRESPEN|PCIM_CMD_SERRESPEN); 62851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, 62861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_cmd, /*bytes*/2); 62871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 62881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, HCNTRL, CHIPRST | ahd->pause); 62891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 62911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ensure that the reset has finished. We delay 1000us 62921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * prior to reading the register to make sure the chip 62931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has sufficiently completed its reset to handle register 62941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * accesses. 62951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 62961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait = 1000; 62971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 62981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_delay(1000); 62991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (--wait && !(ahd_inb(ahd, HCNTRL) & CHIPRSTACK)); 63001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wait == 0) { 630248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: WARNING - Failed chip reset! " 63031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Trying to initialize anyway.\n", ahd_name(ahd)); 63041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 63051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, HCNTRL, ahd->pause); 63061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_PCIX_CHIPRST_BUG) != 0) { 63081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 63091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear any latched PCI error status and restore 63101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * previous SERR and PERR response enables. 63111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 63121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1, 63131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0xFF, /*bytes*/1); 63141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, 63151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd, /*bytes*/2); 63161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 63171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 63191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Mode should be SCSI after a chip reset, but lets 63201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set it just to be safe. We touch the MODE_PTR 63211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * register directly so as to bypass the lazy update 63221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * code in ahd_set_modes(). 63231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 63241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_known_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 63251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, MODE_PTR, 63261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_build_mode_state(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI)); 63271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 63291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Restore SXFRCTL1. 63301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 63311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We must always initialize STPWEN to 1 before we 63321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * restore the saved values. STPWEN is initialized 63331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to a tri-state condition which can only be cleared 63341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by turning it on. 63351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 63361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SXFRCTL1, sxfrctl1|STPWEN); 63371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SXFRCTL1, sxfrctl1); 63381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Determine chip configuration */ 63401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->features &= ~AHD_WIDE; 63411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_inb(ahd, SBLKCTL) & SELWIDE) != 0) 63421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->features |= AHD_WIDE; 63431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 63451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If a recovery action has forced a chip reset, 63461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * re-initialize the chip to our liking. 63471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 63481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reinit != 0) 63491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_chip_init(ahd); 63501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 63521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 63531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 63551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Determine the number of SCBs available on the controller 63561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6357289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic int 63581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_probe_scbs(struct ahd_softc *ahd) { 63591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 63601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 63621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 63631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < AHD_SCB_MAX; i++) { 63641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int j; 63651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, i); 63671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, SCB_BASE, i); 63681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = 2; j < 64; j++) 63691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCB_BASE+j, 0); 63701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start out life as unallocated (needing an abort) */ 63711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCB_CONTROL, MK_MESSAGE); 63721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_inw_scbram(ahd, SCB_BASE) != i) 63731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 63741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, 0); 63751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_inw_scbram(ahd, SCB_BASE) != 0) 63761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 63771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 63781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (i); 63791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 63801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 63821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 63831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 63841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t *baddr; 63851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds baddr = (dma_addr_t *)arg; 63871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *baddr = segs->ds_addr; 63881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 63891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 63911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_initialize_hscbs(struct ahd_softc *ahd) 63921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 63931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 63941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ahd->scb_data.maxhscbs; i++) { 63961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, i); 63971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear the control byte. */ 63991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCB_CONTROL, 0); 64001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set the next pointer */ 64021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, SCB_NEXT, SCB_LIST_NULL); 64031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 64041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 64051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 64071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_init_scbdata(struct ahd_softc *ahd) 64081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 64091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb_data *scb_data; 64101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 64111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_data = &ahd->scb_data; 64131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TAILQ_INIT(&scb_data->free_scbs); 64141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < AHD_NUM_TARGETS * AHD_NUM_LUNS_NONPKT; i++) 64151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_INIT(&scb_data->free_scb_lists[i]); 64161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_INIT(&scb_data->any_dev_free_scb_list); 64171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SLIST_INIT(&scb_data->hscb_maps); 64181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SLIST_INIT(&scb_data->sg_maps); 64191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SLIST_INIT(&scb_data->sense_maps); 64201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Determine the number of hardware SCBs and initialize them */ 64221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_data->maxhscbs = ahd_probe_scbs(ahd); 64231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb_data->maxhscbs == 0) { 642448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: No SCB space found\n", ahd_name(ahd)); 64251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (ENXIO); 64261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 64271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_initialize_hscbs(ahd); 64291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 64311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Create our DMA tags. These tags define the kinds of device 64321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * accessible memory allocations and memory mappings we will 64331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * need to perform during normal operation. 64341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 64351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unless we need to further restrict the allocation, we rely 64361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on the restrictions of the parent dmat, hence the common 64371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * use of MAXADDR and MAXSIZE. 64381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 64391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* DMA tag for our hardware scb structures */ 64411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, 64421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, 64431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 64441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*highaddr*/BUS_SPACE_MAXADDR, 64451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*filter*/NULL, /*filterarg*/NULL, 64461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PAGE_SIZE, /*nsegments*/1, 64471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 64481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*flags*/0, &scb_data->hscb_dmat) != 0) { 64491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error_exit; 64501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 64511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_data->init_level++; 64531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* DMA tag for our S/G structures. */ 64551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/8, 64561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, 64571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 64581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*highaddr*/BUS_SPACE_MAXADDR, 64591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*filter*/NULL, /*filterarg*/NULL, 64601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_sglist_allocsize(ahd), /*nsegments*/1, 64611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 64621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*flags*/0, &scb_data->sg_dmat) != 0) { 64631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error_exit; 64641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 64651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 64661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MEMORY) != 0) 646748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: ahd_sglist_allocsize = 0x%x\n", ahd_name(ahd), 64681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_sglist_allocsize(ahd)); 64691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 64701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_data->init_level++; 64721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* DMA tag for our sense buffers. We allocate in page sized chunks */ 64741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, 64751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, 64761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 64771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*highaddr*/BUS_SPACE_MAXADDR, 64781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*filter*/NULL, /*filterarg*/NULL, 64791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PAGE_SIZE, /*nsegments*/1, 64801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 64811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*flags*/0, &scb_data->sense_dmat) != 0) { 64821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error_exit; 64831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 64841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_data->init_level++; 64861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Perform initial CCB allocation */ 64881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_alloc_scbs(ahd); 64891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb_data->numscbs == 0) { 649148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: ahd_init_scbdata - " 64921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Unable to allocate initial scbs\n", 64931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd)); 64941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error_exit; 64951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 64961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 649825985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Note that we were successful 64991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 65001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 65011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror_exit: 65031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (ENOMEM); 65051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 65061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct scb * 65081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_find_scb_by_tag(struct ahd_softc *ahd, u_int tag) 65091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 65101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 65111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 65131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Look on the pending list. 65141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 65151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) { 65161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (SCB_GET_TAG(scb) == tag) 65171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (scb); 65181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 65191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 65211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Then on all of the collision free lists. 65221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 65231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) { 65241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *list_scb; 65251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_scb = scb; 65271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 65281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (SCB_GET_TAG(list_scb) == tag) 65291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (list_scb); 65301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_scb = LIST_NEXT(list_scb, collision_links); 65311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (list_scb); 65321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 65331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 65351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And finally on the generic free list. 65361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 65371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_FOREACH(scb, &ahd->scb_data.any_dev_free_scb_list, links.le) { 65381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (SCB_GET_TAG(scb) == tag) 65391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (scb); 65401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 65411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (NULL); 65431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 65441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 65461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_fini_scbdata(struct ahd_softc *ahd) 65471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 65481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb_data *scb_data; 65491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_data = &ahd->scb_data; 65511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb_data == NULL) 65521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 65531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (scb_data->init_level) { 65551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 65561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 7: 65571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 65581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct map_node *sns_map; 65591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((sns_map = SLIST_FIRST(&scb_data->sense_maps)) != NULL) { 65611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SLIST_REMOVE_HEAD(&scb_data->sense_maps, links); 65621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dmamap_unload(ahd, scb_data->sense_dmat, 65631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sns_map->dmamap); 65641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dmamem_free(ahd, scb_data->sense_dmat, 65651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sns_map->vaddr, sns_map->dmamap); 656648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(sns_map); 65671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 65681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dma_tag_destroy(ahd, scb_data->sense_dmat); 65691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 65701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 65711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 6: 65721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 65731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct map_node *sg_map; 65741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((sg_map = SLIST_FIRST(&scb_data->sg_maps)) != NULL) { 65761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SLIST_REMOVE_HEAD(&scb_data->sg_maps, links); 65771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dmamap_unload(ahd, scb_data->sg_dmat, 65781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_map->dmamap); 65791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dmamem_free(ahd, scb_data->sg_dmat, 65801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_map->vaddr, sg_map->dmamap); 658148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(sg_map); 65821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 65831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dma_tag_destroy(ahd, scb_data->sg_dmat); 65841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 65851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 65861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 5: 65871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 65881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct map_node *hscb_map; 65891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((hscb_map = SLIST_FIRST(&scb_data->hscb_maps)) != NULL) { 65911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SLIST_REMOVE_HEAD(&scb_data->hscb_maps, links); 65921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dmamap_unload(ahd, scb_data->hscb_dmat, 65931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb_map->dmamap); 65941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dmamem_free(ahd, scb_data->hscb_dmat, 65951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb_map->vaddr, hscb_map->dmamap); 659648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(hscb_map); 65971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 65981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dma_tag_destroy(ahd, scb_data->hscb_dmat); 65991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 66001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 66011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 4: 66021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 3: 66031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: 66041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: 66051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 66061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 66071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 66081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 66091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 66111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DSP filter Bypass must be enabled until the first selection 66121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * after a change in bus mode (Razor #491 and #493). 66131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 66141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 66151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_setup_iocell_workaround(struct ahd_softc *ahd) 66161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 66171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mode_state saved_modes; 66181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_modes = ahd_save_modes(ahd); 66201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 66211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, DSPDATACTL, ahd_inb(ahd, DSPDATACTL) 66221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | BYPASSENAB | RCVROFFSTDIS | XMITOFFSTDIS); 66231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) | (ENSELDO|ENSELDI)); 66241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 66251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MISC) != 0) 662648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Setting up iocell workaround\n", ahd_name(ahd)); 66271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 66281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restore_modes(ahd, saved_modes); 66291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags &= ~AHD_HAD_FIRST_SEL; 66301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 66311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 66331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_iocell_first_selection(struct ahd_softc *ahd) 66341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 66351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mode_state saved_modes; 66361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int sblkctl; 66371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->flags & AHD_HAD_FIRST_SEL) != 0) 66391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 66401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_modes = ahd_save_modes(ahd); 66411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 66421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sblkctl = ahd_inb(ahd, SBLKCTL); 66431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 66441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 66451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MISC) != 0) 664648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: iocell first selection\n", ahd_name(ahd)); 66471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 66481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((sblkctl & ENAB40) != 0) { 66491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, DSPDATACTL, 66501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, DSPDATACTL) & ~BYPASSENAB); 66511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 66521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MISC) != 0) 665348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: BYPASS now disabled\n", ahd_name(ahd)); 66541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 66551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 66561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) & ~(ENSELDO|ENSELDI)); 66571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRINT, CLRSCSIINT); 66581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restore_modes(ahd, saved_modes); 66591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags |= AHD_HAD_FIRST_SEL; 66601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 66611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*************************** SCB Management ***********************************/ 66631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 66641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_add_col_list(struct ahd_softc *ahd, struct scb *scb, u_int col_idx) 66651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 66661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb_list *free_list; 66671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb_tailq *free_tailq; 66681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *first_scb; 66691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->flags |= SCB_ON_COL_LIST; 66711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_SET_SCB_COL_IDX(scb, col_idx); 66721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_list = &ahd->scb_data.free_scb_lists[col_idx]; 66731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_tailq = &ahd->scb_data.free_scbs; 66741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds first_scb = LIST_FIRST(free_list); 66751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (first_scb != NULL) { 66761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_INSERT_AFTER(first_scb, scb, collision_links); 66771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 66781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_INSERT_HEAD(free_list, scb, collision_links); 66791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TAILQ_INSERT_TAIL(free_tailq, scb, links.tqe); 66801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 66811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 66821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 66841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_rem_col_list(struct ahd_softc *ahd, struct scb *scb) 66851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 66861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb_list *free_list; 66871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb_tailq *free_tailq; 66881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *first_scb; 66891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int col_idx; 66901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->flags &= ~SCB_ON_COL_LIST; 66921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds col_idx = AHD_GET_SCB_COL_IDX(ahd, scb); 66931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_list = &ahd->scb_data.free_scb_lists[col_idx]; 66941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_tailq = &ahd->scb_data.free_scbs; 66951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds first_scb = LIST_FIRST(free_list); 66961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (first_scb == scb) { 66971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *next_scb; 66981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 67001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Maintain order in the collision free 67011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lists for fairness if this device has 67021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * other colliding tags active. 67031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 67041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb = LIST_NEXT(scb, collision_links); 67051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (next_scb != NULL) { 67061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TAILQ_INSERT_AFTER(free_tailq, scb, 67071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb, links.tqe); 67081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 67091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TAILQ_REMOVE(free_tailq, scb, links.tqe); 67101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 67111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_REMOVE(scb, collision_links); 67121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 67131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 67151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get a free scb. If there are none, see if we can allocate a new SCB. 67161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 67171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct scb * 67181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_get_scb(struct ahd_softc *ahd, u_int col_idx) 67191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 67201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 67211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tries; 67221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tries = 0; 67241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslook_again: 67251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) { 67261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (AHD_GET_SCB_COL_IDX(ahd, scb) != col_idx) { 67271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_rem_col_list(ahd, scb); 67281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto found; 67291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 67301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 67311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((scb = LIST_FIRST(&ahd->scb_data.any_dev_free_scb_list)) == NULL) { 67321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tries++ != 0) 67341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (NULL); 67351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_alloc_scbs(ahd); 67361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto look_again; 67371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 67381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_REMOVE(scb, links.le); 67391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (col_idx != AHD_NEVER_COL_IDX 67401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (scb->col_scb != NULL) 67411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (scb->col_scb->flags & SCB_ACTIVE) == 0) { 67421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_REMOVE(scb->col_scb, links.le); 67431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_add_col_list(ahd, scb->col_scb, col_idx); 67441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 67451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfound: 67461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->flags |= SCB_ACTIVE; 67471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (scb); 67481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 67491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 67511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return an SCB resource to the free list. 67521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 67531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 67541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_free_scb(struct ahd_softc *ahd, struct scb *scb) 6755be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 67561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clean up for the next user */ 67571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->flags = SCB_FLAG_NONE; 67581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->hscb->control = 0; 67591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = NULL; 67601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb->col_scb == NULL) { 67621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 67641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * No collision possible. Just free normally. 67651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 67661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list, 67671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb, links.le); 67681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((scb->col_scb->flags & SCB_ON_COL_LIST) != 0) { 67691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 67711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The SCB we might have collided with is on 67721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a free collision list. Put both SCBs on 67731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the generic list. 67741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 67751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_rem_col_list(ahd, scb->col_scb); 67761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list, 67771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb, links.le); 67781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list, 67791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->col_scb, links.le); 67801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((scb->col_scb->flags 67811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds & (SCB_PACKETIZED|SCB_ACTIVE)) == SCB_ACTIVE 67821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (scb->col_scb->hscb->control & TAG_ENB) != 0) { 67831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 67851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The SCB we might collide with on the next allocation 67861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is still active in a non-packetized, tagged, context. 67871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Put us on the SCB collision list. 67881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 67891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_add_col_list(ahd, scb, 67901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_GET_SCB_COL_IDX(ahd, scb->col_scb)); 67911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 67921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 67931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The SCB we might collide with on the next allocation 67941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is either active in a packetized context, or free. 67951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since we can't collide, put this SCB on the generic 67961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * free list. 67971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 67981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list, 67991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb, links.le); 68001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 68011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_platform_scb_free(ahd, scb); 68031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 68041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6805289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void 68061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_alloc_scbs(struct ahd_softc *ahd) 68071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 68081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb_data *scb_data; 68091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *next_scb; 68101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hardware_scb *hscb; 68111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct map_node *hscb_map; 68121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct map_node *sg_map; 68131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct map_node *sense_map; 68141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t *segs; 68151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t *sense_data; 68161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t hscb_busaddr; 68171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t sg_busaddr; 68181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t sense_busaddr; 68191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int newcount; 68201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 68211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_data = &ahd->scb_data; 68231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb_data->numscbs >= AHD_SCB_MAX_ALLOC) 68241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Can't allocate any more */ 68251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 68261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb_data->scbs_left != 0) { 68281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int offset; 68291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = (PAGE_SIZE / sizeof(*hscb)) - scb_data->scbs_left; 68311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb_map = SLIST_FIRST(&scb_data->hscb_maps); 68321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb = &((struct hardware_scb *)hscb_map->vaddr)[offset]; 68331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb_busaddr = hscb_map->physaddr + (offset * sizeof(*hscb)); 68341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 683548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg hscb_map = kmalloc(sizeof(*hscb_map), GFP_ATOMIC); 68361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (hscb_map == NULL) 68381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 68391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocate the next batch of hardware SCBs */ 68411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_dmamem_alloc(ahd, scb_data->hscb_dmat, 68421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void **)&hscb_map->vaddr, 68431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUS_DMA_NOWAIT, &hscb_map->dmamap) != 0) { 684448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(hscb_map); 68451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 68461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 68471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SLIST_INSERT_HEAD(&scb_data->hscb_maps, hscb_map, links); 68491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dmamap_load(ahd, scb_data->hscb_dmat, hscb_map->dmamap, 68511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb_map->vaddr, PAGE_SIZE, ahd_dmamap_cb, 68521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &hscb_map->physaddr, /*flags*/0); 68531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb = (struct hardware_scb *)hscb_map->vaddr; 68551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb_busaddr = hscb_map->physaddr; 68561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_data->scbs_left = PAGE_SIZE / sizeof(*hscb); 68571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 68581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb_data->sgs_left != 0) { 68601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int offset; 68611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = ((ahd_sglist_allocsize(ahd) / ahd_sglist_size(ahd)) 68631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - scb_data->sgs_left) * ahd_sglist_size(ahd); 68641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_map = SLIST_FIRST(&scb_data->sg_maps); 68651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds segs = sg_map->vaddr + offset; 68661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_busaddr = sg_map->physaddr + offset; 68671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 686848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg sg_map = kmalloc(sizeof(*sg_map), GFP_ATOMIC); 68691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sg_map == NULL) 68711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 68721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocate the next batch of S/G lists */ 68741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_dmamem_alloc(ahd, scb_data->sg_dmat, 68751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void **)&sg_map->vaddr, 68761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUS_DMA_NOWAIT, &sg_map->dmamap) != 0) { 687748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(sg_map); 68781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 68791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 68801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links); 68821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dmamap_load(ahd, scb_data->sg_dmat, sg_map->dmamap, 68841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_map->vaddr, ahd_sglist_allocsize(ahd), 68851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dmamap_cb, &sg_map->physaddr, /*flags*/0); 68861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds segs = sg_map->vaddr; 68881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_busaddr = sg_map->physaddr; 68891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_data->sgs_left = 68901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_sglist_allocsize(ahd) / ahd_sglist_size(ahd); 68911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 68921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_debug & AHD_SHOW_MEMORY) 689348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Mapped SG data\n"); 68941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 68951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 68961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb_data->sense_left != 0) { 68981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int offset; 68991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = PAGE_SIZE - (AHD_SENSE_BUFSIZE * scb_data->sense_left); 69011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sense_map = SLIST_FIRST(&scb_data->sense_maps); 69021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sense_data = sense_map->vaddr + offset; 69031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sense_busaddr = sense_map->physaddr + offset; 69041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 690548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg sense_map = kmalloc(sizeof(*sense_map), GFP_ATOMIC); 69061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sense_map == NULL) 69081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 69091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocate the next batch of sense buffers */ 69111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_dmamem_alloc(ahd, scb_data->sense_dmat, 69121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void **)&sense_map->vaddr, 69131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUS_DMA_NOWAIT, &sense_map->dmamap) != 0) { 691448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(sense_map); 69151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 69161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 69171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SLIST_INSERT_HEAD(&scb_data->sense_maps, sense_map, links); 69191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dmamap_load(ahd, scb_data->sense_dmat, sense_map->dmamap, 69211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sense_map->vaddr, PAGE_SIZE, ahd_dmamap_cb, 69221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &sense_map->physaddr, /*flags*/0); 69231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sense_data = sense_map->vaddr; 69251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sense_busaddr = sense_map->physaddr; 69261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_data->sense_left = PAGE_SIZE / AHD_SENSE_BUFSIZE; 69271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 69281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_debug & AHD_SHOW_MEMORY) 692948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Mapped sense data\n"); 69301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 69311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 69321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69336d07cb71fdacc710fd9816cddb5c2df0f7bd96b4Amol Lad newcount = min(scb_data->sense_left, scb_data->scbs_left); 69346d07cb71fdacc710fd9816cddb5c2df0f7bd96b4Amol Lad newcount = min(newcount, scb_data->sgs_left); 69356d07cb71fdacc710fd9816cddb5c2df0f7bd96b4Amol Lad newcount = min(newcount, (AHD_SCB_MAX_ALLOC - scb_data->numscbs)); 69361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < newcount; i++) { 69371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb_platform_data *pdata; 693811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke u_int col_tag; 69391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef __linux__ 69401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 69411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 694211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 694348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg next_scb = kmalloc(sizeof(*next_scb), GFP_ATOMIC); 69441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (next_scb == NULL) 69451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 69461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 694748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg pdata = kmalloc(sizeof(*pdata), GFP_ATOMIC); 69481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pdata == NULL) { 694948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(next_scb); 69501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 69511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 69521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb->platform_data = pdata; 69531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb->hscb_map = hscb_map; 69541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb->sg_map = sg_map; 69551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb->sense_map = sense_map; 69561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb->sg_list = segs; 69571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb->sense_data = sense_data; 69581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb->sense_busaddr = sense_busaddr; 69591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(hscb, 0, sizeof(*hscb)); 69601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb->hscb = hscb; 69611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb->hscb_busaddr = ahd_htole32(hscb_busaddr); 69621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 69641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The sequencer always starts with the second entry. 69651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The first entry is embedded in the scb. 69661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 69671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb->sg_list_busaddr = sg_busaddr; 69681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) 69691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb->sg_list_busaddr 69701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds += sizeof(struct ahd_dma64_seg); 69711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 69721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb->sg_list_busaddr += sizeof(struct ahd_dma_seg); 69731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb->ahd_softc = ahd; 69741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb->flags = SCB_FLAG_NONE; 69751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef __linux__ 69761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = ahd_dmamap_create(ahd, ahd->buffer_dmat, /*flags*/0, 69771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &next_scb->dmamap); 69781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error != 0) { 697948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(next_scb); 698048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(pdata); 69811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 69821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 69831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 69841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb->hscb->tag = ahd_htole16(scb_data->numscbs); 69851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds col_tag = scb_data->numscbs ^ 0x100; 69861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb->col_scb = ahd_find_scb_by_tag(ahd, col_tag); 69871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (next_scb->col_scb != NULL) 69881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_scb->col_scb->col_scb = next_scb; 69891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_free_scb(ahd, next_scb); 69901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb++; 69911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb_busaddr += sizeof(*hscb); 69921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds segs += ahd_sglist_size(ahd); 69931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_busaddr += ahd_sglist_size(ahd); 69941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sense_data += AHD_SENSE_BUFSIZE; 69951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sense_busaddr += AHD_SENSE_BUFSIZE; 69961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_data->numscbs++; 699711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke scb_data->sense_left--; 699811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke scb_data->scbs_left--; 699911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke scb_data->sgs_left--; 70001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 70011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 70021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 70041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_controller_info(struct ahd_softc *ahd, char *buf) 70051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 70061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *speed; 70071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *type; 70081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len; 70091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = sprintf(buf, "%s: ", ahd_chip_names[ahd->chip & AHD_CHIPID_MASK]); 70111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += len; 70121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds speed = "Ultra320 "; 70141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_WIDE) != 0) { 70151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = "Wide "; 70161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 70171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = "Single "; 70181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 70191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = sprintf(buf, "%s%sChannel %c, SCSI Id=%d, ", 70201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds speed, type, ahd->channel, ahd->our_id); 70211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += len; 70221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(buf, "%s, %d SCBs", ahd->bus_description, 70241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->scb_data.maxhscbs); 70251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 70261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *channel_strings[] = { 70281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Primary Low", 70291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Primary High", 70301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Secondary Low", 70311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Secondary High" 70321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 70331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *termstat_strings[] = { 70351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Terminated Correctly", 70361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Over Terminated", 70371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Under Terminated", 70381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Not Configured" 70391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 70401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7041be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko/***************************** Timer Facilities *******************************/ 7042be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#define ahd_timer_init init_timer 7043be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko#define ahd_timer_stop del_timer_sync 7044be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkotypedef void ahd_linux_callback_t (u_long); 7045be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 7046be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkostatic void 7047be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenkoahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg) 7048be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko{ 7049be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko struct ahd_softc *ahd; 7050be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 7051be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko ahd = (struct ahd_softc *)arg; 7052be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko del_timer(timer); 7053be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko timer->data = (u_long)arg; 7054be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko timer->expires = jiffies + (usec * HZ)/1000000; 7055be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko timer->function = (ahd_linux_callback_t*)func; 7056be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko add_timer(timer); 7057be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko} 7058be0d67680d524981dd65c661efe3c9cbd52a684fDenys Vlasenko 70591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 70601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start the board, ready for normal operation 70611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 70621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 70631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_init(struct ahd_softc *ahd) 70641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 70651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t *next_vaddr; 70661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t next_baddr; 70671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t driver_data_size; 70681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 70691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 70701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int warn_user; 70711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t current_sensing; 70721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t fstat; 70731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 70751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->stack_size = ahd_probe_stack_size(ahd); 707748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg ahd->saved_stack = kmalloc(ahd->stack_size * sizeof(uint16_t), GFP_ATOMIC); 70781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->saved_stack == NULL) 70791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (ENOMEM); 70801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 708225985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Verify that the compiler hasn't over-aggressively 70831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * padded important structures. 70841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 70851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sizeof(struct hardware_scb) != 64) 70861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("Hardware SCB size is incorrect"); 70871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 70891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_DEBUG_SEQUENCER) != 0) 70901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags |= AHD_SEQUENCER_DEBUG; 70911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 70921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 70941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Default to allowing initiator operations. 70951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 70961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags |= AHD_INITIATORROLE; 70971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 70991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Only allow target mode features if this unit has them enabled. 71001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 71011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((AHD_TMODE_ENABLE & (0x1 << ahd->unit)) == 0) 71021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->features &= ~AHD_TARGETMODE; 71031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef __linux__ 71051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* DMA tag for mapping buffers into device visible space. */ 71061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, 71071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, 71081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*lowaddr*/ahd->flags & AHD_39BIT_ADDRESSING 71091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? (dma_addr_t)0x7FFFFFFFFFULL 71101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds : BUS_SPACE_MAXADDR_32BIT, 71111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*highaddr*/BUS_SPACE_MAXADDR, 71121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*filter*/NULL, /*filterarg*/NULL, 71131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*maxsize*/(AHD_NSEG - 1) * PAGE_SIZE, 71141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*nsegments*/AHD_NSEG, 71151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*maxsegsz*/AHD_MAXTRANSFER_SIZE, 71161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*flags*/BUS_DMA_ALLOCNOW, 71171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &ahd->buffer_dmat) != 0) { 71181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (ENOMEM); 71191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 71201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 71211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->init_level++; 71231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 71251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DMA tag for our command fifos and other data in system memory 71261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the card's sequencer must be able to access. For initiator 71271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * roles, we need to allocate space for the qoutfifo. When providing 71281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for the target mode role, we must additionally provide space for 71291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the incoming target command fifo. 71301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 713111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke driver_data_size = AHD_SCB_MAX * sizeof(*ahd->qoutfifo) 71321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds + sizeof(struct hardware_scb); 71331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_TARGETMODE) != 0) 71341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver_data_size += AHD_TMODE_CMDS * sizeof(struct target_cmd); 71351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) 71361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver_data_size += PKT_OVERRUN_BUFSIZE; 71371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, 71381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, 71391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 71401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*highaddr*/BUS_SPACE_MAXADDR, 71411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*filter*/NULL, /*filterarg*/NULL, 71421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver_data_size, 71431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*nsegments*/1, 71441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 71451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*flags*/0, &ahd->shared_data_dmat) != 0) { 71461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (ENOMEM); 71471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 71481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->init_level++; 71501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocation of driver data */ 71521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_dmamem_alloc(ahd, ahd->shared_data_dmat, 715366a0683e4620f087e41e79d4d2be6c5a06bb206bHannes Reinecke (void **)&ahd->shared_data_map.vaddr, 715466a0683e4620f087e41e79d4d2be6c5a06bb206bHannes Reinecke BUS_DMA_NOWAIT, 715566a0683e4620f087e41e79d4d2be6c5a06bb206bHannes Reinecke &ahd->shared_data_map.dmamap) != 0) { 71561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (ENOMEM); 71571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 71581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->init_level++; 71601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* And permanently map it in */ 716266a0683e4620f087e41e79d4d2be6c5a06bb206bHannes Reinecke ahd_dmamap_load(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap, 716366a0683e4620f087e41e79d4d2be6c5a06bb206bHannes Reinecke ahd->shared_data_map.vaddr, driver_data_size, 716466a0683e4620f087e41e79d4d2be6c5a06bb206bHannes Reinecke ahd_dmamap_cb, &ahd->shared_data_map.physaddr, 716566a0683e4620f087e41e79d4d2be6c5a06bb206bHannes Reinecke /*flags*/0); 716611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd->qoutfifo = (struct ahd_completion *)ahd->shared_data_map.vaddr; 71671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_vaddr = (uint8_t *)&ahd->qoutfifo[AHD_QOUT_SIZE]; 716866a0683e4620f087e41e79d4d2be6c5a06bb206bHannes Reinecke next_baddr = ahd->shared_data_map.physaddr 716911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke + AHD_QOUT_SIZE*sizeof(struct ahd_completion); 71701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_TARGETMODE) != 0) { 71711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->targetcmds = (struct target_cmd *)next_vaddr; 71721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_vaddr += AHD_TMODE_CMDS * sizeof(struct target_cmd); 71731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_baddr += AHD_TMODE_CMDS * sizeof(struct target_cmd); 71741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 71751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) { 71771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->overrun_buf = next_vaddr; 71781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_vaddr += PKT_OVERRUN_BUFSIZE; 71791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_baddr += PKT_OVERRUN_BUFSIZE; 71801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 71811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 71831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We need one SCB to serve as the "next SCB". Since the 71841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tag identifier in this SCB will never be used, there is 71851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * no point in using a valid HSCB tag from an SCB pulled from 71861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the standard free pool. So, we allocate this "sentinel" 71871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * specially from the DMA safe memory chunk used for the QOUTFIFO. 71881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 71891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->next_queued_hscb = (struct hardware_scb *)next_vaddr; 719066a0683e4620f087e41e79d4d2be6c5a06bb206bHannes Reinecke ahd->next_queued_hscb_map = &ahd->shared_data_map; 71911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->next_queued_hscb->hscb_busaddr = ahd_htole32(next_baddr); 71921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->init_level++; 71941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocate SCB data now that buffer_dmat is initialized */ 71961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_init_scbdata(ahd) != 0) 71971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (ENOMEM); 71981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->flags & AHD_INITIATORROLE) == 0) 72001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags &= ~AHD_RESET_BUS_A; 72011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 72021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 72031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Before committing these settings to the chip, give 72041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the OSM one last chance to modify our configuration. 72051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 72061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_platform_init(ahd); 72071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 72081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Bring up the chip. */ 72091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_chip_init(ahd); 72101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 72111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 72121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 72131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->flags & AHD_CURRENT_SENSING) == 0) 72141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto init_done; 72151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 72161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 72171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Verify termination based on current draw and 72181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * warn user if the bus is over/under terminated. 72191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 72201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = ahd_write_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, 72211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CURSENSE_ENB); 72221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error != 0) { 722348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: current sensing timeout 1\n", ahd_name(ahd)); 72241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto init_done; 72251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 72261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 20, fstat = FLX_FSTAT_BUSY; 72271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (fstat & FLX_FSTAT_BUSY) != 0 && i; i--) { 72281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = ahd_read_flexport(ahd, FLXADDR_FLEXSTAT, &fstat); 72291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error != 0) { 723048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: current sensing timeout 2\n", 72311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd)); 72321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto init_done; 72331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 72341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 72351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i == 0) { 723648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Timedout during current-sensing test\n", 72371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd)); 72381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto init_done; 72391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 72401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 72411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Latch Current Sensing status. */ 72421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = ahd_read_flexport(ahd, FLXADDR_CURRENT_STAT, ¤t_sensing); 72431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error != 0) { 724448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: current sensing timeout 3\n", ahd_name(ahd)); 72451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto init_done; 72461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 72471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 72481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Diable current sensing. */ 72491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_write_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, 0); 72501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 72511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 72521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_TERMCTL) != 0) { 725348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: current_sensing == 0x%x\n", 72541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), current_sensing); 72551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 72561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 72571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds warn_user = 0; 72581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++, current_sensing >>= FLX_CSTAT_SHIFT) { 72591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int term_stat; 72601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 72611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds term_stat = (current_sensing & FLX_CSTAT_MASK); 72621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (term_stat) { 72631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FLX_CSTAT_OVER: 72641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FLX_CSTAT_UNDER: 72651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds warn_user++; 72661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FLX_CSTAT_INVALID: 72671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FLX_CSTAT_OKAY: 72681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (warn_user == 0 && bootverbose == 0) 72691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 727048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: %s Channel %s\n", ahd_name(ahd), 72711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds channel_strings[i], termstat_strings[term_stat]); 72721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 72731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 72741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 72751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (warn_user) { 727648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: WARNING. Termination is not configured correctly.\n" 72771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%s: WARNING. SCSI bus operations may FAIL.\n", 72781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), ahd_name(ahd)); 72791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 72801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsinit_done: 72811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restart(ahd); 72821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US, 72831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_stat_timer, ahd); 72841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 72851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 72861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 72871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 72881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (Re)initialize chip state after a chip reset. 72891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 72901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 72911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_chip_init(struct ahd_softc *ahd) 72921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 72931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t busaddr; 72941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int sxfrctl1; 72951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scsiseq_template; 72961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int wait; 72971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int i; 72981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int target; 72991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 73011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 73021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Take the LED out of diagnostic mode 73031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 73041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SBLKCTL, ahd_inb(ahd, SBLKCTL) & ~(DIAGLEDEN|DIAGLEDON)); 73051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 73071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return HS_MAILBOX to its default value. 73081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 73091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->hs_mailbox = 0; 73101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, HS_MAILBOX, 0); 73111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1. */ 73131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, IOWNID, ahd->our_id); 73141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, TOWNID, ahd->our_id); 73151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sxfrctl1 = (ahd->flags & AHD_TERM_ENB_A) != 0 ? STPWEN : 0; 73161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sxfrctl1 |= (ahd->flags & AHD_SPCHK_ENB_A) != 0 ? ENSPCHK : 0; 73171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_LONG_SETIMO_BUG) 73181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ahd->seltime != STIMESEL_MIN)) { 73191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 73201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The selection timer duration is twice as long 73211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as it should be. Halve it by adding "1" to 73221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the user specified setting. 73231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 73241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sxfrctl1 |= ahd->seltime + STIMESEL_BUG_ADJ; 73251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 73261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sxfrctl1 |= ahd->seltime; 73271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 73281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SXFRCTL0, DFON); 73301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SXFRCTL1, sxfrctl1|ahd->seltime|ENSTIMER|ACTNEGEN); 73311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); 73321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 73341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now that termination is set, wait for up 73351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to 500ms for our transceivers to settle. If 73361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the adapter does not have a cable attached, 73371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the transceivers may never settle, so don't 73381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * complain if we fail here. 73391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 73401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (wait = 10000; 73411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ahd_inb(ahd, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait; 73421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait--) 73431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_delay(100); 73441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear any false bus resets due to the transceivers settling */ 73461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI); 73471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRINT, CLRSCSIINT); 73481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Initialize mode specific S/G state. */ 73501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 2; i++) { 73511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_DFF0 + i, AHD_MODE_DFF0 + i); 73521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR); 73531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SG_STATE, 0); 73541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSEQINTSRC, 0xFF); 73551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEQIMODE, 73561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ENSAVEPTRS|ENCFG4DATA|ENCFG4ISTAT 73571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds |ENCFG4TSTAT|ENCFG4ICMD|ENCFG4TCMD); 73581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 73591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 73611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, DSCOMMAND0, ahd_inb(ahd, DSCOMMAND0)|MPARCKEN|CACHETHEN); 73621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, DFF_THRSH, RD_DFTHRSH_75|WR_DFTHRSH_75); 73631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SIMODE0, ENIOERR|ENOVERRUN); 73641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SIMODE3, ENNTRAMPERR|ENOSRAMPERR); 73651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) { 73661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, OPTIONMODE, AUTOACKEN|AUTO_MSGOUT_DE); 73671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 73681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, OPTIONMODE, AUTOACKEN|BUSFREEREV|AUTO_MSGOUT_DE); 73691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 73701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSCHKN, CURRFIFODEF|WIDERESEN|SHVALIDSTDIS); 73711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->chip & AHD_BUS_MASK) == AHD_PCIX) 73721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 73731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Do not issue a target abort when a split completion 73741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * error occurs. Let our PCIX interrupt handler deal 73751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with it instead. H2A4 Razor #625 73761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 73771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, PCIXCTL, ahd_inb(ahd, PCIXCTL) | SPLTSTADIS); 73781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_LQOOVERRUN_BUG) != 0) 73801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQOSCSCTL, LQONOCHKOVER); 73811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 73831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Tweak IOCELL settings. 73841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 73851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->flags & AHD_HP_BOARD) != 0) { 73861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < NUMDSPS; i++) { 73871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, DSPSELECT, i); 73881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, WRTBIASCTL, WRTBIASCTL_HP_DEFAULT); 73891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 73901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 73911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MISC) != 0) 739248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: WRTBIASCTL now 0x%x\n", ahd_name(ahd), 73931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WRTBIASCTL_HP_DEFAULT); 73941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 73951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 73961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_setup_iocell_workaround(ahd); 73971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 73991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Enable LQI Manager interrupts. 74001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 74011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQIMODE1, ENLQIPHASE_LQ|ENLQIPHASE_NLQ|ENLIQABORT 74021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ENLQICRCI_LQ|ENLQICRCI_NLQ|ENLQIBADLQI 74031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ENLQIOVERI_LQ|ENLQIOVERI_NLQ); 74041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQOMODE0, ENLQOATNLQ|ENLQOATNPKT|ENLQOTCRC); 74051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 740653467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * We choose to have the sequencer catch LQOPHCHGINPKT errors 740753467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * manually for the command phase at the start of a packetized 740853467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * selection case. ENLQOBUSFREE should be made redundant by 740953467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * the BUSFREE interrupt, but it seems that some LQOBUSFREE 741053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * events fail to assert the BUSFREE interrupt so we must 741153467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * also enable LQOBUSFREE interrupts. 74121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 741353467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_outb(ahd, LQOMODE1, ENLQOBUSFREE); 74141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 74161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Setup sequencer interrupt handlers. 74171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 74181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, INTVEC1_ADDR, ahd_resolve_seqaddr(ahd, LABEL_seq_isr)); 74191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, INTVEC2_ADDR, ahd_resolve_seqaddr(ahd, LABEL_timer_isr)); 74201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 74221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Setup SCB Offset registers. 74231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 74241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0) { 74251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LUNPTR, offsetof(struct hardware_scb, 74261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_long_lun)); 74271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 74281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LUNPTR, offsetof(struct hardware_scb, lun)); 74291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 74301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CMDLENPTR, offsetof(struct hardware_scb, cdb_len)); 74311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, ATTRPTR, offsetof(struct hardware_scb, task_attribute)); 74321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, FLAGPTR, offsetof(struct hardware_scb, task_management)); 74331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CMDPTR, offsetof(struct hardware_scb, 74341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shared_data.idata.cdb)); 74351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, QNEXTPTR, 74361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offsetof(struct hardware_scb, next_hscb_busaddr)); 74371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, ABRTBITPTR, MK_MESSAGE_BIT_OFFSET); 74381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, ABRTBYTEPTR, offsetof(struct hardware_scb, control)); 74391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0) { 74401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LUNLEN, 74411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(ahd->next_queued_hscb->pkt_long_lun) - 1); 74421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 74431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LUNLEN, LUNLEN_SINGLE_LEVEL_LUN); 74441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 74451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CDBLIMIT, SCB_CDB_LEN_PTR - 1); 74461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, MAXCMD, 0xFF); 74471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCBAUTOPTR, 74481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AUSCBPTR_EN | offsetof(struct hardware_scb, tag)); 74491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We haven't been enabled for target mode yet. */ 74511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, MULTARGID, 0); 74521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, MULTARGID + 1, 0); 74531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 74551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Initialize the negotiation table. */ 74561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_NEW_IOCELL_OPTS) == 0) { 74571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 74581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear the spare bytes in the neg table to avoid 74591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * spurious parity errors. 74601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 74611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (target = 0; target < AHD_NUM_TARGETS; target++) { 74621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, NEGOADDR, target); 74631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PER_DEV0); 74641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < AHD_NUM_PER_DEV_ANNEXCOLS; i++) 74651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, ANNEXDAT, 0); 74661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 74671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 74681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (target = 0; target < AHD_NUM_TARGETS; target++) { 74691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo devinfo; 74701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_initiator_tinfo *tinfo; 74711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 74721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, 74741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target, &tstate); 74751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_compile_devinfo(&devinfo, ahd->our_id, 74761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target, CAM_LUN_WILDCARD, 74771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 'A', ROLE_INITIATOR); 74781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_update_neg_table(ahd, &devinfo, &tinfo->curr); 74791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 74801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRSINT3, NTRAMPERR|OSRAMPERR); 74821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CLRINT, CLRSCSIINT); 74831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef NEEDS_MORE_TESTING 74851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 74861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Always enable abort on incoming L_Qs if this feature is 74871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * supported. We use this to catch invalid SCB references. 74881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 74891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_ABORT_LQI_BUG) == 0) 74901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQCTL1, ABORTPENDING); 74911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 74921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 74931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, LQCTL1, 0); 74941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* All of our queues are empty */ 74961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->qoutfifonext = 0; 749711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd->qoutfifonext_valid_tag = QOUTFIFO_ENTRY_VALID; 749811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outb(ahd, QOUTFIFO_ENTRY_VALID_TAG, QOUTFIFO_ENTRY_VALID); 74991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < AHD_QOUT_SIZE; i++) 750011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd->qoutfifo[i].valid_tag = 0; 75011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_sync_qoutfifo(ahd, BUS_DMASYNC_PREREAD); 75021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->qinfifonext = 0; 75041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < AHD_QIN_SIZE; i++) 75051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->qinfifo[i] = SCB_LIST_NULL; 75061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_TARGETMODE) != 0) { 75081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* All target command blocks start out invalid. */ 75091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < AHD_TMODE_CMDS; i++) 75101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->targetcmds[i].cmd_valid = 0; 75111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_sync_tqinfifo(ahd, BUS_DMASYNC_PREREAD); 75121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->tqinfifonext = 1; 75131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, KERNEL_TQINPOS, ahd->tqinfifonext - 1); 75141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, TQINPOS, ahd->tqinfifonext); 75151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 75161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Initialize Scratch Ram. */ 75181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEQ_FLAGS, 0); 75191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEQ_FLAGS2, 0); 75201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We don't have any waiting selections */ 75221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, WAITING_TID_HEAD, SCB_LIST_NULL); 75231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, WAITING_TID_TAIL, SCB_LIST_NULL); 752453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_outw(ahd, MK_MESSAGE_SCB, SCB_LIST_NULL); 752553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_outw(ahd, MK_MESSAGE_SCSIID, 0xFF); 75261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < AHD_NUM_TARGETS; i++) 75271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, WAITING_SCB_TAILS + (2 * i), SCB_LIST_NULL); 75281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 75301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Nobody is waiting to be DMAed into the QOUTFIFO. 75311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 75321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, COMPLETE_SCB_HEAD, SCB_LIST_NULL); 75331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, COMPLETE_SCB_DMAINPROG_HEAD, SCB_LIST_NULL); 75341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, SCB_LIST_NULL); 753511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, SCB_LIST_NULL); 753611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outw(ahd, COMPLETE_ON_QFREEZE_HEAD, SCB_LIST_NULL); 75371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 75391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The Freeze Count is 0. 75401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 754166a0683e4620f087e41e79d4d2be6c5a06bb206bHannes Reinecke ahd->qfreeze_cnt = 0; 75421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, QFREEZE_COUNT, 0); 754311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outw(ahd, KERNEL_QFREEZE_COUNT, 0); 75441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 75461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Tell the sequencer where it can find our arrays in memory. 75471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 754866a0683e4620f087e41e79d4d2be6c5a06bb206bHannes Reinecke busaddr = ahd->shared_data_map.physaddr; 7549ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke ahd_outl(ahd, SHARED_DATA_ADDR, busaddr); 7550ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke ahd_outl(ahd, QOUTFIFO_NEXT_ADDR, busaddr); 75511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 75531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Setup the allowed SCSI Sequences based on operational mode. 75541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we are a target, we'll enable select in operations once 75551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we've had a lun enabled. 75561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 75571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsiseq_template = ENAUTOATNP; 75581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->flags & AHD_INITIATORROLE) != 0) 75591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsiseq_template |= ENRSELI; 75601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ_TEMPLATE, scsiseq_template); 75611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* There are no busy SCBs yet. */ 75631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (target = 0; target < AHD_NUM_TARGETS; target++) { 75641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int lun; 75651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (lun = 0; lun < AHD_NUM_LUNS_NONPKT; lun++) 75671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unbusy_tcl(ahd, BUILD_TCL_RAW(target, 'A', lun)); 75681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 75691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 75711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialize the group code to command length table. 75721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Vendor Unique codes are set to 0 so we only capture 75731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the first byte of the cdb. These can be overridden 75741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when target mode is enabled. 75751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 75761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CMDSIZE_TABLE, 5); 75771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CMDSIZE_TABLE + 1, 9); 75781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CMDSIZE_TABLE + 2, 9); 75791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CMDSIZE_TABLE + 3, 0); 75801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CMDSIZE_TABLE + 4, 15); 75811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CMDSIZE_TABLE + 5, 11); 75821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CMDSIZE_TABLE + 6, 0); 75831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CMDSIZE_TABLE + 7, 0); 75841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Tell the sequencer of our initial queue positions */ 75861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); 75871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, QOFF_CTLSTA, SCB_QSIZE_512); 75881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->qinfifonext = 0; 75891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); 75901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_hescb_qoff(ahd, 0); 75911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_snscb_qoff(ahd, 0); 75921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_sescb_qoff(ahd, 0); 75931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_sdscb_qoff(ahd, 0); 75941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 75961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Tell the sequencer which SCB will be the next one it receives. 75971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 75981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds busaddr = ahd_le32toh(ahd->next_queued_hscb->hscb_busaddr); 7599ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr); 76001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 76021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Default to coalescing disabled. 76031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 76041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, INT_COALESCING_CMDCOUNT, 0); 76051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, CMDS_PENDING, 0); 76061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_update_coalescing_values(ahd, ahd->int_coalescing_timer, 76071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->int_coalescing_maxcmds, 76081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->int_coalescing_mincmds); 76091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_enable_coalescing(ahd, FALSE); 76101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_loadseq(ahd); 76121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 76133fb086126462c2de06dddaec58981d8827be100dHannes Reinecke 76143fb086126462c2de06dddaec58981d8827be100dHannes Reinecke if (ahd->features & AHD_AIC79XXB_SLOWCRC) { 76153fb086126462c2de06dddaec58981d8827be100dHannes Reinecke u_int negodat3 = ahd_inb(ahd, NEGCONOPTS); 76163fb086126462c2de06dddaec58981d8827be100dHannes Reinecke 76173fb086126462c2de06dddaec58981d8827be100dHannes Reinecke negodat3 |= ENSLOWCRC; 76183fb086126462c2de06dddaec58981d8827be100dHannes Reinecke ahd_outb(ahd, NEGCONOPTS, negodat3); 76193fb086126462c2de06dddaec58981d8827be100dHannes Reinecke negodat3 = ahd_inb(ahd, NEGCONOPTS); 76203fb086126462c2de06dddaec58981d8827be100dHannes Reinecke if (!(negodat3 & ENSLOWCRC)) 762148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("aic79xx: failed to set the SLOWCRC bit\n"); 76223fb086126462c2de06dddaec58981d8827be100dHannes Reinecke else 762348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("aic79xx: SLOWCRC bit set\n"); 76243fb086126462c2de06dddaec58981d8827be100dHannes Reinecke } 76251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 76261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 76281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Setup default device and controller settings. 76291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This should only be called if our probe has 76301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * determined that no configuration data is available. 76311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 76321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 76331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_default_config(struct ahd_softc *ahd) 76341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 76351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int targ; 76361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->our_id = 7; 76381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 76401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate a tstate to house information for our 76411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * initiator presence on the bus as well as the user 76421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data for any target mode initiator. 76431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 76441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_alloc_tstate(ahd, ahd->our_id, 'A') == NULL) { 764548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: unable to allocate ahd_tmode_tstate. " 76461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Failing attach\n", ahd_name(ahd)); 76471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (ENOMEM); 76481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 76491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (targ = 0; targ < AHD_NUM_TARGETS; targ++) { 76511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo devinfo; 76521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_initiator_tinfo *tinfo; 76531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 76541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint16_t target_mask; 76551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, 76571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds targ, &tstate); 76581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 76591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We support SPC2 and SPI4. 76601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 76611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->user.protocol_version = 4; 76621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->user.transport_version = 4; 76631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target_mask = 0x01 << targ; 76651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->user_discenable |= target_mask; 76661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tstate->discenable |= target_mask; 76671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->user_tagenable |= target_mask; 76681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_FORCE_160 76691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->user.period = AHD_SYNCRATE_DT; 76701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 76711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->user.period = AHD_SYNCRATE_160; 76721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 76731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->user.offset = MAX_OFFSET; 76741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->user.ppr_options = MSG_EXT_PPR_RD_STRM 76751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | MSG_EXT_PPR_WR_FLOW 76761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | MSG_EXT_PPR_HOLD_MCS 76771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | MSG_EXT_PPR_IU_REQ 76781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | MSG_EXT_PPR_QAS_REQ 76791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | MSG_EXT_PPR_DT_REQ; 76801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_RTI) != 0) 76811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->user.ppr_options |= MSG_EXT_PPR_RTI; 76821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; 76841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 76861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start out Async/Narrow/Untagged and with 76871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * conservative protocol support. 76881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 76891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->goal.protocol_version = 2; 76901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->goal.transport_version = 2; 76911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->curr.protocol_version = 2; 76921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->curr.transport_version = 2; 76931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_compile_devinfo(&devinfo, ahd->our_id, 76941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds targ, CAM_LUN_WILDCARD, 76951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 'A', ROLE_INITIATOR); 76961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tstate->tagenable &= ~target_mask; 76971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, 76981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_TRANS_CUR|AHD_TRANS_GOAL, /*paused*/TRUE); 76991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, 77001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*ppr_options*/0, AHD_TRANS_CUR|AHD_TRANS_GOAL, 77011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*paused*/TRUE); 77021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 77031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 77041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 77051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 77071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Parse device configuration information. 77081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 77091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 77101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc) 77111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 77121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int targ; 77131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int max_targ; 77141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max_targ = sc->max_targets & CFMAXTARG; 77161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->our_id = sc->brtime_id & CFSCSIID; 77171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 77191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate a tstate to house information for our 77201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * initiator presence on the bus as well as the user 77211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data for any target mode initiator. 77221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 77231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_alloc_tstate(ahd, ahd->our_id, 'A') == NULL) { 772448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: unable to allocate ahd_tmode_tstate. " 77251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Failing attach\n", ahd_name(ahd)); 77261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (ENOMEM); 77271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 77281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (targ = 0; targ < max_targ; targ++) { 77301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo devinfo; 77311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_initiator_tinfo *tinfo; 77321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_transinfo *user_tinfo; 77331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 77341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint16_t target_mask; 77351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, 77371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds targ, &tstate); 77381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user_tinfo = &tinfo->user; 77391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 77411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We support SPC2 and SPI4. 77421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 77431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->user.protocol_version = 4; 77441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->user.transport_version = 4; 77451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target_mask = 0x01 << targ; 77471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->user_discenable &= ~target_mask; 77481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tstate->discenable &= ~target_mask; 77491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->user_tagenable &= ~target_mask; 77501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sc->device_flags[targ] & CFDISC) { 77511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tstate->discenable |= target_mask; 77521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->user_discenable |= target_mask; 77531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->user_tagenable |= target_mask; 77541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 77551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 77561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Cannot be packetized without disconnection. 77571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 77581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc->device_flags[targ] &= ~CFPACKETIZED; 77591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 77601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user_tinfo->ppr_options = 0; 77621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user_tinfo->period = (sc->device_flags[targ] & CFXFER); 77631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (user_tinfo->period < CFXFER_ASYNC) { 77641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (user_tinfo->period <= AHD_PERIOD_10MHz) 77651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user_tinfo->ppr_options |= MSG_EXT_PPR_DT_REQ; 77661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user_tinfo->offset = MAX_OFFSET; 77671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 77681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user_tinfo->offset = 0; 77691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user_tinfo->period = AHD_ASYNC_XFER_PERIOD; 77701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 77711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_FORCE_160 77721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (user_tinfo->period <= AHD_SYNCRATE_160) 77731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user_tinfo->period = AHD_SYNCRATE_DT; 77741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 77751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((sc->device_flags[targ] & CFPACKETIZED) != 0) { 77771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user_tinfo->ppr_options |= MSG_EXT_PPR_RD_STRM 77781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | MSG_EXT_PPR_WR_FLOW 77791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | MSG_EXT_PPR_HOLD_MCS 77801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | MSG_EXT_PPR_IU_REQ; 77811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_RTI) != 0) 77821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user_tinfo->ppr_options |= MSG_EXT_PPR_RTI; 77831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 77841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((sc->device_flags[targ] & CFQAS) != 0) 77861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user_tinfo->ppr_options |= MSG_EXT_PPR_QAS_REQ; 77871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((sc->device_flags[targ] & CFWIDEB) != 0) 77891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user_tinfo->width = MSG_EXT_WDTR_BUS_16_BIT; 77901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 77911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user_tinfo->width = MSG_EXT_WDTR_BUS_8_BIT; 77921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 77931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MISC) != 0) 779448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(%d): %x:%x:%x:%x\n", targ, user_tinfo->width, 77951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user_tinfo->period, user_tinfo->offset, 77961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user_tinfo->ppr_options); 77971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 77981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 77991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start out Async/Narrow/Untagged and with 78001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * conservative protocol support. 78011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 78021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tstate->tagenable &= ~target_mask; 78031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->goal.protocol_version = 2; 78041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->goal.transport_version = 2; 78051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->curr.protocol_version = 2; 78061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo->curr.transport_version = 2; 78071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_compile_devinfo(&devinfo, ahd->our_id, 78081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds targ, CAM_LUN_WILDCARD, 78091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 'A', ROLE_INITIATOR); 78101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, 78111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_TRANS_CUR|AHD_TRANS_GOAL, /*paused*/TRUE); 78121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, 78131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*ppr_options*/0, AHD_TRANS_CUR|AHD_TRANS_GOAL, 78141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*paused*/TRUE); 78151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 78161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags &= ~AHD_SPCHK_ENB_A; 78181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sc->bios_control & CFSPARITY) 78191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags |= AHD_SPCHK_ENB_A; 78201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags &= ~AHD_RESET_BUS_A; 78221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sc->bios_control & CFRESETB) 78231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags |= AHD_RESET_BUS_A; 78241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags &= ~AHD_EXTENDED_TRANS_A; 78261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sc->bios_control & CFEXTEND) 78271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags |= AHD_EXTENDED_TRANS_A; 78281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags &= ~AHD_BIOS_ENABLED; 78301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((sc->bios_control & CFBIOSSTATE) == CFBS_ENABLED) 78311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags |= AHD_BIOS_ENABLED; 78321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags &= ~AHD_STPWLEVEL_A; 78341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((sc->adapter_control & CFSTPWLEVEL) != 0) 78351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags |= AHD_STPWLEVEL_A; 78361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 78381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 78391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 78411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Parse device configuration information. 78421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 78431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 78441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_parse_vpddata(struct ahd_softc *ahd, struct vpd_config *vpd) 78451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 78461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 78471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = ahd_verify_vpd_cksum(vpd); 78491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error == 0) 78501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (EINVAL); 78511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((vpd->bios_flags & VPDBOOTHOST) != 0) 78521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags |= AHD_BOOT_CHANNEL; 78531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 78541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 78551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 78571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_intr_enable(struct ahd_softc *ahd, int enable) 78581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 78591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int hcntrl; 78601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hcntrl = ahd_inb(ahd, HCNTRL); 78621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hcntrl &= ~INTEN; 78631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->pause &= ~INTEN; 78641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->unpause &= ~INTEN; 78651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (enable) { 78661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hcntrl |= INTEN; 78671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->pause |= INTEN; 78681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->unpause |= INTEN; 78691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 78701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, HCNTRL, hcntrl); 78711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 78721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7873289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void 78741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_update_coalescing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds, 78751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int mincmds) 78761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 78771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (timer > AHD_TIMER_MAX_US) 78781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timer = AHD_TIMER_MAX_US; 78791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->int_coalescing_timer = timer; 78801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (maxcmds > AHD_INT_COALESCING_MAXCMDS_MAX) 78821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxcmds = AHD_INT_COALESCING_MAXCMDS_MAX; 78831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mincmds > AHD_INT_COALESCING_MINCMDS_MAX) 78841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mincmds = AHD_INT_COALESCING_MINCMDS_MAX; 78851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->int_coalescing_maxcmds = maxcmds; 78861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, INT_COALESCING_TIMER, timer / AHD_TIMER_US_PER_TICK); 78871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, INT_COALESCING_MAXCMDS, -maxcmds); 78881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, INT_COALESCING_MINCMDS, -mincmds); 78891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 78901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7891289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void 78921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_enable_coalescing(struct ahd_softc *ahd, int enable) 78931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 78941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->hs_mailbox &= ~ENINT_COALESCE; 78961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (enable) 78971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->hs_mailbox |= ENINT_COALESCE; 78981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, HS_MAILBOX, ahd->hs_mailbox); 78991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_flush_device_writes(ahd); 79001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_run_qoutfifo(ahd); 79011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 79021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 79041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ensure that the card is paused in a location 79051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * outside of all critical sections and that all 79061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pending work is completed prior to returning. 79071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine should only be called from outside 79081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * an interrupt context. 79091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 79101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 79111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_pause_and_flushwork(struct ahd_softc *ahd) 79121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 79131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int intstat; 79141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int maxloops; 79151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxloops = 1000; 79171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags |= AHD_ALL_INTERRUPTS; 79181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pause(ahd); 79191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 792011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Freeze the outgoing selections. We do this only 79211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * until we are safely paused without further selections 79221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pending. 79231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 792411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd->qfreeze_cnt--; 792511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outw(ahd, KERNEL_QFREEZE_COUNT, ahd->qfreeze_cnt); 79261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEQ_FLAGS2, ahd_inb(ahd, SEQ_FLAGS2) | SELECTOUT_QFROZEN); 79271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 79281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 793011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke /* 793111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * Give the sequencer some time to service 793211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * any active selections. 793311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke */ 793411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_delay(500); 793511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 79361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_intr(ahd); 79371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pause(ahd); 79381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intstat = ahd_inb(ahd, INTSTAT); 793911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if ((intstat & INT_PEND) == 0) { 794011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_clear_critical_section(ahd); 794111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke intstat = ahd_inb(ahd, INTSTAT); 794211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } 79431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (--maxloops 79441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (intstat != 0xFF || (ahd->features & AHD_REMOVABLE) == 0) 79451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ((intstat & INT_PEND) != 0 79461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || (ahd_inb(ahd, SCSISEQ0) & ENSELO) != 0 79471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) != 0)); 79481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (maxloops == 0) { 795048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Infinite interrupt loop, INTSTAT = %x", 79511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, INTSTAT)); 79521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 795311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd->qfreeze_cnt++; 795411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outw(ahd, KERNEL_QFREEZE_COUNT, ahd->qfreeze_cnt); 79551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_flush_qoutfifo(ahd); 79571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags &= ~AHD_ALL_INTERRUPTS; 79591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 79601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 796167eb63364ede1a16ea60b4de0dca64ca35868082FUJITA Tomonori#ifdef CONFIG_PM 79621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 79631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_suspend(struct ahd_softc *ahd) 79641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 79651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pause_and_flushwork(ahd); 79671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (LIST_FIRST(&ahd->pending_scbs) != NULL) { 79691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 79701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (EBUSY); 79711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 79721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_shutdown(ahd); 79731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 79741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 79751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7976b5720729f58a4a05b0e2c8c61ac3ed3a3e9f94e5Hannes Reineckevoid 79771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_resume(struct ahd_softc *ahd) 79781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 79791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_reset(ahd, /*reinit*/TRUE); 79811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_intr_enable(ahd, TRUE); 79821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restart(ahd); 79831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 798467eb63364ede1a16ea60b4de0dca64ca35868082FUJITA Tomonori#endif 79851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************** Busy Target Table *********************************/ 79871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 79881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set SCBPTR to the SCB that contains the busy 79891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * table entry for TCL. Return the offset into 79901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the SCB that contains the entry for TCL. 79911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * saved_scbid is dereferenced and set to the 79921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scbid that should be restored once manipualtion 79931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the TCL entry is complete. 79941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 79951beb6fa85ca9afaee109811a3f4a984232a32a4fHarvey Harrisonstatic inline u_int 79961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_index_busy_tcl(struct ahd_softc *ahd, u_int *saved_scbid, u_int tcl) 79971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 79981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 79991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Index to the SCB that contains the busy entry. 80001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 80011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 80021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *saved_scbid = ahd_get_scbptr(ahd); 80031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, TCL_LUN(tcl) 80041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((TCL_TARGET_OFFSET(tcl) & 0xC) << 4)); 80051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 80071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And now calculate the SCB offset to the entry. 80081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Each entry is 2 bytes wide, hence the 80091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * multiplication by 2. 80101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 80111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (((TCL_TARGET_OFFSET(tcl) & 0x3) << 1) + SCB_DISCONNECTED_LISTS); 80121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 80131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 80151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return the untagged transaction id for a given target/channel lun. 80161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8017289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic u_int 80181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl) 80191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 80201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 80211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scb_offset; 80221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int saved_scbptr; 80231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_offset = ahd_index_busy_tcl(ahd, &saved_scbptr, tcl); 80251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_inw_scbram(ahd, scb_offset); 80261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, saved_scbptr); 80271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (scbid); 80281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 80291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8030289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void 80311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_busy_tcl(struct ahd_softc *ahd, u_int tcl, u_int scbid) 80321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 80331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scb_offset; 80341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int saved_scbptr; 80351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_offset = ahd_index_busy_tcl(ahd, &saved_scbptr, tcl); 80371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, scb_offset, scbid); 80381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, saved_scbptr); 80391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 80401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************** SCB and SCB queue management **********************/ 8042a76106afbeb0c7d50762e7e5239496e5f7a0a074Adrian Bunkstatic int 80431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_match_scb(struct ahd_softc *ahd, struct scb *scb, int target, 80441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char channel, int lun, u_int tag, role_t role) 80451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 80461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int targ = SCB_GET_TARGET(ahd, scb); 80471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char chan = SCB_GET_CHANNEL(ahd, scb); 80481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int slun = SCB_GET_LUN(scb); 80491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int match; 80501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds match = ((chan == channel) || (channel == ALL_CHANNELS)); 80521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (match != 0) 80531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds match = ((targ == target) || (target == CAM_TARGET_WILDCARD)); 80541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (match != 0) 80551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds match = ((lun == slun) || (lun == CAM_LUN_WILDCARD)); 80561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (match != 0) { 80571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_TARGET_MODE 80581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int group; 80591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds group = XPT_FC_GROUP(scb->io_ctx->ccb_h.func_code); 80611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (role == ROLE_INITIATOR) { 80621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds match = (group != XPT_FC_GROUP_TMODE) 80631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ((tag == SCB_GET_TAG(scb)) 80641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || (tag == SCB_LIST_NULL)); 80651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (role == ROLE_TARGET) { 80661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds match = (group == XPT_FC_GROUP_TMODE) 80671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ((tag == scb->io_ctx->csio.tag_id) 80681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || (tag == SCB_LIST_NULL)); 80691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 80701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else /* !AHD_TARGET_MODE */ 80711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds match = ((tag == SCB_GET_TAG(scb)) || (tag == SCB_LIST_NULL)); 80721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* AHD_TARGET_MODE */ 80731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 80741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return match; 80761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 80771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8078289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void 80791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_freeze_devq(struct ahd_softc *ahd, struct scb *scb) 80801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 80811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int target; 80821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char channel; 80831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int lun; 80841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target = SCB_GET_TARGET(ahd, scb); 80861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lun = SCB_GET_LUN(scb); 80871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds channel = SCB_GET_CHANNEL(ahd, scb); 80881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_search_qinfifo(ahd, target, channel, lun, 80901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*tag*/SCB_LIST_NULL, ROLE_UNKNOWN, 80911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CAM_REQUEUE_REQ, SEARCH_COMPLETE); 80921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_platform_freeze_devq(ahd, scb); 80941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 80951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 80971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_qinfifo_requeue_tail(struct ahd_softc *ahd, struct scb *scb) 80981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 80991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *prev_scb; 81001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mode_state saved_modes; 81011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_modes = ahd_save_modes(ahd); 81031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); 81041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prev_scb = NULL; 81051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_qinfifo_count(ahd) != 0) { 81061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int prev_tag; 81071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int prev_pos; 81081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prev_pos = AHD_QIN_WRAP(ahd->qinfifonext - 1); 81101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prev_tag = ahd->qinfifo[prev_pos]; 81111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prev_scb = ahd_lookup_scb(ahd, prev_tag); 81121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 81131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_qinfifo_requeue(ahd, prev_scb, scb); 81141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); 81151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restore_modes(ahd, saved_modes); 81161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 81171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 81191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_qinfifo_requeue(struct ahd_softc *ahd, struct scb *prev_scb, 81201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb) 81211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 81221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (prev_scb == NULL) { 81231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t busaddr; 81241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds busaddr = ahd_le32toh(scb->hscb->hscb_busaddr); 8126ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr); 81271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 81281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prev_scb->hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr; 81291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_sync_scb(ahd, prev_scb, 81301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 81311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 81321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb); 81331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->qinfifonext++; 81341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->hscb->next_hscb_busaddr = ahd->next_queued_hscb->hscb_busaddr; 81351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 81361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 81371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 81391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_qinfifo_count(struct ahd_softc *ahd) 81401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 81411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int qinpos; 81421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int wrap_qinpos; 81431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int wrap_qinfifonext; 81441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 81461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qinpos = ahd_get_snscb_qoff(ahd); 81471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wrap_qinpos = AHD_QIN_WRAP(qinpos); 81481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wrap_qinfifonext = AHD_QIN_WRAP(ahd->qinfifonext); 81491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wrap_qinfifonext >= wrap_qinpos) 81501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (wrap_qinfifonext - wrap_qinpos); 81511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 81521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (wrap_qinfifonext 81536391a11375de5e2bb1eb8481e54619761dc65d9fTobias Klauser + ARRAY_SIZE(ahd->qinfifo) - wrap_qinpos); 81541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 81551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8156d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 81571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_reset_cmds_pending(struct ahd_softc *ahd) 81581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 81591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 81601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mode_state saved_modes; 81611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int pending_cmds; 81621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_modes = ahd_save_modes(ahd); 81641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); 81651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 81671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Don't count any commands as outstanding that the 81681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sequencer has already marked for completion. 81691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 81701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_flush_qoutfifo(ahd); 81711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pending_cmds = 0; 81731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) { 81741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pending_cmds++; 81751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 81761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, CMDS_PENDING, pending_cmds - ahd_qinfifo_count(ahd)); 81771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restore_modes(ahd, saved_modes); 81781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags &= ~AHD_UPDATE_PEND_CMDS; 81791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 81801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 818124f6d2fd314f8580fcfd96391ce9689727d55572Adrian Bunkstatic void 818253467e636b7beb350c307cc88323aae4676577f2Hannes Reineckeahd_done_with_status(struct ahd_softc *ahd, struct scb *scb, uint32_t status) 818353467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke{ 818453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke cam_status ostat; 818553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke cam_status cstat; 818653467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke 818753467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ostat = ahd_get_transaction_status(scb); 818853467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke if (ostat == CAM_REQ_INPROG) 818953467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_set_transaction_status(scb, status); 819053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke cstat = ahd_get_transaction_status(scb); 819153467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke if (cstat != CAM_REQ_CMP) 819253467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_freeze_scb(scb); 819353467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_done(ahd, scb); 819453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke} 819553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke 81961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 81971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel, 81981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int lun, u_int tag, role_t role, uint32_t status, 81991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_search_action action) 82001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 82011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 820253467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke struct scb *mk_msg_scb; 82031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *prev_scb; 82041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mode_state saved_modes; 82051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int qinstart; 82061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int qinpos; 82071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int qintail; 82081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int tid_next; 82091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int tid_prev; 82101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 821153467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke u_int seq_flags2; 82121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int savedscbptr; 82131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t busaddr; 82141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int found; 82151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int targets; 82161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 82171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Must be in CCHAN mode */ 82181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_modes = ahd_save_modes(ahd); 82191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); 82201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 82211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 82221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Halt any pending SCB DMA. The sequencer will reinitiate 82231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this dma if the qinfifo is not empty once we unpause. 82241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 82251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_inb(ahd, CCSCBCTL) & (CCARREN|CCSCBEN|CCSCBDIR)) 82261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds == (CCARREN|CCSCBEN|CCSCBDIR)) { 82271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, CCSCBCTL, 82281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, CCSCBCTL) & ~(CCARREN|CCSCBEN)); 82291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((ahd_inb(ahd, CCSCBCTL) & (CCARREN|CCSCBEN)) != 0) 82301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; 82311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 82321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Determine sequencer's position in the qinfifo. */ 82331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qintail = AHD_QIN_WRAP(ahd->qinfifonext); 82341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qinstart = ahd_get_snscb_qoff(ahd); 82351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qinpos = AHD_QIN_WRAP(qinstart); 82361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found = 0; 82371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prev_scb = NULL; 82381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 82391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (action == SEARCH_PRINT) { 824048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("qinstart = %d qinfifonext = %d\nQINFIFO:", 82411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qinstart, ahd->qinfifonext); 82421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 82431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 82441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 82451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start with an empty queue. Entries that are not chosen 82461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for removal will be re-added to the queue as we go. 82471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 82481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->qinfifonext = qinstart; 82491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds busaddr = ahd_le32toh(ahd->next_queued_hscb->hscb_busaddr); 8250ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr); 82511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 82521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (qinpos != qintail) { 82531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, ahd->qinfifo[qinpos]); 82541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb == NULL) { 825548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("qinpos = %d, SCB index = %d\n", 82561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qinpos, ahd->qinfifo[qinpos]); 82571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("Loop 1\n"); 82581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 82591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 82601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_match_scb(ahd, scb, target, channel, lun, tag, role)) { 82611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 82621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We found an scb that needs to be acted on. 82631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 82641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found++; 82651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (action) { 82661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SEARCH_COMPLETE: 82671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((scb->flags & SCB_ACTIVE) == 0) 826848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Inactive SCB in qinfifo\n"); 826953467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_done_with_status(ahd, scb, status); 82701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 82711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SEARCH_REMOVE: 82721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 82731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SEARCH_PRINT: 827448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk(" 0x%x", ahd->qinfifo[qinpos]); 82751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 82761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SEARCH_COUNT: 82771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_qinfifo_requeue(ahd, prev_scb, scb); 82781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prev_scb = scb; 82791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 82801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 82811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 82821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_qinfifo_requeue(ahd, prev_scb, scb); 82831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prev_scb = scb; 82841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 82851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qinpos = AHD_QIN_WRAP(qinpos+1); 82861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 82871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 82881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); 82891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 82901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (action == SEARCH_PRINT) 829148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\nWAITING_TID_QUEUES:\n"); 82921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 82931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 82941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Search waiting for selection lists. We traverse the 82951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * list of "their ids" waiting for selection and, if 82961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * appropriate, traverse the SCBs of each "their id" 82971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * looking for matches. 82981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 829911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 830053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke seq_flags2 = ahd_inb(ahd, SEQ_FLAGS2); 830153467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke if ((seq_flags2 & PENDING_MK_MESSAGE) != 0) { 830253467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke scbid = ahd_inw(ahd, MK_MESSAGE_SCB); 830353467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke mk_msg_scb = ahd_lookup_scb(ahd, scbid); 830453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke } else 830553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke mk_msg_scb = NULL; 83061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds savedscbptr = ahd_get_scbptr(ahd); 83071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tid_next = ahd_inw(ahd, WAITING_TID_HEAD); 83081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tid_prev = SCB_LIST_NULL; 83091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds targets = 0; 83101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (scbid = tid_next; !SCBID_IS_NULL(scbid); scbid = tid_next) { 83111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int tid_head; 831253467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke u_int tid_tail; 83131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 83141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds targets++; 831553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke if (targets > AHD_NUM_TARGETS) 83161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("TID LIST LOOP"); 831753467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke 83181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scbid >= ahd->scb_data.numscbs) { 831948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Waiting TID List inconsistency. " 83201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "SCB index == 0x%x, yet numscbs == 0x%x.", 83211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), scbid, ahd->scb_data.numscbs); 83221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 83231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("for safety"); 83241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 83251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 83261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb == NULL) { 832748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: SCB = 0x%x Not Active!\n", 83281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), scbid); 83291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("Waiting TID List traversal\n"); 83301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 83311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, scbid); 83321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tid_next = ahd_inw_scbram(ahd, SCB_NEXT2); 83331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_match_scb(ahd, scb, target, channel, CAM_LUN_WILDCARD, 83341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_LIST_NULL, ROLE_UNKNOWN) == 0) { 83351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tid_prev = scbid; 83361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 83371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 83381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 83391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 83401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We found a list of scbs that needs to be searched. 83411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 83421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (action == SEARCH_PRINT) 834348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk(" %d ( ", SCB_GET_TARGET(ahd, scb)); 83441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tid_head = scbid; 83451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found += ahd_search_scb_list(ahd, target, channel, 83461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lun, tag, role, status, 834753467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke action, &tid_head, &tid_tail, 83481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_TARGET(ahd, scb)); 834953467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke /* 835053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * Check any MK_MESSAGE SCB that is still waiting to 835153467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * enter this target's waiting for selection queue. 835253467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke */ 835353467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke if (mk_msg_scb != NULL 835453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke && ahd_match_scb(ahd, mk_msg_scb, target, channel, 835553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke lun, tag, role)) { 835653467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke 835753467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke /* 835853467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * We found an scb that needs to be acted on. 835953467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke */ 836053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke found++; 836153467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke switch (action) { 836253467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke case SEARCH_COMPLETE: 836353467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke if ((mk_msg_scb->flags & SCB_ACTIVE) == 0) 836448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Inactive SCB pending MK_MSG\n"); 836553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_done_with_status(ahd, mk_msg_scb, status); 836653467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke /* FALLTHROUGH */ 836753467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke case SEARCH_REMOVE: 836853467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke { 836953467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke u_int tail_offset; 837053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke 837148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Removing MK_MSG scb\n"); 837253467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke 837353467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke /* 837453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * Reset our tail to the tail of the 837553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * main per-target list. 837653467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke */ 837753467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke tail_offset = WAITING_SCB_TAILS 837853467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke + (2 * SCB_GET_TARGET(ahd, mk_msg_scb)); 837953467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_outw(ahd, tail_offset, tid_tail); 838053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke 838153467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke seq_flags2 &= ~PENDING_MK_MESSAGE; 838253467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_outb(ahd, SEQ_FLAGS2, seq_flags2); 838353467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_outw(ahd, CMDS_PENDING, 838453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_inw(ahd, CMDS_PENDING)-1); 838553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke mk_msg_scb = NULL; 838653467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke break; 838753467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke } 838853467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke case SEARCH_PRINT: 838948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk(" 0x%x", SCB_GET_TAG(scb)); 839053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke /* FALLTHROUGH */ 839153467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke case SEARCH_COUNT: 839253467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke break; 839353467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke } 839453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke } 839553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke 839653467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke if (mk_msg_scb != NULL 839753467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke && SCBID_IS_NULL(tid_head) 839853467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke && ahd_match_scb(ahd, scb, target, channel, CAM_LUN_WILDCARD, 839953467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke SCB_LIST_NULL, ROLE_UNKNOWN)) { 840053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke 840153467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke /* 840253467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * When removing the last SCB for a target 840353467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * queue with a pending MK_MESSAGE scb, we 840453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * must queue the MK_MESSAGE scb. 840553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke */ 840648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Queueing mk_msg_scb\n"); 840753467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke tid_head = ahd_inw(ahd, MK_MESSAGE_SCB); 840853467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke seq_flags2 &= ~PENDING_MK_MESSAGE; 840953467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_outb(ahd, SEQ_FLAGS2, seq_flags2); 841053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke mk_msg_scb = NULL; 841153467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke } 84121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tid_head != scbid) 84131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_stitch_tid_list(ahd, tid_prev, tid_head, tid_next); 84141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!SCBID_IS_NULL(tid_head)) 84151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tid_prev = tid_head; 84161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (action == SEARCH_PRINT) 841748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk(")\n"); 84181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 841953467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke 842053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke /* Restore saved state. */ 84211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, savedscbptr); 84221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restore_modes(ahd, saved_modes); 84231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (found); 84241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 84251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 84261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 84271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_search_scb_list(struct ahd_softc *ahd, int target, char channel, 84281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int lun, u_int tag, role_t role, uint32_t status, 842953467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_search_action action, u_int *list_head, 843053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke u_int *list_tail, u_int tid) 84311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 84321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 84331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 84341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int next; 84351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int prev; 84361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int found; 84371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 843811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 84391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found = 0; 84401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prev = SCB_LIST_NULL; 84411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next = *list_head; 844253467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke *list_tail = SCB_LIST_NULL; 84431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (scbid = next; !SCBID_IS_NULL(scbid); scbid = next) { 84441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scbid >= ahd->scb_data.numscbs) { 844548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s:SCB List inconsistency. " 84461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "SCB == 0x%x, yet numscbs == 0x%x.", 84471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), scbid, ahd->scb_data.numscbs); 84481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_card_state(ahd); 84491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("for safety"); 84501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 84511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb = ahd_lookup_scb(ahd, scbid); 84521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scb == NULL) { 845348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: SCB = %d Not Active!\n", 84541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), scbid); 84551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("Waiting List traversal\n"); 84561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 84571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, scbid); 845853467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke *list_tail = scbid; 84591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next = ahd_inw_scbram(ahd, SCB_NEXT); 84601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_match_scb(ahd, scb, target, channel, 84611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lun, SCB_LIST_NULL, role) == 0) { 84621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prev = scbid; 84631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 84641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 84651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found++; 84661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (action) { 84671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SEARCH_COMPLETE: 84681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((scb->flags & SCB_ACTIVE) == 0) 846948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Inactive SCB in Waiting List\n"); 847053467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_done_with_status(ahd, scb, status); 84711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 84721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SEARCH_REMOVE: 84731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_rem_wscb(ahd, scbid, prev, next, tid); 847453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke *list_tail = prev; 847553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke if (SCBID_IS_NULL(prev)) 84761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *list_head = next; 84771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 84781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SEARCH_PRINT: 847948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("0x%x ", scbid); 84801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SEARCH_COUNT: 84811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prev = scbid; 84821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 84831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 84841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (found > AHD_SCB_MAX) 84851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("SCB LIST LOOP"); 84861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 84871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (action == SEARCH_COMPLETE 84881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || action == SEARCH_REMOVE) 84891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, CMDS_PENDING, ahd_inw(ahd, CMDS_PENDING) - found); 84901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (found); 84911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 84921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 84931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 84941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_stitch_tid_list(struct ahd_softc *ahd, u_int tid_prev, 84951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int tid_cur, u_int tid_next) 84961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 849711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 84981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 84991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (SCBID_IS_NULL(tid_cur)) { 85001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 85011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Bypass current TID list */ 85021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (SCBID_IS_NULL(tid_prev)) { 85031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, WAITING_TID_HEAD, tid_next); 85041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 85051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, tid_prev); 85061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, SCB_NEXT2, tid_next); 85071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 85081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (SCBID_IS_NULL(tid_next)) 85091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, WAITING_TID_TAIL, tid_prev); 85101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 85111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 85121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Stitch through tid_cur */ 85131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (SCBID_IS_NULL(tid_prev)) { 85141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, WAITING_TID_HEAD, tid_cur); 85151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 85161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, tid_prev); 85171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, SCB_NEXT2, tid_cur); 85181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 85191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, tid_cur); 85201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, SCB_NEXT2, tid_next); 85211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 85221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (SCBID_IS_NULL(tid_next)) 85231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, WAITING_TID_TAIL, tid_cur); 85241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 85251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 85261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 85271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 85281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Manipulate the waiting for selection list and return the 85291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scb that follows the one that we remove. 85301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 85311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int 85321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_rem_wscb(struct ahd_softc *ahd, u_int scbid, 85331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int prev, u_int next, u_int tid) 85341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 85351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int tail_offset; 85361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 853711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 85381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!SCBID_IS_NULL(prev)) { 85391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, prev); 85401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, SCB_NEXT, next); 85411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 85421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 85431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 854453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * SCBs that have MK_MESSAGE set in them may 854553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * cause the tail pointer to be updated without 854653467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * setting the next pointer of the previous tail. 854753467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * Only clear the tail if the removed SCB was 854853467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke * the tail. 85491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 85501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tail_offset = WAITING_SCB_TAILS + (2 * tid); 85511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (SCBID_IS_NULL(next) 85521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ahd_inw(ahd, tail_offset) == scbid) 85531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, tail_offset, prev); 855453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke 85551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_add_scb_to_free_list(ahd, scbid); 85561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (next); 85571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 85581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 85591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 85601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Add the SCB as selected by SCBPTR onto the on chip list of 85611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * free hardware SCBs. This list is empty/unused if we are not 85621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * performing SCB paging. 85631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 85641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 85651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_add_scb_to_free_list(struct ahd_softc *ahd, u_int scbid) 85661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 85671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* XXX Need some other mechanism to designate "free". */ 85681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 85691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Invalidate the tag so that our abort 85701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * routines don't think it's active. 85711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCB_TAG, SCB_LIST_NULL); 85721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 85731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 85741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 85751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/******************************** Error Handling ******************************/ 85761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 85771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Abort all SCBs that match the given description (target/channel/lun/tag), 85781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * setting their status to the passed in status if the status has not already 85791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * been modified from CAM_REQ_INPROG. This routine assumes that the sequencer 85801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is paused before it is called. 85811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8582289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic int 85831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_abort_scbs(struct ahd_softc *ahd, int target, char channel, 85841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int lun, u_int tag, role_t role, uint32_t status) 85851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 85861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scbp; 85871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scbp_next; 85881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int i, j; 85891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int maxtarget; 85901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int minlun; 85911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int maxlun; 85921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int found; 85931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mode_state saved_modes; 85941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 85951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* restore this when we're done */ 85961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_modes = ahd_save_modes(ahd); 85971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 85981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 85991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found = ahd_search_qinfifo(ahd, target, channel, lun, SCB_LIST_NULL, 86001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds role, CAM_REQUEUE_REQ, SEARCH_COMPLETE); 86011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 86021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 86031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clean out the busy target table for any untagged commands. 86041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 86051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = 0; 86061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxtarget = 16; 86071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (target != CAM_TARGET_WILDCARD) { 86081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = target; 86091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (channel == 'B') 86101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i += 8; 86111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxtarget = i + 1; 86121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 86131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 86141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lun == CAM_LUN_WILDCARD) { 86151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds minlun = 0; 86161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxlun = AHD_NUM_LUNS_NONPKT; 86171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (lun >= AHD_NUM_LUNS_NONPKT) { 86181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds minlun = maxlun = 0; 86191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 86201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds minlun = lun; 86211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxlun = lun + 1; 86221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 86231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 86241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (role != ROLE_TARGET) { 86251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;i < maxtarget; i++) { 86261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = minlun;j < maxlun; j++) { 86271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scbid; 86281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int tcl; 86291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 86301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcl = BUILD_TCL_RAW(i, 'A', j); 86311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbid = ahd_find_busy_tcl(ahd, tcl); 86321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbp = ahd_lookup_scb(ahd, scbid); 86331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scbp == NULL 86341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || ahd_match_scb(ahd, scbp, target, channel, 86351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lun, tag, role) == 0) 86361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 86371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unbusy_tcl(ahd, BUILD_TCL_RAW(i, 'A', j)); 86381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 86391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 86401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 86411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 86421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 86431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Don't abort commands that have already completed, 86441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but haven't quite made it up to the host yet. 86451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 86461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_flush_qoutfifo(ahd); 86471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 86481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 86491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Go through the pending CCB list and look for 86501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * commands for this target that are still active. 86511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These are other tagged commands that were 86521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * disconnected when the reset occurred. 86531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 86541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbp_next = LIST_FIRST(&ahd->pending_scbs); 86551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (scbp_next != NULL) { 86561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbp = scbp_next; 86571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scbp_next = LIST_NEXT(scbp, pending_links); 86581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_match_scb(ahd, scbp, target, channel, lun, tag, role)) { 86591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cam_status ostat; 86601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 86611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ostat = ahd_get_transaction_status(scbp); 86621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ostat == CAM_REQ_INPROG) 86631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_transaction_status(scbp, status); 86641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_get_transaction_status(scbp) != CAM_REQ_CMP) 86651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_freeze_scb(scbp); 86661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((scbp->flags & SCB_ACTIVE) == 0) 866748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Inactive SCB on pending list\n"); 86681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_done(ahd, scbp); 86691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found++; 86701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 86711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 86721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restore_modes(ahd, saved_modes); 86731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_platform_abort_scbs(ahd, target, channel, lun, tag, role, status); 86741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags |= AHD_UPDATE_PEND_CMDS; 86751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return found; 86761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 86771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 86781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 86791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_reset_current_bus(struct ahd_softc *ahd) 86801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 86811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t scsiseq; 86821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 86831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 86841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) & ~ENSCSIRST); 86851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsiseq = ahd_inb(ahd, SCSISEQ0) & ~(ENSELO|ENARBO|SCSIRSTO); 86861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ0, scsiseq | SCSIRSTO); 86871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_flush_device_writes(ahd); 86881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_delay(AHD_BUSRESET_DELAY); 86891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Turn off the bus reset */ 86901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ0, scsiseq); 86911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_flush_device_writes(ahd); 86921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_delay(AHD_BUSRESET_DELAY); 86931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->bugs & AHD_SCSIRST_BUG) != 0) { 86941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 86951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2A Razor #474 86961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Certain chip state is not cleared for 86971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCSI bus resets that we initiate, so 86981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we must reset the chip. 86991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 87001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_reset(ahd, /*reinit*/TRUE); 87011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_intr_enable(ahd, /*enable*/TRUE); 87021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 87031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 87041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_clear_intstat(ahd); 87061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 87071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 87091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) 87101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8711678e80a32fcce02323bbd753ed8944ea92d0a2d5Harvey Harrison struct ahd_devinfo caminfo; 87121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int initiator; 87131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int target; 87141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int max_scsiid; 87151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int found; 87161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int fifo; 87171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int next_fifo; 8718f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke uint8_t scsiseq; 8719f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke 8720f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke /* 8721f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke * Check if the last bus reset is cleared 8722f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke */ 8723f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke if (ahd->flags & AHD_BUS_RESET_ACTIVE) { 872448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: bus reset still active\n", 8725f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke ahd_name(ahd)); 8726f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke return 0; 8727f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke } 8728f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke ahd->flags |= AHD_BUS_RESET_ACTIVE; 87291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->pending_device = NULL; 87311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8732678e80a32fcce02323bbd753ed8944ea92d0a2d5Harvey Harrison ahd_compile_devinfo(&caminfo, 87331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CAM_TARGET_WILDCARD, 87341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CAM_TARGET_WILDCARD, 87351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CAM_LUN_WILDCARD, 87361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds channel, ROLE_UNKNOWN); 87371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pause(ahd); 87381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Make sure the sequencer is in a safe location. */ 87401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_clear_critical_section(ahd); 87411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8742f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke /* 8743f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke * Run our command complete fifos to ensure that we perform 8744f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke * completion processing on any commands that 'completed' 8745f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke * before the reset occurred. 8746f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke */ 8747f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke ahd_run_qoutfifo(ahd); 87481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_TARGET_MODE 87491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->flags & AHD_TARGETROLE) != 0) { 87501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_run_tqinfifo(ahd, /*paused*/TRUE); 87511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 87521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 87531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 87541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 87561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable selections so no automatic hardware 87571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * functions will modify chip state. 87581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 87591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ0, 0); 87601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ1, 0); 87611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 87631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Safely shut down our DMA engines. Always start with 87641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the FIFO that is not currently active (if any are 87651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * actively connected). 87661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 87671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_fifo = fifo = ahd_inb(ahd, DFFSTAT) & CURRFIFO; 87681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (next_fifo > CURRFIFO_1) 87691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If disconneced, arbitrarily start with FIFO1. */ 87701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_fifo = fifo = 0; 87711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 87721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_fifo ^= CURRFIFO_1; 87731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, next_fifo, next_fifo); 87741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, DFCNTRL, 87751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, DFCNTRL) & ~(SCSIEN|HDMAEN)); 87761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((ahd_inb(ahd, DFCNTRL) & HDMAENACK) != 0) 87771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_delay(10); 87781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 87791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set CURRFIFO to the now inactive channel. 87801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 87811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 87821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, DFFSTAT, next_fifo); 87831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (next_fifo != fifo); 87841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 87861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset the bus if we are initiating this reset 87871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 87881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_clear_msg_state(ahd); 87891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SIMODE1, 8790ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke ahd_inb(ahd, SIMODE1) & ~(ENBUSFREE|ENSCSIRST)); 87911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (initiate_reset) 87931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_reset_current_bus(ahd); 87941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_clear_intstat(ahd); 87961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 87981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clean up all the state information for the 87991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pending transactions on this bus. 88001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 88011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found = ahd_abort_scbs(ahd, CAM_TARGET_WILDCARD, channel, 88021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CAM_LUN_WILDCARD, SCB_LIST_NULL, 88031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ROLE_UNKNOWN, CAM_SCSI_BUS_RESET); 88041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 88061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Cleanup anything left in the FIFOs. 88071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 88081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_clear_fifo(ahd, 0); 88091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_clear_fifo(ahd, 1); 88101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 88128883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke * Clear SCSI interrupt status 88138883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke */ 88148883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI); 88158883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke 88168883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke /* 8817f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke * Reenable selections 88181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8819f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) | ENSCSIRST); 8820f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke scsiseq = ahd_inb(ahd, SCSISEQ_TEMPLATE); 8821f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke ahd_outb(ahd, SCSISEQ1, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP)); 88221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max_scsiid = (ahd->features & AHD_WIDE) ? 15 : 7; 8824f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke#ifdef AHD_TARGET_MODE 88251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 88261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send an immediate notify ccb to all target more peripheral 88271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers affected by this action. 88281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 88291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (target = 0; target <= max_scsiid; target++) { 88301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate* tstate; 88311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lun; 88321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tstate = ahd->enabled_targets[target]; 88341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tstate == NULL) 88351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 88361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (lun = 0; lun < AHD_NUM_LUNS; lun++) { 88371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_lstate* lstate; 88381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate = tstate->enabled_luns[lun]; 88401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lstate == NULL) 88411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 88421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_queue_lstate_event(ahd, lstate, CAM_TARGET_WILDCARD, 88441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EVENT_TYPE_BUS_RESET, /*arg*/0); 88451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_send_lstate_events(ahd, lstate); 88461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 88471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 88481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 88491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8850f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke * Revert to async/narrow transfers until we renegotiate. 88511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8852f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke for (target = 0; target <= max_scsiid; target++) { 88531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8854f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke if (ahd->enabled_targets[target] == NULL) 8855f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke continue; 8856f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke for (initiator = 0; initiator <= max_scsiid; initiator++) { 8857f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke struct ahd_devinfo devinfo; 88581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8859f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke ahd_compile_devinfo(&devinfo, target, initiator, 8860f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke CAM_LUN_WILDCARD, 8861f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke 'A', ROLE_UNKNOWN); 8862f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, 8863f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke AHD_TRANS_CUR, /*paused*/TRUE); 8864f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke ahd_set_syncrate(ahd, &devinfo, /*period*/0, 8865f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke /*offset*/0, /*ppr_options*/0, 8866f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke AHD_TRANS_CUR, /*paused*/TRUE); 8867f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke } 88681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 88691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88708883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke /* Notify the XPT that a bus reset occurred */ 8871678e80a32fcce02323bbd753ed8944ea92d0a2d5Harvey Harrison ahd_send_async(ahd, caminfo.channel, CAM_TARGET_WILDCARD, 88728883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke CAM_LUN_WILDCARD, AC_BUS_RESET); 88738883c1f182fa88d2b8e0adb6ae90a42f67e5353eHannes Reinecke 8874f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke ahd_restart(ahd); 8875f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke 8876f41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2Hannes Reinecke return (found); 88771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 88781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**************************** Statistics Processing ***************************/ 88801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 88811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_stat_timer(void *arg) 88821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 888385a46523ff68aa0e4d2477c51075ffd9fc7e7a14Christoph Hellwig struct ahd_softc *ahd = arg; 88841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_long s; 88851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int enint_coal; 88861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lock(ahd, &s); 88881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enint_coal = ahd->hs_mailbox & ENINT_COALESCE; 88901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->cmdcmplt_total > ahd->int_coalescing_threshold) 88911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enint_coal |= ENINT_COALESCE; 88921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (ahd->cmdcmplt_total < ahd->int_coalescing_stop_threshold) 88931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enint_coal &= ~ENINT_COALESCE; 88941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (enint_coal != (ahd->hs_mailbox & ENINT_COALESCE)) { 88961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_enable_coalescing(ahd, enint_coal); 88971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 88981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_INT_COALESCING) != 0) 889948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Interrupt coalescing " 89001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "now %sabled. Cmds %d\n", 89011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), 89021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (enint_coal & ENINT_COALESCE) ? "en" : "dis", 89031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->cmdcmplt_total); 89041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 89051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 89061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->cmdcmplt_bucket = (ahd->cmdcmplt_bucket+1) & (AHD_STAT_BUCKETS-1); 89081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->cmdcmplt_total -= ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]; 89091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket] = 0; 89101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US, 89111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_stat_timer, ahd); 89121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unlock(ahd, &s); 89131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 89141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/****************************** Status Processing *****************************/ 89161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8917289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void 89181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) 89191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 892011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke struct hardware_scb *hscb; 892111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke int paused; 89221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 89241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The sequencer freezes its select-out queue 89251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * anytime a SCSI status error occurs. We must 892611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * handle the error and increment our qfreeze count 892711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * to allow the sequencer to continue. We don't 892811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * bother clearing critical sections here since all 892911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * operations are on data structures that the sequencer 893011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke * is not touching once the queue is frozen. 89311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 89321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb = scb->hscb; 89331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 893411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if (ahd_is_paused(ahd)) { 893511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke paused = 1; 893611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } else { 893711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke paused = 0; 893811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_pause(ahd); 893911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } 894011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 89411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Freeze the queue until the client sees the error. */ 89421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_freeze_devq(ahd, scb); 89431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_freeze_scb(scb); 894411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd->qfreeze_cnt++; 894511668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_outw(ahd, KERNEL_QFREEZE_COUNT, ahd->qfreeze_cnt); 894611668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 894711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke if (paused == 0) 894811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_unpause(ahd); 89491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Don't want to clobber the original sense code */ 89511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((scb->flags & SCB_SENSE) != 0) { 89521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 89531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear the SCB_SENSE Flag and perform 89541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a normal command completion. 89551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 89561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->flags &= ~SCB_SENSE; 89571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); 89581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_done(ahd, scb); 89591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 89601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 89611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_transaction_status(scb, CAM_SCSI_STATUS_ERROR); 89621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scsi_status(scb, hscb->shared_data.istatus.scsi_status); 89631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (hscb->shared_data.istatus.scsi_status) { 89641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case STATUS_PKT_SENSE: 89651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 89661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scsi_status_iu_header *siu; 89671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_sync_sense(ahd, scb, BUS_DMASYNC_POSTREAD); 89691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds siu = (struct scsi_status_iu_header *)scb->sense_data; 89701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scsi_status(scb, siu->status); 89711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 89721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_SENSE) != 0) { 89731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 897448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("SCB 0x%x Received PKT Status of 0x%x\n", 89751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_TAG(scb), siu->status); 897648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\tflags = 0x%x, sense len = 0x%x, " 89771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "pktfail = 0x%x\n", 89781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds siu->flags, scsi_4btoul(siu->sense_length), 89791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_4btoul(siu->pkt_failures_length)); 89801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 89811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 89821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((siu->flags & SIU_RSPVALID) != 0) { 89831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 89841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scsi_4btoul(siu->pkt_failures_length) < 4) { 898548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Unable to parse pkt_failures\n"); 89861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 89871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (SIU_PKTFAIL_CODE(siu)) { 89891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIU_PFC_NONE: 899048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("No packet failure found\n"); 89911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 89921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIU_PFC_CIU_FIELDS_INVALID: 899348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Invalid Command IU Field\n"); 89941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 89951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIU_PFC_TMF_NOT_SUPPORTED: 89963f4f27e1783b3fe57f1f8c441b1376fae48dfb15Masanari Iida printk("TMF not supported\n"); 89971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 89981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIU_PFC_TMF_FAILED: 899948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("TMF failed\n"); 90001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 90011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIU_PFC_INVALID_TYPE_CODE: 900248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Invalid L_Q Type code\n"); 90031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 90041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIU_PFC_ILLEGAL_REQUEST: 900548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Illegal request\n"); 90061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 90071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 90081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 90091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 90101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (siu->status == SCSI_STATUS_OK) 90111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_transaction_status(scb, 90121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CAM_REQ_CMP_ERR); 90131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 90141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((siu->flags & SIU_SNSVALID) != 0) { 90151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->flags |= SCB_PKT_SENSE; 90161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 90171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_SENSE) != 0) 901848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Sense data available\n"); 90191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 90201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 90211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_done(ahd, scb); 90221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 90231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 90241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SCSI_STATUS_CMD_TERMINATED: 90251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SCSI_STATUS_CHECK_COND: 90261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 90271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_devinfo devinfo; 90281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_dma_seg *sg; 90291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scsi_sense *sc; 90301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_initiator_tinfo *targ_info; 90311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 90321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_transinfo *tinfo; 90331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 90341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_debug & AHD_SHOW_SENSE) { 90351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 903648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("SCB %d: requests Check Status\n", 90371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_TAG(scb)); 90381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 90391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 90401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 90411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_perform_autosense(scb) == 0) 90421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 90431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 90441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_compile_devinfo(&devinfo, SCB_GET_OUR_ID(scb), 90451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_TARGET(ahd, scb), 90461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_LUN(scb), 90471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_CHANNEL(ahd, scb), 90481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ROLE_INITIATOR); 90491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds targ_info = ahd_fetch_transinfo(ahd, 90501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo.channel, 90511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo.our_scsiid, 90521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devinfo.target, 90531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &tstate); 90541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tinfo = &targ_info->curr; 90551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg = scb->sg_list; 90561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc = (struct scsi_sense *)hscb->shared_data.idata.cdb; 90571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 90581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Save off the residual if there is one. 90591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 90601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_update_residual(ahd, scb); 90611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 90621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_debug & AHD_SHOW_SENSE) { 90631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 906448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Sending Sense\n"); 90651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 90661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 90671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->sg_count = 0; 90681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg = ahd_sg_setup(ahd, scb, sg, ahd_get_sense_bufaddr(ahd, scb), 90691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_get_sense_bufsize(ahd, scb), 90701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*last*/TRUE); 90711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc->opcode = REQUEST_SENSE; 90721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc->byte2 = 0; 90731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tinfo->protocol_version <= SCSI_REV_2 90741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && SCB_GET_LUN(scb) < 8) 90751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc->byte2 = SCB_GET_LUN(scb) << 5; 90761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc->unused[0] = 0; 90771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc->unused[1] = 0; 90781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc->length = ahd_get_sense_bufsize(ahd, scb); 90791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc->control = 0; 90801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 90811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 90821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We can't allow the target to disconnect. 90831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This will be an untagged transaction and 90841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * having the target disconnect will make this 90851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transaction indestinguishable from outstanding 90861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tagged transactions. 90871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 90881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb->control = 0; 90891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 90901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 90911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This request sense could be because the 90921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the device lost power or in some other 90931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * way has lost our transfer negotiations. 90941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Renegotiate if appropriate. Unit attention 90951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * errors will be reported before any data 90961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * phases occur. 90971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 90981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_get_residual(scb) == ahd_get_transfer_length(scb)) { 90991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_update_neg_request(ahd, &devinfo, 91001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tstate, targ_info, 91011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_NEG_IF_NON_ASYNC); 91021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 91031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tstate->auto_negotiate & devinfo.target_mask) { 91041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb->control |= MK_MESSAGE; 91051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->flags &= 91061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ~(SCB_NEGOTIATE|SCB_ABORT|SCB_DEVICE_RESET); 91071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->flags |= SCB_AUTO_NEGOTIATE; 91081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 91091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb->cdb_len = sizeof(*sc); 91101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_setup_data_scb(ahd, scb); 91111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb->flags |= SCB_SENSE; 91121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_queue_scb(ahd, scb); 91131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 91141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 91151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SCSI_STATUS_OK: 91163f4f27e1783b3fe57f1f8c441b1376fae48dfb15Masanari Iida printk("%s: Interrupted for status of 0???\n", 91171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd)); 91181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 91191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 91201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_done(ahd, scb); 91211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 91221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 91231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 91241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9125289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void 9126289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkahd_handle_scb_status(struct ahd_softc *ahd, struct scb *scb) 9127289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk{ 9128289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk if (scb->hscb->shared_data.istatus.scsi_status != 0) { 9129289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk ahd_handle_scsi_status(ahd, scb); 9130289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk } else { 9131289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk ahd_calc_residual(ahd, scb); 9132289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk ahd_done(ahd, scb); 9133289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk } 9134289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk} 9135289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 91361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 91371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calculate the residual for a just completed SCB. 91381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9139289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic void 91401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_calc_residual(struct ahd_softc *ahd, struct scb *scb) 91411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 91421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hardware_scb *hscb; 91431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct initiator_status *spkt; 91441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t sgptr; 91451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t resid_sgptr; 91461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t resid; 91471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 91481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 91491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5 cases. 91501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1) No residual. 91511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SG_STATUS_VALID clear in sgptr. 91521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2) Transferless command 91531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3) Never performed any transfers. 91541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sgptr has SG_FULL_RESID set. 91551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4) No residual but target did not 91561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * save data pointers after the 91571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * last transfer, so sgptr was 91581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * never updated. 91591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5) We have a partial residual. 91601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Use residual_sgptr to determine 91611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * where we are. 91621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 91631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 91641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hscb = scb->hscb; 91651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgptr = ahd_le32toh(hscb->sgptr); 91661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((sgptr & SG_STATUS_VALID) == 0) 91671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Case 1 */ 91681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 91691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgptr &= ~SG_STATUS_VALID; 91701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 91711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((sgptr & SG_LIST_NULL) != 0) 91721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Case 2 */ 91731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 91741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 91751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 91761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Residual fields are the same in both 91771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * target and initiator status packets, 91781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so we can always use the initiator fields 91791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * regardless of the role for this SCB. 91801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 91811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spkt = &hscb->shared_data.istatus; 91821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resid_sgptr = ahd_le32toh(spkt->residual_sgptr); 91831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((sgptr & SG_FULL_RESID) != 0) { 91841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Case 3 */ 91851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resid = ahd_get_transfer_length(scb); 91861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((resid_sgptr & SG_LIST_NULL) != 0) { 91871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Case 4 */ 91881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 91891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((resid_sgptr & SG_OVERRUN_RESID) != 0) { 91901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 919148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("data overrun detected Tag == 0x%x.\n", 91921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCB_GET_TAG(scb)); 91931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_freeze_devq(ahd, scb); 91941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR); 91951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_freeze_scb(scb); 91961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 91971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((resid_sgptr & ~SG_PTR_MASK) != 0) { 91981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("Bogus resid sgptr value 0x%x\n", resid_sgptr); 91991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* NOTREACHED */ 92001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 92011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_dma_seg *sg; 92021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 92041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Remainder of the SG where the transfer 92051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stopped. 92061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 92071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resid = ahd_le32toh(spkt->residual_datacnt) & AHD_SG_LEN_MASK; 92081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg = ahd_sg_bus_to_virt(ahd, scb, resid_sgptr & SG_PTR_MASK); 92091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The residual sg_ptr always points to the next sg */ 92111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg--; 92121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 92141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Add up the contents of all residual 92151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SG segments that are after the SG where 92161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the transfer stopped. 92171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 92181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((ahd_le32toh(sg->len) & AHD_DMA_LAST_SEG) == 0) { 92191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg++; 92201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resid += ahd_le32toh(sg->len) & AHD_SG_LEN_MASK; 92211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 92221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 92231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((scb->flags & SCB_SENSE) == 0) 92241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_residual(scb, resid); 92251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 92261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_sense_residual(scb, resid); 92271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 92291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_MISC) != 0) { 92301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_print_path(ahd, scb); 923148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Handled %sResidual of %d bytes\n", 92321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (scb->flags & SCB_SENSE) ? "Sense " : "", resid); 92331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 92341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 92351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 92361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/******************************* Target Mode **********************************/ 92381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_TARGET_MODE 92391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 92401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Add a target mode event to this lun's queue 92411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 92421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 92431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_queue_lstate_event(struct ahd_softc *ahd, struct ahd_tmode_lstate *lstate, 92441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int initiator_id, u_int event_type, u_int event_arg) 92451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 92461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_event *event; 92471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pending; 92481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_freeze_devq(lstate->path, /*count*/1); 92501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lstate->event_w_idx >= lstate->event_r_idx) 92511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pending = lstate->event_w_idx - lstate->event_r_idx; 92521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 92531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pending = AHD_TMODE_EVENT_BUFFER_SIZE + 1 92541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - (lstate->event_r_idx - lstate->event_w_idx); 92551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (event_type == EVENT_TYPE_BUS_RESET 92571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || event_type == MSG_BUS_DEV_RESET) { 92581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 92591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Any earlier events are irrelevant, so reset our buffer. 92601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This has the effect of allowing us to deal with reset 92611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * floods (an external device holding down the reset line) 92621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * without losing the event that is really interesting. 92631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 92641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate->event_r_idx = 0; 92651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate->event_w_idx = 0; 92661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_release_devq(lstate->path, pending, /*runqueue*/FALSE); 92671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 92681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pending == AHD_TMODE_EVENT_BUFFER_SIZE) { 92701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_print_path(lstate->path); 927148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("immediate event %x:%x lost\n", 92721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate->event_buffer[lstate->event_r_idx].event_type, 92731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate->event_buffer[lstate->event_r_idx].event_arg); 92741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate->event_r_idx++; 92751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lstate->event_r_idx == AHD_TMODE_EVENT_BUFFER_SIZE) 92761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate->event_r_idx = 0; 92771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_release_devq(lstate->path, /*count*/1, /*runqueue*/FALSE); 92781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 92791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds event = &lstate->event_buffer[lstate->event_w_idx]; 92811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds event->initiator_id = initiator_id; 92821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds event->event_type = event_type; 92831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds event->event_arg = event_arg; 92841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate->event_w_idx++; 92851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lstate->event_w_idx == AHD_TMODE_EVENT_BUFFER_SIZE) 92861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate->event_w_idx = 0; 92871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 92881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 92901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send any target mode events queued up waiting 92911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for immediate notify resources. 92921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 92931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 92941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_send_lstate_events(struct ahd_softc *ahd, struct ahd_tmode_lstate *lstate) 92951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 92961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ccb_hdr *ccbh; 92971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ccb_immed_notify *inot; 92981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (lstate->event_r_idx != lstate->event_w_idx 93001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ccbh = SLIST_FIRST(&lstate->immed_notifies)) != NULL) { 93011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_event *event; 93021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 93031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds event = &lstate->event_buffer[lstate->event_r_idx]; 93041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SLIST_REMOVE_HEAD(&lstate->immed_notifies, sim_links.sle); 93051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inot = (struct ccb_immed_notify *)ccbh; 93061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (event->event_type) { 93071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case EVENT_TYPE_BUS_RESET: 93081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccbh->status = CAM_SCSI_BUS_RESET|CAM_DEV_QFRZN; 93091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 93101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 93111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccbh->status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN; 93121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inot->message_args[0] = event->event_type; 93131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inot->message_args[1] = event->event_arg; 93141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 93151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 93161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inot->initiator_id = event->initiator_id; 93171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inot->sense_len = 0; 93181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_done((union ccb *)inot); 93191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate->event_r_idx++; 93201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lstate->event_r_idx == AHD_TMODE_EVENT_BUFFER_SIZE) 93211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate->event_r_idx = 0; 93221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 93231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 93241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 93251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 93261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/******************** Sequencer Program Patching/Download *********************/ 93271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 93281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DUMP_SEQ 93291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 93301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_dumpseq(struct ahd_softc* ahd) 93311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 93321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 93331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int max_prog; 93341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 93351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max_prog = 2048; 93361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 93371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); 9338ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke ahd_outw(ahd, PRGMCNT, 0); 93391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < max_prog; i++) { 93401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t ins_bytes[4]; 93411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 93421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_insb(ahd, SEQRAM, ins_bytes, 4); 934348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("0x%08x\n", ins_bytes[0] << 24 93441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ins_bytes[1] << 16 93451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ins_bytes[2] << 8 93461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ins_bytes[3]); 93471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 93481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 93491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 93501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 93511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 93521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_loadseq(struct ahd_softc *ahd) 93531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 93541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cs cs_table[num_critical_sections]; 93551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int begin_set[num_critical_sections]; 93561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int end_set[num_critical_sections]; 9357980b306a297725d4f25c779ca15086de757acadfDenys Vlasenko const struct patch *cur_patch; 93581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int cs_count; 93591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int cur_cs; 93601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int i; 93611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int downloaded; 93621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int skip_addr; 93631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int sg_prefetch_cnt; 93641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int sg_prefetch_cnt_limit; 93651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int sg_prefetch_align; 93661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int sg_size; 936711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke u_int cacheline_mask; 93681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t download_consts[DOWNLOAD_CONST_COUNT]; 93691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 93701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bootverbose) 937148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Downloading Sequencer Program...", 93721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd)); 93731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 937411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke#if DOWNLOAD_CONST_COUNT != 8 93751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#error "Download Const Mismatch" 93761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 93771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 93781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start out with 0 critical sections 93791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that apply to this firmware load. 93801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 93811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cs_count = 0; 93821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_cs = 0; 93831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(begin_set, 0, sizeof(begin_set)); 93841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(end_set, 0, sizeof(end_set)); 93851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 93861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 93871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Setup downloadable constant table. 93881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 93891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The computation for the S/G prefetch variables is 93901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a bit complicated. We would like to always fetch 93911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in terms of cachelined sized increments. However, 93921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if the cacheline is not an even multiple of the 93931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SG element size or is larger than our SG RAM, using 93941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * just the cache size might leave us with only a portion 93951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of an SG element at the tail of a prefetch. If the 93961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cacheline is larger than our S/G prefetch buffer less 93971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the size of an SG element, we may round down to a cacheline 93981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that doesn't contain any or all of the S/G of interest 93991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * within the bounds of our S/G ram. Provide variables to 94001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the sequencer that will allow it to handle these edge 94011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cases. 94021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 94031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start by aligning to the nearest cacheline. */ 94041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_prefetch_align = ahd->pci_cachesize; 94051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sg_prefetch_align == 0) 94061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_prefetch_align = 8; 94071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Round down to the nearest power of 2. */ 94081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (powerof2(sg_prefetch_align) == 0) 94091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_prefetch_align--; 941011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 941111668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke cacheline_mask = sg_prefetch_align - 1; 941211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke 94131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 94141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the cacheline boundary is greater than half our prefetch RAM 94151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we risk not being able to fetch even a single complete S/G 94161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * segment if we align to that boundary. 94171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 94181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sg_prefetch_align > CCSGADDR_MAX/2) 94191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_prefetch_align = CCSGADDR_MAX/2; 94201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start by fetching a single cacheline. */ 94211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_prefetch_cnt = sg_prefetch_align; 94221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 94231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Increment the prefetch count by cachelines until 94241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * at least one S/G element will fit. 94251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 94261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_size = sizeof(struct ahd_dma_seg); 94271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) 94281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_size = sizeof(struct ahd_dma64_seg); 94291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (sg_prefetch_cnt < sg_size) 94301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_prefetch_cnt += sg_prefetch_align; 94311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 94321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the cacheline is not an even multiple of 94331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the S/G size, we may only get a partial S/G when 94341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we align. Add a cacheline if this is the case. 94351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 94361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((sg_prefetch_align % sg_size) != 0 94371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (sg_prefetch_cnt < CCSGADDR_MAX)) 94381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_prefetch_cnt += sg_prefetch_align; 94391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 94401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Lastly, compute a value that the sequencer can use 94411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to determine if the remainder of the CCSGRAM buffer 94421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has a full S/G element in it. 94431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 94441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sg_prefetch_cnt_limit = -(sg_prefetch_cnt - sg_size + 1); 94451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds download_consts[SG_PREFETCH_CNT] = sg_prefetch_cnt; 94461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds download_consts[SG_PREFETCH_CNT_LIMIT] = sg_prefetch_cnt_limit; 94471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds download_consts[SG_PREFETCH_ALIGN_MASK] = ~(sg_prefetch_align - 1); 94481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds download_consts[SG_PREFETCH_ADDR_MASK] = (sg_prefetch_align - 1); 94491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds download_consts[SG_SIZEOF] = sg_size; 94501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds download_consts[PKT_OVERRUN_BUFOFFSET] = 94511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ahd->overrun_buf - (uint8_t *)ahd->qoutfifo) / 256; 94521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds download_consts[SCB_TRANSFER_SIZE] = SCB_TRANSFER_SIZE_1BYTE_LUN; 945311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke download_consts[CACHELINE_MASK] = cacheline_mask; 94541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_patch = patches; 94551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds downloaded = 0; 94561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_addr = 0; 94571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); 9458ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke ahd_outw(ahd, PRGMCNT, 0); 94591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 94601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < sizeof(seqprog)/4; i++) { 94611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_check_patch(ahd, &cur_patch, i, &skip_addr) == 0) { 94621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 94631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Don't download this instruction as it 94641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is in a patch that was removed. 94651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 94661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 94671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 94681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 94691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Move through the CS table until we find a CS 94701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that might apply to this instruction. 94711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 94721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (; cur_cs < num_critical_sections; cur_cs++) { 94731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (critical_sections[cur_cs].end <= i) { 94741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (begin_set[cs_count] == TRUE 94751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && end_set[cs_count] == FALSE) { 94761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cs_table[cs_count].end = downloaded; 94771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end_set[cs_count] = TRUE; 94781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cs_count++; 94791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 94801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 94811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 94821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (critical_sections[cur_cs].begin <= i 94831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && begin_set[cs_count] == FALSE) { 94841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cs_table[cs_count].begin = downloaded; 94851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds begin_set[cs_count] = TRUE; 94861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 94871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 94881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 94891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_download_instr(ahd, i, download_consts); 94901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds downloaded++; 94911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 94921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 94931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->num_critical_sections = cs_count; 94941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cs_count != 0) { 94951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 94961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cs_count *= sizeof(struct cs); 949748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg ahd->critical_sections = kmalloc(cs_count, GFP_ATOMIC); 94981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->critical_sections == NULL) 94991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("ahd_loadseq: Could not malloc"); 95001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(ahd->critical_sections, cs_table, cs_count); 95011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 95021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE); 95031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bootverbose) { 950548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk(" %d instructions downloaded\n", downloaded); 950648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n", 95071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), ahd->features, ahd->bugs, ahd->flags); 95081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 95091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 95101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 9512980b306a297725d4f25c779ca15086de757acadfDenys Vlasenkoahd_check_patch(struct ahd_softc *ahd, const struct patch **start_patch, 95131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int start_instr, u_int *skip_addr) 95141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9515980b306a297725d4f25c779ca15086de757acadfDenys Vlasenko const struct patch *cur_patch; 9516980b306a297725d4f25c779ca15086de757acadfDenys Vlasenko const struct patch *last_patch; 95171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int num_patches; 95181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95196391a11375de5e2bb1eb8481e54619761dc65d9fTobias Klauser num_patches = ARRAY_SIZE(patches); 95201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last_patch = &patches[num_patches]; 95211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_patch = *start_patch; 95221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (cur_patch < last_patch && start_instr == cur_patch->begin) { 95241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cur_patch->patch_func(ahd) == 0) { 95261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start rejecting code */ 95281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *skip_addr = start_instr + cur_patch->skip_instr; 95291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_patch += cur_patch->skip_patch; 95301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 95311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Accepted this patch. Advance to the next 95321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * one and wait for our intruction pointer to 95331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hit this point. 95341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 95351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_patch++; 95361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 95371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 95381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *start_patch = cur_patch; 95401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (start_instr < *skip_addr) 95411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Still skipping */ 95421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 95431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (1); 95451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 95461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int 95481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_resolve_seqaddr(struct ahd_softc *ahd, u_int address) 95491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9550980b306a297725d4f25c779ca15086de757acadfDenys Vlasenko const struct patch *cur_patch; 95511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int address_offset; 95521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int skip_addr; 95531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int i; 95541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds address_offset = 0; 95561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_patch = patches; 95571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_addr = 0; 95581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < address;) { 95601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_check_patch(ahd, &cur_patch, i, &skip_addr); 95621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skip_addr > i) { 95641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int end_addr; 95651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95666d07cb71fdacc710fd9816cddb5c2df0f7bd96b4Amol Lad end_addr = min(address, skip_addr); 95671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds address_offset += end_addr - i; 95681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = skip_addr; 95691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 95701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i++; 95711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 95721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 95731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (address - address_offset); 95741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 95751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 95771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_download_instr(struct ahd_softc *ahd, u_int instrptr, uint8_t *dconsts) 95781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 95791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds union ins_formats instr; 95801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ins_format1 *fmt1_ins; 95811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ins_format3 *fmt3_ins; 95821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int opcode; 95831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 95851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The firmware is always compiled into a little endian format. 95861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 95871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds instr.integer = ahd_le32toh(*(uint32_t*)&seqprog[instrptr * 4]); 95881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fmt1_ins = &instr.format1; 95901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fmt3_ins = NULL; 95911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Pull the opcode */ 95931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds opcode = instr.format1.opcode; 95941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (opcode) { 95951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AIC_OP_JMP: 95961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AIC_OP_JC: 95971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AIC_OP_JNC: 95981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AIC_OP_CALL: 95991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AIC_OP_JNE: 96001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AIC_OP_JNZ: 96011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AIC_OP_JE: 96021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AIC_OP_JZ: 96031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 96041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fmt3_ins = &instr.format3; 96051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fmt3_ins->address = ahd_resolve_seqaddr(ahd, fmt3_ins->address); 96061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 96071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 96081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AIC_OP_OR: 96091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AIC_OP_AND: 96101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AIC_OP_XOR: 96111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AIC_OP_ADD: 96121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AIC_OP_ADC: 96131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AIC_OP_BMOV: 96141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fmt1_ins->parity != 0) { 96151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fmt1_ins->immediate = dconsts[fmt1_ins->immediate]; 96161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 96171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fmt1_ins->parity = 0; 96181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 96191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AIC_OP_ROL: 96201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 96211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, count; 96221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 96231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Calculate odd parity for the instruction */ 96241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0, count = 0; i < 31; i++) { 96251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t mask; 96261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 96271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask = 0x01 << i; 96281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((instr.integer & mask) != 0) 96291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count++; 96301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 96311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((count & 0x01) == 0) 96321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds instr.format1.parity = 1; 96331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 96341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The sequencer is a little endian cpu */ 96351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds instr.integer = ahd_htole32(instr.integer); 96361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outsb(ahd, SEQRAM, instr.bytes, 4); 96371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 96381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 96391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 96401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("Unknown opcode encountered in seq program"); 96411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 96421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 96431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 96441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 96451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 96461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_probe_stack_size(struct ahd_softc *ahd) 96471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 96481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int last_probe; 96491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 96501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last_probe = 0; 96511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 96521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 96531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 96541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 96551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We avoid using 0 as a pattern to avoid 96561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * confusion if the stack implementation 96571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "back-fills" with zeros when "poping' 96581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * entries. 96591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 96601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 1; i <= last_probe+1; i++) { 96611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, STACK, i & 0xFF); 96621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, STACK, (i >> 8) & 0xFF); 96631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 96641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 96651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Verify */ 96661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = last_probe+1; i > 0; i--) { 96671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int stack_entry; 96681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 96691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stack_entry = ahd_inb(ahd, STACK) 96701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds |(ahd_inb(ahd, STACK) << 8); 96711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (stack_entry != i) 96721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto sized; 96731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 96741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last_probe++; 96751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 96761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssized: 96771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (last_probe); 96781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 96791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 96801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 9681d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkoahd_print_register(const ahd_reg_parse_entry_t *table, u_int num_entries, 96821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *name, u_int address, u_int value, 96831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int *cur_column, u_int wrap_point) 96841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 96851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int printed; 96861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int printed_mask; 96871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 96881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cur_column != NULL && *cur_column >= wrap_point) { 968948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\n"); 96901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *cur_column = 0; 96911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 969248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printed = printk("%s[0x%x]", name, value); 96931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (table == NULL) { 969448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printed += printk(" "); 96951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *cur_column += printed; 96961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (printed); 96971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 96981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printed_mask = 0; 96991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (printed_mask != 0xFF) { 97001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int entry; 97011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 97021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (entry = 0; entry < num_entries; entry++) { 97031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((value & table[entry].mask) 97041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds != table[entry].value) 97051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || ((printed_mask & table[entry].mask) 97061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds == table[entry].mask)) 97071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 97081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 970948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printed += printk("%s%s", 97101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printed_mask == 0 ? ":(" : "|", 97111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds table[entry].name); 97121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printed_mask |= table[entry].mask; 97131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 97141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 97151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 97161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (entry >= num_entries) 97171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 97181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 97191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (printed_mask != 0) 972048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printed += printk(") "); 97211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 972248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printed += printk(" "); 97231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cur_column != NULL) 97241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *cur_column += printed; 97251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (printed); 97261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 97271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 97281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 97291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_dump_card_state(struct ahd_softc *ahd) 97301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 97311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 97321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mode_state saved_modes; 97331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int dffstat; 97341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int paused; 97351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scb_index; 97361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int saved_scb_index; 97371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int cur_col; 97381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 97391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 97401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_is_paused(ahd)) { 97411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds paused = 1; 97421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 97431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds paused = 0; 97441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pause(ahd); 97451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 97461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_modes = ahd_save_modes(ahd); 97471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 974848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n" 97491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%s: Dumping Card State at program address 0x%x Mode 0x%x\n", 97501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), 9751ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke ahd_inw(ahd, CURADDR), 97521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_build_mode_state(ahd, ahd->saved_src_mode, 97531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->saved_dst_mode)); 97541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (paused) 975548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Card was paused\n"); 97561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 97571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_check_cmdcmpltqueues(ahd)) 975848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Completions are pending\n"); 97591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 97601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 97611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Mode independent registers. 97621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 97631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_col = 0; 976453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_intstat_print(ahd_inb(ahd, INTSTAT), &cur_col, 50); 976553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_seloid_print(ahd_inb(ahd, SELOID), &cur_col, 50); 976653467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_selid_print(ahd_inb(ahd, SELID), &cur_col, 50); 97671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_hs_mailbox_print(ahd_inb(ahd, LOCAL_HS_MAILBOX), &cur_col, 50); 97681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_intctl_print(ahd_inb(ahd, INTCTL), &cur_col, 50); 97691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_seqintstat_print(ahd_inb(ahd, SEQINTSTAT), &cur_col, 50); 97701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_saved_mode_print(ahd_inb(ahd, SAVED_MODE), &cur_col, 50); 97711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dffstat_print(ahd_inb(ahd, DFFSTAT), &cur_col, 50); 97721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_scsisigi_print(ahd_inb(ahd, SCSISIGI), &cur_col, 50); 97731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_scsiphase_print(ahd_inb(ahd, SCSIPHASE), &cur_col, 50); 97741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_scsibus_print(ahd_inb(ahd, SCSIBUS), &cur_col, 50); 97751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lastphase_print(ahd_inb(ahd, LASTPHASE), &cur_col, 50); 97761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_scsiseq0_print(ahd_inb(ahd, SCSISEQ0), &cur_col, 50); 97771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_scsiseq1_print(ahd_inb(ahd, SCSISEQ1), &cur_col, 50); 97781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_seqctl0_print(ahd_inb(ahd, SEQCTL0), &cur_col, 50); 97791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_seqintctl_print(ahd_inb(ahd, SEQINTCTL), &cur_col, 50); 97801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_seq_flags_print(ahd_inb(ahd, SEQ_FLAGS), &cur_col, 50); 97811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_seq_flags2_print(ahd_inb(ahd, SEQ_FLAGS2), &cur_col, 50); 978253467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_qfreeze_count_print(ahd_inw(ahd, QFREEZE_COUNT), &cur_col, 50); 978353467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_kernel_qfreeze_count_print(ahd_inw(ahd, KERNEL_QFREEZE_COUNT), 978453467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke &cur_col, 50); 978553467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_mk_message_scb_print(ahd_inw(ahd, MK_MESSAGE_SCB), &cur_col, 50); 978653467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_mk_message_scsiid_print(ahd_inb(ahd, MK_MESSAGE_SCSIID), 978753467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke &cur_col, 50); 97881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_sstat0_print(ahd_inb(ahd, SSTAT0), &cur_col, 50); 97891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_sstat1_print(ahd_inb(ahd, SSTAT1), &cur_col, 50); 97901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_sstat2_print(ahd_inb(ahd, SSTAT2), &cur_col, 50); 97911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_sstat3_print(ahd_inb(ahd, SSTAT3), &cur_col, 50); 97921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_perrdiag_print(ahd_inb(ahd, PERRDIAG), &cur_col, 50); 97931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_simode1_print(ahd_inb(ahd, SIMODE1), &cur_col, 50); 97941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lqistat0_print(ahd_inb(ahd, LQISTAT0), &cur_col, 50); 97951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lqistat1_print(ahd_inb(ahd, LQISTAT1), &cur_col, 50); 97961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lqistat2_print(ahd_inb(ahd, LQISTAT2), &cur_col, 50); 97971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lqostat0_print(ahd_inb(ahd, LQOSTAT0), &cur_col, 50); 97981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lqostat1_print(ahd_inb(ahd, LQOSTAT1), &cur_col, 50); 97991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lqostat2_print(ahd_inb(ahd, LQOSTAT2), &cur_col, 50); 980048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\n"); 980148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\nSCB Count = %d CMDS_PENDING = %d LASTSCB 0x%x " 98021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "CURRSCB 0x%x NEXTSCB 0x%x\n", 98031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->scb_data.numscbs, ahd_inw(ahd, CMDS_PENDING), 98041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inw(ahd, LASTSCB), ahd_inw(ahd, CURRSCB), 98051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inw(ahd, NEXTSCB)); 98061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_col = 0; 98071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* QINFIFO */ 98081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_search_qinfifo(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS, 98091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CAM_LUN_WILDCARD, SCB_LIST_NULL, 98101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ROLE_UNKNOWN, /*status*/0, SEARCH_PRINT); 98111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_scb_index = ahd_get_scbptr(ahd); 981248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Pending list:"); 98131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = 0; 98141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) { 98151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i++ > AHD_SCB_MAX) 98161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 981748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg cur_col = printk("\n%3d FIFO_USE[0x%x] ", SCB_GET_TAG(scb), 98181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT)); 98191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, SCB_GET_TAG(scb)); 98201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_scb_control_print(ahd_inb_scbram(ahd, SCB_CONTROL), 98211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &cur_col, 60); 98221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_scb_scsiid_print(ahd_inb_scbram(ahd, SCB_SCSIID), 98231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &cur_col, 60); 98241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 982548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\nTotal %d\n", i); 98261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 982748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Kernel Free SCB list: "); 98281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = 0; 98291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) { 98301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *list_scb; 98311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 98321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_scb = scb; 98331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 983448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%d ", SCB_GET_TAG(list_scb)); 98351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_scb = LIST_NEXT(list_scb, collision_links); 98361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (list_scb && i++ < AHD_SCB_MAX); 98371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 98381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 98391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_FOREACH(scb, &ahd->scb_data.any_dev_free_scb_list, links.le) { 98401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i++ > AHD_SCB_MAX) 98411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 984248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%d ", SCB_GET_TAG(scb)); 98431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 984448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\n"); 98451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 984648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Sequencer Complete DMA-inprog list: "); 98471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_index = ahd_inw(ahd, COMPLETE_SCB_DMAINPROG_HEAD); 98481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = 0; 98491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { 98501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, scb_index); 985148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%d ", scb_index); 98521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); 98531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 985448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\n"); 98551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 985648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Sequencer Complete list: "); 98571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_index = ahd_inw(ahd, COMPLETE_SCB_HEAD); 98581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = 0; 98591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { 98601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, scb_index); 986148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%d ", scb_index); 98621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); 98631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 986448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\n"); 98651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 98661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 986748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Sequencer DMA-Up and Complete list: "); 98681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_index = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD); 98691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = 0; 98701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { 98711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, scb_index); 987248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%d ", scb_index); 98731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); 98741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 987548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\n"); 987648813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Sequencer On QFreeze and Complete list: "); 987711668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke scb_index = ahd_inw(ahd, COMPLETE_ON_QFREEZE_HEAD); 987811668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke i = 0; 987911668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { 988011668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke ahd_set_scbptr(ahd, scb_index); 988148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%d ", scb_index); 988211668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); 988311668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke } 988448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\n"); 98851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, saved_scb_index); 98861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dffstat = ahd_inb(ahd, DFFSTAT); 98871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 2; i++) { 98881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 98891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *fifo_scb; 98901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 98911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int fifo_scbptr; 98921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 98931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_DFF0 + i, AHD_MODE_DFF0 + i); 98941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_scbptr = ahd_get_scbptr(ahd); 989548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\n\n%s: FIFO%d %s, LONGJMP == 0x%x, SCB 0x%x\n", 98961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), i, 98971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (dffstat & (FIFO0FREE << i)) ? "Free" : "Active", 98981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inw(ahd, LONGJMP_ADDR), fifo_scbptr); 98991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_col = 0; 99001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_seqimode_print(ahd_inb(ahd, SEQIMODE), &cur_col, 50); 99011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_seqintsrc_print(ahd_inb(ahd, SEQINTSRC), &cur_col, 50); 99021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dfcntrl_print(ahd_inb(ahd, DFCNTRL), &cur_col, 50); 99031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dfstatus_print(ahd_inb(ahd, DFSTATUS), &cur_col, 50); 99041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_sg_cache_shadow_print(ahd_inb(ahd, SG_CACHE_SHADOW), 99051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &cur_col, 50); 99061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_sg_state_print(ahd_inb(ahd, SG_STATE), &cur_col, 50); 99071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dffsxfrctl_print(ahd_inb(ahd, DFFSXFRCTL), &cur_col, 50); 99081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_soffcnt_print(ahd_inb(ahd, SOFFCNT), &cur_col, 50); 99091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mdffstat_print(ahd_inb(ahd, MDFFSTAT), &cur_col, 50); 99101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cur_col > 50) { 991148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\n"); 99121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_col = 0; 99131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 991448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg cur_col += printk("SHADDR = 0x%x%x, SHCNT = 0x%x ", 99151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inl(ahd, SHADDR+4), 99161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inl(ahd, SHADDR), 99171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ahd_inb(ahd, SHCNT) 99181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | (ahd_inb(ahd, SHCNT + 1) << 8) 99191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | (ahd_inb(ahd, SHCNT + 2) << 16))); 99201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cur_col > 50) { 992148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\n"); 99221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_col = 0; 99231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 992448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg cur_col += printk("HADDR = 0x%x%x, HCNT = 0x%x ", 99251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inl(ahd, HADDR+4), 99261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inl(ahd, HADDR), 99271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ahd_inb(ahd, HCNT) 99281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | (ahd_inb(ahd, HCNT + 1) << 8) 99291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | (ahd_inb(ahd, HCNT + 2) << 16))); 99301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_ccsgctl_print(ahd_inb(ahd, CCSGCTL), &cur_col, 50); 99311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 99321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_SG) != 0) { 99331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fifo_scb = ahd_lookup_scb(ahd, fifo_scbptr); 99341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fifo_scb != NULL) 99351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dump_sglist(fifo_scb); 99361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 99371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 99381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 993948813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\nLQIN: "); 99401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 20; i++) 994148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("0x%x ", ahd_inb(ahd, LQIN + i)); 994248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\n"); 99431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 994448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: LQISTATE = 0x%x, LQOSTATE = 0x%x, OPTIONMODE = 0x%x\n", 99451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), ahd_inb(ahd, LQISTATE), ahd_inb(ahd, LQOSTATE), 99461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, OPTIONMODE)); 994748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: OS_SPACE_CNT = 0x%x MAXCMDCNT = 0x%x\n", 99481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), ahd_inb(ahd, OS_SPACE_CNT), 99491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, MAXCMDCNT)); 995048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: SAVED_SCSIID = 0x%x SAVED_LUN = 0x%x\n", 995153467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_name(ahd), ahd_inb(ahd, SAVED_SCSIID), 995253467e636b7beb350c307cc88323aae4676577f2Hannes Reinecke ahd_inb(ahd, SAVED_LUN)); 99531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_simode0_print(ahd_inb(ahd, SIMODE0), &cur_col, 50); 995448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\n"); 99551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); 99561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_col = 0; 99571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_ccscbctl_print(ahd_inb(ahd, CCSCBCTL), &cur_col, 50); 995848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\n"); 99591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); 996048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: REG0 == 0x%x, SINDEX = 0x%x, DINDEX = 0x%x\n", 99611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), ahd_inw(ahd, REG0), ahd_inw(ahd, SINDEX), 99621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inw(ahd, DINDEX)); 996348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%s: SCBPTR == 0x%x, SCB_NEXT == 0x%x, SCB_NEXT2 == 0x%x\n", 99641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_name(ahd), ahd_get_scbptr(ahd), 99651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inw_scbram(ahd, SCB_NEXT), 99661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inw_scbram(ahd, SCB_NEXT2)); 996748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("CDB %x %x %x %x %x %x\n", 99681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_CDB_STORE), 99691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_CDB_STORE+1), 99701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_CDB_STORE+2), 99711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_CDB_STORE+3), 99721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_CDB_STORE+4), 99731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_CDB_STORE+5)); 997448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("STACK:"); 99751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ahd->stack_size; i++) { 99761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->saved_stack[i] = 99771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb(ahd, STACK)|(ahd_inb(ahd, STACK) << 8); 997848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk(" 0x%x", ahd->saved_stack[i]); 99791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 99801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = ahd->stack_size-1; i >= 0; i--) { 99811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, STACK, ahd->saved_stack[i] & 0xFF); 99821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, STACK, (ahd->saved_stack[i] >> 8) & 0xFF); 99831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 998448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n"); 99851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restore_modes(ahd, saved_modes); 99861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (paused == 0) 99871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 99881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 99891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9990289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk#if 0 99911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 99921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_dump_scbs(struct ahd_softc *ahd) 99931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 99941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_mode_state saved_modes; 99951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int saved_scb_index; 99961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 99971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 99981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_modes = ahd_save_modes(ahd); 99991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 100001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_scb_index = ahd_get_scbptr(ahd); 100011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < AHD_SCB_MAX; i++) { 100021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, i); 1000348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("%3d", i); 1000448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("(CTRL 0x%x ID 0x%x N 0x%x N2 0x%x SG 0x%x, RSG 0x%x)\n", 100051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_CONTROL), 100061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inb_scbram(ahd, SCB_SCSIID), 100071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inw_scbram(ahd, SCB_NEXT), 100081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inw_scbram(ahd, SCB_NEXT2), 100091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inl_scbram(ahd, SCB_SGPTR), 100101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR)); 100111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1001248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("\n"); 100131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_set_scbptr(ahd, saved_scb_index); 100141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restore_modes(ahd, saved_modes); 100151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10016289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk#endif /* 0 */ 100171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**************************** Flexport Logic **********************************/ 100191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 100201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read count 16bit words from 16bit word address start_addr from the 100211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SEEPROM attached to the controller, into buf, using the controller's 100221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SEEPROM reading state machine. Optionally treat the data as a byte 100231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stream in terms of byte order. 100241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 100251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 100261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_read_seeprom(struct ahd_softc *ahd, uint16_t *buf, 100271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int start_addr, u_int count, int bytestream) 100281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 100291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int cur_addr; 100301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int end_addr; 100311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 100321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 100341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we never make it through the loop even once, 100351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we were passed invalid arguments. 100361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 100371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = EINVAL; 100381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 100391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end_addr = start_addr + count; 100401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (cur_addr = start_addr; cur_addr < end_addr; cur_addr++) { 100411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEEADR, cur_addr); 100431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEECTL, SEEOP_READ | SEESTART); 100441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = ahd_wait_seeprom(ahd); 100461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) 100471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 100481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bytestream != 0) { 100491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t *bytestream_ptr; 100501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bytestream_ptr = (uint8_t *)buf; 100521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *bytestream_ptr++ = ahd_inb(ahd, SEEDAT); 100531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *bytestream_ptr = ahd_inb(ahd, SEEDAT+1); 100541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 100551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 100561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ahd_inw() already handles machine byte order. 100571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 100581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buf = ahd_inw(ahd, SEEDAT); 100591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 100601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf++; 100611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 100621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (error); 100631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 100641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 100661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write count 16bit words from buf, into SEEPROM attache to the 100671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * controller starting at 16bit word address start_addr, using the 100681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * controller's SEEPROM writing state machine. 100691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 100701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 100711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_write_seeprom(struct ahd_softc *ahd, uint16_t *buf, 100721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int start_addr, u_int count) 100731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 100741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int cur_addr; 100751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int end_addr; 100761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 100771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 100781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 100801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = ENOENT; 100811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Place the chip into write-enable mode */ 100831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEEADR, SEEOP_EWEN_ADDR); 100841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEECTL, SEEOP_EWEN | SEESTART); 100851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = ahd_wait_seeprom(ahd); 100861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) 100871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (error); 100881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1009025985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Write the data. If we don't get through the loop at 100911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * least once, the arguments were invalid. 100921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 100931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = EINVAL; 100941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end_addr = start_addr + count; 100951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (cur_addr = start_addr; cur_addr < end_addr; cur_addr++) { 100961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outw(ahd, SEEDAT, *buf++); 100971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEEADR, cur_addr); 100981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEECTL, SEEOP_WRITE | SEESTART); 100991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = ahd_wait_seeprom(ahd); 101011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 101021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 101031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 101041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 101061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable writes. 101071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 101081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEEADR, SEEOP_EWDS_ADDR); 101091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SEECTL, SEEOP_EWDS | SEESTART); 101101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = ahd_wait_seeprom(ahd); 101111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) 101121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (error); 101131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (retval); 101141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 101151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 101171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait ~100us for the serial eeprom to satisfy our request. 101181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10119289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic int 101201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_wait_seeprom(struct ahd_softc *ahd) 101211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 101221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cnt; 101231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1012411668bb673c41ec169a85d0b52c538a1c11d29e1Hannes Reinecke cnt = 5000; 101251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((ahd_inb(ahd, SEESTAT) & (SEEARBACK|SEEBUSY)) != 0 && --cnt) 101261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_delay(5); 101271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cnt == 0) 101291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (ETIMEDOUT); 101301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 101311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 101321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 101341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Validate the two checksums in the per_channel 101351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * vital product data struct. 101361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10137289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic int 101381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_verify_vpd_cksum(struct vpd_config *vpd) 101391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 101401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 101411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int maxaddr; 101421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t checksum; 101431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t *vpdarray; 101441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vpdarray = (uint8_t *)vpd; 101461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxaddr = offsetof(struct vpd_config, vpd_checksum); 101471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds checksum = 0; 101481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = offsetof(struct vpd_config, resource_type); i < maxaddr; i++) 101491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds checksum = checksum + vpdarray[i]; 101501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (checksum == 0 101511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || (-checksum & 0xFF) != vpd->vpd_checksum) 101521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 101531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds checksum = 0; 101551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxaddr = offsetof(struct vpd_config, checksum); 101561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = offsetof(struct vpd_config, default_target_flags); 101571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i < maxaddr; i++) 101581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds checksum = checksum + vpdarray[i]; 101591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (checksum == 0 101601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || (-checksum & 0xFF) != vpd->checksum) 101611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 101621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (1); 101631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 101641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 101661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_verify_cksum(struct seeprom_config *sc) 101671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 101681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 101691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int maxaddr; 101701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t checksum; 101711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint16_t *scarray; 101721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxaddr = (sizeof(*sc)/2) - 1; 101741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds checksum = 0; 101751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scarray = (uint16_t *)sc; 101761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < maxaddr; i++) 101781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds checksum = checksum + scarray[i]; 101791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (checksum == 0 101801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || (checksum & 0xFFFF) != sc->checksum) { 101811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 101821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 101831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (1); 101841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 101851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 101861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 101881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_acquire_seeprom(struct ahd_softc *ahd) 101891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 101901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 101911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We should be able to determine the SEEPROM type 101921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from the flexport logic, but unfortunately not 101931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * all implementations have this logic and there is 101941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * no programatic method for determining if the logic 101951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is present. 101961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 101971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (1); 101981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 101991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t seetype; 102001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 102011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 102021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = ahd_read_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, &seetype); 102031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error != 0 102041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || ((seetype & FLX_ROMSTAT_SEECFG) == FLX_ROMSTAT_SEE_NONE)) 102051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 102061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (1); 102071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 102081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 102091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 102101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 102111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_release_seeprom(struct ahd_softc *ahd) 102121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 102131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Currently a no-op */ 102141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 102151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10216289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk/* 10217289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk * Wait at most 2 seconds for flexport arbitration to succeed. 10218289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk */ 10219289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkstatic int 10220289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunkahd_wait_flexport(struct ahd_softc *ahd) 10221289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk{ 10222289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk int cnt; 10223289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 10224289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 10225289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk cnt = 1000000 * 2 / 5; 10226289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk while ((ahd_inb(ahd, BRDCTL) & FLXARBACK) == 0 && --cnt) 10227289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk ahd_delay(5); 10228289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 10229289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk if (cnt == 0) 10230289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk return (ETIMEDOUT); 10231289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk return (0); 10232289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk} 10233289fe5b1f99c5e61ed32796cbed0a1ecc3589041Adrian Bunk 102341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 102351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_write_flexport(struct ahd_softc *ahd, u_int addr, u_int value) 102361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 102371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 102381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 102391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 102401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (addr > 7) 102411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("ahd_write_flexport: address out of range"); 102421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, BRDCTL, BRDEN|(addr << 3)); 102431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = ahd_wait_flexport(ahd); 102441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error != 0) 102451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (error); 102461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, BRDDAT, value); 102471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_flush_device_writes(ahd); 102481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, BRDCTL, BRDSTB|BRDEN|(addr << 3)); 102491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_flush_device_writes(ahd); 102501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, BRDCTL, BRDEN|(addr << 3)); 102511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_flush_device_writes(ahd); 102521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, BRDCTL, 0); 102531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_flush_device_writes(ahd); 102541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 102551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 102561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 102571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 102581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_read_flexport(struct ahd_softc *ahd, u_int addr, uint8_t *value) 102591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 102601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 102611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 102621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); 102631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (addr > 7) 102641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("ahd_read_flexport: address out of range"); 102651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, BRDCTL, BRDRW|BRDEN|(addr << 3)); 102661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = ahd_wait_flexport(ahd); 102671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error != 0) 102681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (error); 102691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *value = ahd_inb(ahd, BRDDAT); 102701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, BRDCTL, 0); 102711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_flush_device_writes(ahd); 102721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 102731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 102741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 102751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************* Target Mode ****************************************/ 102761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_TARGET_MODE 102771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscam_status 102781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_find_tmode_devs(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb, 102791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate **tstate, 102801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_lstate **lstate, 102811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int notfound_failure) 102821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 102831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 102841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_TARGETMODE) == 0) 102851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (CAM_REQ_INVALID); 102861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 102871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 102881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle the 'black hole' device that sucks up 102891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * requests to unattached luns on enabled targets. 102901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 102911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD 102921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) { 102931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *tstate = NULL; 102941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *lstate = ahd->black_hole; 102951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 102961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int max_id; 102971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 102982b89dad0c7e3b03d45d9674ee9a7b49670df098eHannes Reinecke max_id = (ahd->features & AHD_WIDE) ? 16 : 8; 102992b89dad0c7e3b03d45d9674ee9a7b49670df098eHannes Reinecke if (ccb->ccb_h.target_id >= max_id) 103001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (CAM_TID_INVALID); 103011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 103021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ccb->ccb_h.target_lun >= AHD_NUM_LUNS) 103031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (CAM_LUN_INVALID); 103041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 103051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *tstate = ahd->enabled_targets[ccb->ccb_h.target_id]; 103061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *lstate = NULL; 103071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*tstate != NULL) 103081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *lstate = 103091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (*tstate)->enabled_luns[ccb->ccb_h.target_lun]; 103101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 103111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 103121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (notfound_failure != 0 && *lstate == NULL) 103131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (CAM_PATH_INVALID); 103141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 103151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (CAM_REQ_CMP); 103161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 103171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 103181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 103191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) 103201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 103211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if NOT_YET 103221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 103231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_lstate *lstate; 103241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ccb_en_lun *cel; 103251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cam_status status; 103261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int target; 103271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int lun; 103281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int target_mask; 103291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_long s; 103301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char channel; 103311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 103321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = ahd_find_tmode_devs(ahd, sim, ccb, &tstate, &lstate, 103331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*notfound_failure*/FALSE); 103341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 103351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status != CAM_REQ_CMP) { 103361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccb->ccb_h.status = status; 103371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 103381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 103391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 103401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_MULTIROLE) != 0) { 103411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int our_id; 103421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 103431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds our_id = ahd->our_id; 103441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ccb->ccb_h.target_id != our_id) { 103451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_MULTI_TID) != 0 103461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ahd->flags & AHD_INITIATORROLE) != 0) { 103471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 103481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Only allow additional targets if 103491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the initiator role is disabled. 103501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The hardware cannot handle a re-select-in 103511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on the initiator id during a re-select-out 103521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on a different target id. 103531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 103541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = CAM_TID_INVALID; 103551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((ahd->flags & AHD_INITIATORROLE) != 0 103561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || ahd->enabled_luns > 0) { 103571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 103581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Only allow our target id to change 103591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if the initiator role is not configured 103601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and there are no enabled luns which 103611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are attached to the currently registered 103621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scsi id. 103631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 103641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = CAM_TID_INVALID; 103651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 103661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 103671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 103681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 103691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status != CAM_REQ_CMP) { 103701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccb->ccb_h.status = status; 103711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 103721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 103731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 103741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 103751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We now have an id that is valid. 103761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we aren't in target mode, switch modes. 103771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 103781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->flags & AHD_TARGETROLE) == 0 103791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) { 103801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_long s; 103811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1038248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Configuring Target Mode\n"); 103831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lock(ahd, &s); 103841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (LIST_FIRST(&ahd->pending_scbs) != NULL) { 103851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccb->ccb_h.status = CAM_BUSY; 103861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unlock(ahd, &s); 103871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 103881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 103891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags |= AHD_TARGETROLE; 103901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_MULTIROLE) == 0) 103911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags &= ~AHD_INITIATORROLE; 103921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pause(ahd); 103931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_loadseq(ahd); 103941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restart(ahd); 103951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unlock(ahd, &s); 103961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 103971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cel = &ccb->cel; 103981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target = ccb->ccb_h.target_id; 103991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lun = ccb->ccb_h.target_lun; 104001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds channel = SIM_CHANNEL(ahd, sim); 104011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target_mask = 0x01 << target; 104021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (channel == 'B') 104031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target_mask <<= 8; 104041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 104051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cel->enable != 0) { 104061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scsiseq1; 104071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 104081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Are we already enabled?? */ 104091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lstate != NULL) { 104101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_print_path(ccb->ccb_h.path); 1041148813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Lun already enabled\n"); 104121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; 104131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 104141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 104151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 104161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cel->grp6_len != 0 104171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || cel->grp7_len != 0) { 104181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 104191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Don't (yet?) support vendor 104201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * specific commands. 104211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 104221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccb->ccb_h.status = CAM_REQ_INVALID; 1042348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Non-zero Group Codes\n"); 104241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 104251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 104261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 104271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 104281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Seems to be okay. 104291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Setup our data structures. 104301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 104311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (target != CAM_TARGET_WILDCARD && tstate == NULL) { 104321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tstate = ahd_alloc_tstate(ahd, target, channel); 104331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tstate == NULL) { 104341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_print_path(ccb->ccb_h.path); 1043548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Couldn't allocate tstate\n"); 104361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 104371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 104381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 104391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1044048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg lstate = kmalloc(sizeof(*lstate), GFP_ATOMIC); 104411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lstate == NULL) { 104421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_print_path(ccb->ccb_h.path); 1044348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Couldn't allocate lstate\n"); 104441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 104451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 104461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 104471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(lstate, 0, sizeof(*lstate)); 104481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = xpt_create_path(&lstate->path, /*periph*/NULL, 104491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_path_path_id(ccb->ccb_h.path), 104501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_path_target_id(ccb->ccb_h.path), 104511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_path_lun_id(ccb->ccb_h.path)); 104521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status != CAM_REQ_CMP) { 1045348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(lstate); 104541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_print_path(ccb->ccb_h.path); 1045548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Couldn't allocate path\n"); 104561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 104571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 104581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 104591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SLIST_INIT(&lstate->accept_tios); 104601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SLIST_INIT(&lstate->immed_notifies); 104611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lock(ahd, &s); 104621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pause(ahd); 104631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (target != CAM_TARGET_WILDCARD) { 104641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tstate->enabled_luns[lun] = lstate; 104651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->enabled_luns++; 104661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 104671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_MULTI_TID) != 0) { 104681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int targid_mask; 104691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10470ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke targid_mask = ahd_inw(ahd, TARGID); 104711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds targid_mask |= target_mask; 10472ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke ahd_outw(ahd, TARGID, targid_mask); 104731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_update_scsiid(ahd, targid_mask); 104741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 104751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int our_id; 104761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char channel; 104771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 104781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds channel = SIM_CHANNEL(ahd, sim); 104791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds our_id = SIM_SCSI_ID(ahd, sim); 104801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 104811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 104821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This can only happen if selections 104831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are not enabled 104841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 104851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (target != our_id) { 104861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int sblkctl; 104871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char cur_channel; 104881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int swap; 104891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 104901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sblkctl = ahd_inb(ahd, SBLKCTL); 104911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_channel = (sblkctl & SELBUSB) 104921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? 'B' : 'A'; 104931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_TWIN) == 0) 104941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_channel = 'A'; 104951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds swap = cur_channel != channel; 104961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->our_id = target; 104971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 104981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (swap) 104991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SBLKCTL, 105001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sblkctl ^ SELBUSB); 105011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 105021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSIID, target); 105031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 105041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (swap) 105051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SBLKCTL, sblkctl); 105061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 105071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 105081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 105091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->black_hole = lstate; 105101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allow select-in operations */ 105111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->black_hole != NULL && ahd->enabled_luns > 0) { 105121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsiseq1 = ahd_inb(ahd, SCSISEQ_TEMPLATE); 105131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsiseq1 |= ENSELI; 105141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ_TEMPLATE, scsiseq1); 105151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsiseq1 = ahd_inb(ahd, SCSISEQ1); 105161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsiseq1 |= ENSELI; 105171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ1, scsiseq1); 105181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 105191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 105201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unlock(ahd, &s); 105211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccb->ccb_h.status = CAM_REQ_CMP; 105221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_print_path(ccb->ccb_h.path); 1052348813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Lun now enabled for target mode\n"); 105241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 105251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scb *scb; 105261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, empty; 105271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 105281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lstate == NULL) { 105291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccb->ccb_h.status = CAM_LUN_INVALID; 105301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 105311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 105321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 105331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_lock(ahd, &s); 105341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 105351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccb->ccb_h.status = CAM_REQ_CMP; 105361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) { 105371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ccb_hdr *ccbh; 105381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 105391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccbh = &scb->io_ctx->ccb_h; 105401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ccbh->func_code == XPT_CONT_TARGET_IO 105411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){ 1054248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("CTIO pending\n"); 105431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccb->ccb_h.status = CAM_REQ_INVALID; 105441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unlock(ahd, &s); 105451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 105461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 105471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 105481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 105491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (SLIST_FIRST(&lstate->accept_tios) != NULL) { 1055048813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("ATIOs pending\n"); 105511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccb->ccb_h.status = CAM_REQ_INVALID; 105521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 105531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 105541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (SLIST_FIRST(&lstate->immed_notifies) != NULL) { 1055548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("INOTs pending\n"); 105561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccb->ccb_h.status = CAM_REQ_INVALID; 105571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 105581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 105591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ccb->ccb_h.status != CAM_REQ_CMP) { 105601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unlock(ahd, &s); 105611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 105621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 105631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 105641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_print_path(ccb->ccb_h.path); 1056548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Target mode disabled\n"); 105661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_free_path(lstate->path); 1056748813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg kfree(lstate); 105681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 105691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pause(ahd); 105701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Can we clean up the target too? */ 105711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (target != CAM_TARGET_WILDCARD) { 105721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tstate->enabled_luns[lun] = NULL; 105731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->enabled_luns--; 105741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (empty = 1, i = 0; i < 8; i++) 105751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tstate->enabled_luns[i] != NULL) { 105761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds empty = 0; 105771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 105781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 105791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 105801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (empty) { 105811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_free_tstate(ahd, target, channel, 105821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*force*/FALSE); 105831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->features & AHD_MULTI_TID) { 105841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int targid_mask; 105851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10586ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke targid_mask = ahd_inw(ahd, TARGID); 105871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds targid_mask &= ~target_mask; 10588ba62cd2d01e401faa5d5a25fa8e990d0b1a1996aHannes Reinecke ahd_outw(ahd, TARGID, targid_mask); 105891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_update_scsiid(ahd, targid_mask); 105901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 105911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 105921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 105931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 105941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->black_hole = NULL; 105951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 105961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 105971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We can't allow selections without 105981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * our black hole device. 105991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 106001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds empty = TRUE; 106011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 106021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd->enabled_luns == 0) { 106031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Disallow select-in */ 106041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scsiseq1; 106051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 106061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsiseq1 = ahd_inb(ahd, SCSISEQ_TEMPLATE); 106071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsiseq1 &= ~ENSELI; 106081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ_TEMPLATE, scsiseq1); 106091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsiseq1 = ahd_inb(ahd, SCSISEQ1); 106101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsiseq1 &= ~ENSELI; 106111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSISEQ1, scsiseq1); 106121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 106131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_MULTIROLE) == 0) { 1061448813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Configuring Initiator Mode\n"); 106151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags &= ~AHD_TARGETROLE; 106161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags |= AHD_INITIATORROLE; 106171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_pause(ahd); 106181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_loadseq(ahd); 106191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_restart(ahd); 106201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 106211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unpaused. The extra unpause 106221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that follows is harmless. 106231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 106241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 106251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 106261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unpause(ahd); 106271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_unlock(ahd, &s); 106281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 106291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 106301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 106311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 106321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 106331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_update_scsiid(struct ahd_softc *ahd, u_int targid_mask) 106341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 106351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if NOT_YET 106361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scsiid_mask; 106371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int scsiid; 106381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 106391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_MULTI_TID) == 0) 106401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("ahd_update_scsiid called on non-multitid unit\n"); 106411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 106421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 106431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since we will rely on the TARGID mask 106441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for selection enables, ensure that OID 106451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in SCSIID is not set to some other ID 106461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that we don't want to allow selections on. 106471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 106481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_ULTRA2) != 0) 106491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsiid = ahd_inb(ahd, SCSIID_ULTRA2); 106501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 106511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsiid = ahd_inb(ahd, SCSIID); 106521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsiid_mask = 0x1 << (scsiid & OID); 106531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((targid_mask & scsiid_mask) == 0) { 106541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int our_id; 106551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 106561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ffs counts from 1 */ 106571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds our_id = ffs(targid_mask); 106581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (our_id == 0) 106591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds our_id = ahd->our_id; 106601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 106611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds our_id--; 106621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsiid &= TID; 106631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsiid |= our_id; 106641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 106651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->features & AHD_ULTRA2) != 0) 106661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSIID_ULTRA2, scsiid); 106671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 106681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, SCSIID, scsiid); 106691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 106701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 106711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10672d1d7b19d433188e94fc87cc7ca66363cd77a0bbaDenys Vlasenkostatic void 106731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_run_tqinfifo(struct ahd_softc *ahd, int paused) 106741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 106751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct target_cmd *cmd; 106761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 106771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_sync_tqinfifo(ahd, BUS_DMASYNC_POSTREAD); 106781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((cmd = &ahd->targetcmds[ahd->tqinfifonext])->cmd_valid != 0) { 106791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 106801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 106811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Only advance through the queue if we 106821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * have the resources to process the command. 106831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 106841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ahd_handle_target_cmd(ahd, cmd) != 0) 106851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 106861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 106871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->cmd_valid = 0; 106881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_dmamap_sync(ahd, ahd->shared_data_dmat, 1068966a0683e4620f087e41e79d4d2be6c5a06bb206bHannes Reinecke ahd->shared_data_map.dmamap, 106901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_targetcmd_offset(ahd, ahd->tqinfifonext), 106911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct target_cmd), 106921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUS_DMASYNC_PREREAD); 106931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->tqinfifonext++; 106941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 106951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 106961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Lazily update our position in the target mode incoming 106971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * command queue as seen by the sequencer. 106981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 106991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd->tqinfifonext & (HOST_TQINPOS - 1)) == 1) { 107001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int hs_mailbox; 107011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 107021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hs_mailbox = ahd_inb(ahd, HS_MAILBOX); 107031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hs_mailbox &= ~HOST_TQINPOS; 107041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hs_mailbox |= ahd->tqinfifonext & HOST_TQINPOS; 107051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_outb(ahd, HS_MAILBOX, hs_mailbox); 107061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 107071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 107081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 107091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 107101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 107111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_handle_target_cmd(struct ahd_softc *ahd, struct target_cmd *cmd) 107121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 107131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_tstate *tstate; 107141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ahd_tmode_lstate *lstate; 107151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ccb_accept_tio *atio; 107161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t *byte; 107171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int initiator; 107181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int target; 107191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int lun; 107201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 107211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds initiator = SCSIID_TARGET(ahd, cmd->scsiid); 107221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target = SCSIID_OUR_ID(cmd->scsiid); 107231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lun = (cmd->identify & MSG_IDENTIFY_LUNMASK); 107241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 107251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte = cmd->bytes; 107261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tstate = ahd->enabled_targets[target]; 107271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate = NULL; 107281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tstate != NULL) 107291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate = tstate->enabled_luns[lun]; 107301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 107311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 107321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Commands for disabled luns go to the black hole driver. 107331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 107341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lstate == NULL) 107351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate = ahd->black_hole; 107361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 107371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atio = (struct ccb_accept_tio*)SLIST_FIRST(&lstate->accept_tios); 107381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atio == NULL) { 107391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags |= AHD_TQINFIFO_BLOCKED; 107401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 107411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for more ATIOs from the peripheral driver for this lun. 107421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 107431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (1); 107441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 107451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->flags &= ~AHD_TQINFIFO_BLOCKED; 107461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 107471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_TQIN) != 0) 1074848813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Incoming command from %d for %d:%d%s\n", 107491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds initiator, target, lun, 107501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lstate == ahd->black_hole ? "(Black Holed)" : ""); 107511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 107521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle); 107531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 107541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lstate == ahd->black_hole) { 107551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Fill in the wildcards */ 107561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atio->ccb_h.target_id = target; 107571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atio->ccb_h.target_lun = lun; 107581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 107591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 107601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 107611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Package it up and send it off to 107621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * whomever has this lun enabled. 107631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 107641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atio->sense_len = 0; 107651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atio->init_id = initiator; 107661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (byte[0] != 0xFF) { 107671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Tag was included */ 107681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atio->tag_action = *byte++; 107691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atio->tag_id = *byte++; 107701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atio->ccb_h.flags = CAM_TAG_ACTION_VALID; 107711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 107721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atio->ccb_h.flags = 0; 107731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 107741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte++; 107751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 107761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Okay. Now determine the cdb size based on the command code */ 107771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (*byte >> CMD_GROUP_CODE_SHIFT) { 107781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 107791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atio->cdb_len = 6; 107801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 107811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: 107821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: 107831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atio->cdb_len = 10; 107841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 107851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 4: 107861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atio->cdb_len = 16; 107871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 107881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 5: 107891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atio->cdb_len = 12; 107901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 107911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 3: 107921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 107931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Only copy the opcode. */ 107941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atio->cdb_len = 1; 1079548813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Reserved or VU command code type encountered\n"); 107961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 107971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 107981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 107991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(atio->cdb_io.cdb_bytes, byte, atio->cdb_len); 108001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 108011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atio->ccb_h.status |= CAM_CDB_RECVD; 108021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 108031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((cmd->identify & MSG_IDENTIFY_DISCFLAG) == 0) { 108041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 108051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We weren't allowed to disconnect. 108061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We're hanging on the bus until a 108071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * continue target I/O comes in response 108081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to this accept tio. 108091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 108101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG 108111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ahd_debug & AHD_SHOW_TQIN) != 0) 1081248813cf989eb8695fe84df30207fc8ff5f15783cPekka Enberg printk("Received Immediate Command %d:%d:%d - %p\n", 108131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds initiator, target, lun, ahd->pending_device); 108141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 108151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd->pending_device = lstate; 108161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ahd_freeze_ccb((union ccb *)atio); 108171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atio->ccb_h.flags |= CAM_DIS_DISCONNECT; 108181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 108191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpt_done((union ccb*)atio); 108201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 108211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 108221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 108231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 10824