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, &current_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