aic79xx_osm.c revision 68b3aa7c9805aee9005a8ca53c5e99177961fbb9
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Adaptec AIC79xx device driver for Linux.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#171 $
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * --------------------------------------------------------------------------
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 1994-2000 Justin T. Gibbs.
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 1997-1999 Doug Ledford
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2000-2003 Adaptec Inc.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All rights reserved.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Redistribution and use in source and binary forms, with or without
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modification, are permitted provided that the following conditions
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are met:
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1. Redistributions of source code must retain the above copyright
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    notice, this list of conditions, and the following disclaimer,
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    without modification.
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2. Redistributions in binary form must reproduce at minimum a disclaimer
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    substantially similar to the "NO WARRANTY" disclaimer below
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    ("Disclaimer") and any redistribution must be conditioned upon
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    including a substantially similar Disclaimer requirement for further
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    binary redistribution.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3. Neither the names of the above-listed copyright holders nor the names
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    of any contributors may be used to endorse or promote products derived
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    from this software without specific prior written permission.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Alternatively, this software may be distributed under the terms of the
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License ("GPL") version 2 as published by the Free
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Software Foundation.
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NO WARRANTY
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * POSSIBILITY OF SUCH DAMAGES.
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "aic79xx_osm.h"
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "aic79xx_inline.h"
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsicam.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Include aiclib.c as part of our
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "module dependencies are hard" work around.
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "aiclib.c"
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>		/* __setup */
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sd.h"			/* For geometry detection */
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>		/* For fetching system memory size */
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>	/* For ssleep/msleep */
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Lock protecting manipulation of the ahd softc list.
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsspinlock_t ahd_list_spinlock;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* For dynamic sglist size calculation. */
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu_int ahd_linux_nseg;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bucket size for counting good commands in between bad ones.
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AHD_LINUX_ERR_THRESH	1000
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set this to the delay in seconds after SCSI bus reset.
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note, we honor this only for the initial bus reset.
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The scsi error recovery code performs its own bus settle
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * delay handling for error recovery actions.
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_AIC79XX_RESET_DELAY_MS
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AIC79XX_RESET_DELAY CONFIG_AIC79XX_RESET_DELAY_MS
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AIC79XX_RESET_DELAY 5000
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * To change the default number of tagged transactions allowed per-device,
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * add a line to the lilo.conf file like:
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * append="aic79xx=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}"
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * which will result in the first four devices on the first two
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * controllers being set to a tagged queue depth of 32.
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The tag_commands is an array of 16 to allow for wide and twin adapters.
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Twin adapters will use indexes 0-7 for channel 0, and indexes 8-15
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for channel 1.
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct {
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint16_t tag_commands[16];	/* Allow for wide/twin adapters. */
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} adapter_tag_info_t;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modify this as you see fit for your system.
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0			tagged queuing disabled
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1 <= n <= 253	n == max tags ever dispatched.
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The driver will throttle the number of commands dispatched to a
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device if it returns queue full.  For devices with a fixed maximum
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * queue depth, the driver will eventually determine this depth and
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lock it in (a console message is printed to indicate that a lock
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has occurred).  On some devices, queue full is returned for a temporary
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * resource shortage.  These devices will return queue full at varying
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * depths.  The driver will throttle back when the queue fulls occur and
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * attempt to slowly increase the depth over time as the device recovers
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from the resource shortage.
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In this example, the first line will disable tagged queueing for all
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the devices on the first probed aic79xx adapter.
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The second line enables tagged queueing with 4 commands/LUN for IDs
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (0, 2-11, 13-15), disables tagged queueing for ID 12, and tells the
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * driver to attempt to use up to 64 tags for ID 1.
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The third line is the same as the first line.
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The fourth line disables tagged queueing for devices 0 and 3.  It
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enables tagged queueing for the other IDs, with 16 commands/LUN
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IDs 2, 5-7, and 9-15.
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NOTE: The below structure is for reference only, the actual structure
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *       to modify in order to change things is just below this comment block.
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsadapter_tag_info_t aic79xx_tag_info[] =
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{{4, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4}},
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{{0, 16, 4, 0, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_AIC79XX_CMDS_PER_DEVICE
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AIC79XX_CMDS_PER_DEVICE CONFIG_AIC79XX_CMDS_PER_DEVICE
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AIC79XX_CMDS_PER_DEVICE AHD_MAX_QUEUE
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AIC79XX_CONFIGED_TAG_COMMANDS {					\
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE,		\
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE,		\
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE,		\
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE,		\
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE,		\
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE,		\
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE,		\
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE		\
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * By default, use the number of commands specified by
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the users kernel configuration.
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic adapter_tag_info_t aic79xx_tag_info[] =
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{AIC79XX_CONFIGED_TAG_COMMANDS},
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{AIC79XX_CONFIGED_TAG_COMMANDS},
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{AIC79XX_CONFIGED_TAG_COMMANDS},
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{AIC79XX_CONFIGED_TAG_COMMANDS},
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{AIC79XX_CONFIGED_TAG_COMMANDS},
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{AIC79XX_CONFIGED_TAG_COMMANDS},
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{AIC79XX_CONFIGED_TAG_COMMANDS},
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{AIC79XX_CONFIGED_TAG_COMMANDS},
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{AIC79XX_CONFIGED_TAG_COMMANDS},
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{AIC79XX_CONFIGED_TAG_COMMANDS},
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{AIC79XX_CONFIGED_TAG_COMMANDS},
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{AIC79XX_CONFIGED_TAG_COMMANDS},
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{AIC79XX_CONFIGED_TAG_COMMANDS},
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{AIC79XX_CONFIGED_TAG_COMMANDS},
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{AIC79XX_CONFIGED_TAG_COMMANDS},
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{AIC79XX_CONFIGED_TAG_COMMANDS}
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * By default, read streaming is disabled.  In theory,
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * read streaming should enhance performance, but early
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * U320 drive firmware actually performs slower with
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * read streaming enabled.
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_AIC79XX_ENABLE_RD_STRM
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AIC79XX_CONFIGED_RD_STRM 0xFFFF
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AIC79XX_CONFIGED_RD_STRM 0
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic uint16_t aic79xx_rd_strm_info[] =
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_RD_STRM,
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_RD_STRM,
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_RD_STRM,
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_RD_STRM,
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_RD_STRM,
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_RD_STRM,
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_RD_STRM,
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_RD_STRM,
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_RD_STRM,
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_RD_STRM,
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_RD_STRM,
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_RD_STRM,
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_RD_STRM,
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_RD_STRM,
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_RD_STRM,
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_RD_STRM
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DV option:
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * positive value = DV Enabled
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zero		  = DV Disabled
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * negative value = DV Default for adapter type/seeprom
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_AIC79XX_DV_SETTING
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AIC79XX_CONFIGED_DV CONFIG_AIC79XX_DV_SETTING
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AIC79XX_CONFIGED_DV -1
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int8_t aic79xx_dv_settings[] =
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_DV,
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_DV,
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_DV,
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_DV,
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_DV,
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_DV,
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_DV,
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_DV,
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_DV,
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_DV,
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_DV,
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_DV,
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_DV,
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_DV,
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_DV,
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_CONFIGED_DV
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The I/O cell on the chip is very configurable in respect to its analog
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * characteristics.  Set the defaults here; they can be overriden with
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the proper insmod parameters.
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ahd_linux_iocell_opts
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t	precomp;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t	slewrate;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t amplitude;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AIC79XX_DEFAULT_PRECOMP		0xFF
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AIC79XX_DEFAULT_SLEWRATE	0xFF
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AIC79XX_DEFAULT_AMPLITUDE	0xFF
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AIC79XX_DEFAULT_IOOPTS			\
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{						\
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_PRECOMP,		\
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_SLEWRATE,		\
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_AMPLITUDE		\
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AIC79XX_PRECOMP_INDEX	0
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AIC79XX_SLEWRATE_INDEX	1
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AIC79XX_AMPLITUDE_INDEX	2
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ahd_linux_iocell_opts aic79xx_iocell_info[] =
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_IOOPTS,
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_IOOPTS,
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_IOOPTS,
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_IOOPTS,
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_IOOPTS,
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_IOOPTS,
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_IOOPTS,
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_IOOPTS,
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_IOOPTS,
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_IOOPTS,
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_IOOPTS,
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_IOOPTS,
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_IOOPTS,
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_IOOPTS,
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_IOOPTS,
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AIC79XX_DEFAULT_IOOPTS
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There should be a specific return value for this in scsi.h, but
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it seems that most drivers ignore it.
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DID_UNDERFLOW   DID_ERROR
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_print_path(struct ahd_softc *ahd, struct scb *scb)
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("(scsi%d:%c:%d:%d): ",
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       ahd->platform_data->host->host_no,
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       scb != NULL ? SCB_GET_CHANNEL(ahd, scb) : 'X',
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       scb != NULL ? SCB_GET_TARGET(ahd, scb) : -1,
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       scb != NULL ? SCB_GET_LUN(scb) : -1);
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX - these options apply unilaterally to _all_ adapters
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *       cards in the system.  This should be fixed.  Exceptions to this
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *       rule are noted in the comments.
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Skip the scsi bus reset.  Non 0 make us skip the reset at startup.  This
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has no effect on any later resets that might occur due to things like
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCSI bus timeouts.
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic uint32_t aic79xx_no_reset;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Certain PCI motherboards will scan PCI devices from highest to lowest,
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * others scan from lowest to highest, and they tend to do all kinds of
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * strange things when they come into contact with PCI bridge chips.  The
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * net result of all this is that the PCI card that is actually used to boot
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the machine is very hard to detect.  Most motherboards go from lowest
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PCI slot number to highest, and the first SCSI controller found is the
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * one you boot from.  The only exceptions to this are when a controller
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has its BIOS disabled.  So, we by default sort all of our SCSI controllers
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from lowest PCI slot number to highest PCI slot number.  We also force
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * all controllers with their BIOS disabled to the end of the list.  This
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * works on *almost* all computers.  Where it doesn't work, we have this
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * option.  Setting this option to non-0 will reverse the order of the sort
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to highest first, then lowest, but will still leave cards with their BIOS
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * disabled at the very end.  That should fix everyone up unless there are
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * really strange cirumstances.
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic uint32_t aic79xx_reverse_scan;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Should we force EXTENDED translation on a controller.
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     0 == Use whatever is in the SEEPROM or default to off
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     1 == Use whatever is in the SEEPROM or default to on
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic uint32_t aic79xx_extended;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PCI bus parity checking of the Adaptec controllers.  This is somewhat
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dubious at best.  To my knowledge, this option has never actually
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * solved a PCI parity problem, but on certain machines with broken PCI
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chipset configurations, it can generate tons of false error messages.
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It's included in the driver for completeness.
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   0	   = Shut off PCI parity check
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   non-0 = Enable PCI parity check
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NOTE: you can't actually pass -1 on the lilo prompt.  So, to set this
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * variable to -1 you would actually want to simply pass the variable
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * name without a number.  That will invert the 0 which will result in
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -1.
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic uint32_t aic79xx_pci_parity = ~0;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There are lots of broken chipsets in the world.  Some of them will
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * violate the PCI spec when we issue byte sized memory writes to our
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * controller.  I/O mapped register access, if allowed by the given
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * platform, will work in almost all cases.
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuint32_t aic79xx_allow_memio = ~0;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * aic79xx_detect() has been run, so register all device arrivals
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * immediately with the system rather than deferring to the sorted
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * attachment performed by aic79xx_detect().
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint aic79xx_detect_complete;
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * So that we can set how long each device is given as a selection timeout.
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The table of values goes like this:
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   0 - 256ms
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   1 - 128ms
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   2 - 64ms
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   3 - 32ms
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We default to 256ms because some older devices need a longer time
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to respond to initial selection.
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic uint32_t aic79xx_seltime;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Certain devices do not perform any aging on commands.  Should the
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device be saturated by commands in one portion of the disk, it is
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * possible for transactions on far away sectors to never be serviced.
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * To handle these devices, we can periodically send an ordered tag to
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * force all outstanding transactions to be serviced prior to a new
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transaction.
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuint32_t aic79xx_periodic_otag;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Module information and settable options.
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *aic79xx = NULL;
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Maintainer: Justin T. Gibbs <gibbs@scsiguy.com>");
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Adaptec Aic790X U320 SCSI Host Bus Adapter driver");
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("Dual BSD/GPL");
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_VERSION(AIC79XX_DRIVER_VERSION);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(aic79xx, charp, 0);
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(aic79xx,
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"period delimited, options string.\n"
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	verbose			Enable verbose/diagnostic logging\n"
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	allow_memio		Allow device registers to be memory mapped\n"
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	debug			Bitmask of debug values to enable\n"
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	no_reset		Supress initial bus resets\n"
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	extended		Enable extended geometry on all controllers\n"
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	periodic_otag		Send an ordered tagged transaction\n"
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"				periodically to prevent tag starvation.\n"
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"				This may be required by some older disk\n"
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"				or drives/RAID arrays.\n"
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	reverse_scan		Sort PCI devices highest Bus/Slot to lowest\n"
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	tag_info:<tag_str>	Set per-target tag depth\n"
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	global_tag_depth:<int>	Global tag depth for all targets on all buses\n"
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	rd_strm:<rd_strm_masks> Set per-target read streaming setting.\n"
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	dv:<dv_settings>	Set per-controller Domain Validation Setting.\n"
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	slewrate:<slewrate_list>Set the signal slew rate (0-15).\n"
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	precomp:<pcomp_list>	Set the signal precompensation (0-7).\n"
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	amplitude:<int>		Set the signal amplitude (0-7).\n"
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	seltime:<int>		Selection Timeout:\n"
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"				(0/256ms,1/128ms,2/64ms,3/32ms)\n"
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"\n"
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	Sample /etc/modprobe.conf line:\n"
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"		Enable verbose logging\n"
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"		Set tag depth on Controller 2/Target 2 to 10 tags\n"
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"		Shorten the selection timeout to 128ms\n"
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"\n"
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	options aic79xx 'aic79xx=verbose.tag_info:{{}.{}.{..10}}.seltime:1'\n"
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"\n"
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	Sample /etc/modprobe.conf line:\n"
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"		Change Read Streaming for Controller's 2 and 3\n"
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"\n"
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	options aic79xx 'aic79xx=rd_strm:{..0xFFF0.0xC0F0}'");
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_handle_scsi_status(struct ahd_softc *,
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 struct ahd_linux_device *,
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 struct scb *);
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd,
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 Scsi_Cmnd *cmd);
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_filter_inquiry(struct ahd_softc *ahd,
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     struct ahd_devinfo *devinfo);
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_dev_timed_unfreeze(u_long arg);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_sem_timeout(u_long arg);
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd);
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_size_nseg(void);
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd);
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_start_dv(struct ahd_softc *ahd);
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_dv_timeout(struct scsi_cmnd *cmd);
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int  ahd_linux_dv_thread(void *data);
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_kill_dv_thread(struct ahd_softc *ahd);
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_dv_target(struct ahd_softc *ahd, u_int target);
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_dv_transition(struct ahd_softc *ahd,
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    struct scsi_cmnd *cmd,
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    struct ahd_devinfo *devinfo,
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    struct ahd_linux_target *targ);
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_dv_fill_cmd(struct ahd_softc *ahd,
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  struct scsi_cmnd *cmd,
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  struct ahd_devinfo *devinfo);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_dv_inq(struct ahd_softc *ahd,
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct scsi_cmnd *cmd,
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct ahd_devinfo *devinfo,
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct ahd_linux_target *targ,
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     u_int request_length);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_dv_tur(struct ahd_softc *ahd,
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct scsi_cmnd *cmd,
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct ahd_devinfo *devinfo);
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_dv_rebd(struct ahd_softc *ahd,
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct scsi_cmnd *cmd,
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct ahd_devinfo *devinfo,
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct ahd_linux_target *targ);
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_dv_web(struct ahd_softc *ahd,
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct scsi_cmnd *cmd,
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct ahd_devinfo *devinfo,
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct ahd_linux_target *targ);
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_dv_reb(struct ahd_softc *ahd,
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct scsi_cmnd *cmd,
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct ahd_devinfo *devinfo,
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct ahd_linux_target *targ);
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_dv_su(struct ahd_softc *ahd,
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    struct scsi_cmnd *cmd,
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    struct ahd_devinfo *devinfo,
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    struct ahd_linux_target *targ);
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ahd_linux_fallback(struct ahd_softc *ahd,
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct ahd_devinfo *devinfo);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline int ahd_linux_dv_fallback(struct ahd_softc *ahd,
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  struct ahd_devinfo *devinfo);
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_dv_complete(Scsi_Cmnd *cmd);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_generate_dv_pattern(struct ahd_linux_target *targ);
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd,
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     struct ahd_devinfo *devinfo);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int ahd_linux_user_dv_setting(struct ahd_softc *ahd);
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_setup_user_rd_strm_settings(struct ahd_softc *ahd);
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_device_queue_depth(struct ahd_softc *ahd,
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 struct ahd_linux_device *dev);
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ahd_linux_target*	ahd_linux_alloc_target(struct ahd_softc*,
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						       u_int, u_int);
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void			ahd_linux_free_target(struct ahd_softc*,
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						      struct ahd_linux_target*);
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ahd_linux_device*	ahd_linux_alloc_device(struct ahd_softc*,
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						       struct ahd_linux_target*,
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						       u_int);
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void			ahd_linux_free_device(struct ahd_softc*,
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						      struct ahd_linux_device*);
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_run_device_queue(struct ahd_softc*,
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       struct ahd_linux_device*);
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_linux_setup_tag_info_global(char *p);
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic aic_option_callback_t ahd_linux_setup_tag_info;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic aic_option_callback_t ahd_linux_setup_rd_strm_info;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic aic_option_callback_t ahd_linux_setup_dv;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic aic_option_callback_t ahd_linux_setup_iocell_info;
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ahd_linux_next_unit(void);
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ahd_runq_tasklet(unsigned long data);
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int aic79xx_setup(char *c);
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/****************************** Inlines ***************************************/
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline void ahd_schedule_completeq(struct ahd_softc *ahd);
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline void ahd_schedule_runq(struct ahd_softc *ahd);
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline void ahd_setup_runq_tasklet(struct ahd_softc *ahd);
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline void ahd_teardown_runq_tasklet(struct ahd_softc *ahd);
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline struct ahd_linux_device*
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     ahd_linux_get_device(struct ahd_softc *ahd, u_int channel,
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  u_int target, u_int lun, int alloc);
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ahd_cmd *ahd_linux_run_complete_queue(struct ahd_softc *ahd);
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline void ahd_linux_check_device_queue(struct ahd_softc *ahd,
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  struct ahd_linux_device *dev);
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline struct ahd_linux_device *
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     ahd_linux_next_device_to_run(struct ahd_softc *ahd);
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline void ahd_linux_run_device_queues(struct ahd_softc *ahd);
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*);
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline void
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_schedule_completeq(struct ahd_softc *ahd)
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ahd->platform_data->flags & AHD_RUN_CMPLT_Q_TIMER) == 0) {
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd->platform_data->flags |= AHD_RUN_CMPLT_Q_TIMER;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd->platform_data->completeq_timer.expires = jiffies;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		add_timer(&ahd->platform_data->completeq_timer);
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Must be called with our lock held.
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline void
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_schedule_runq(struct ahd_softc *ahd)
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tasklet_schedule(&ahd->platform_data->runq_tasklet);
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ahd_setup_runq_tasklet(struct ahd_softc *ahd)
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tasklet_init(&ahd->platform_data->runq_tasklet, ahd_runq_tasklet,
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     (unsigned long)ahd);
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline void
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_teardown_runq_tasklet(struct ahd_softc *ahd)
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tasklet_kill(&ahd->platform_data->runq_tasklet);
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline struct ahd_linux_device*
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_get_device(struct ahd_softc *ahd, u_int channel, u_int target,
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     u_int lun, int alloc)
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_linux_target *targ;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_linux_device *dev;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int target_offset;
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	target_offset = target;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (channel != 0)
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		target_offset += 8;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ = ahd->platform_data->targets[target_offset];
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ == NULL) {
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (alloc != 0) {
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			targ = ahd_linux_alloc_target(ahd, channel, target);
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (targ == NULL)
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return (NULL);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (NULL);
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = targ->devices[lun];
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev == NULL && alloc != 0)
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev = ahd_linux_alloc_device(ahd, targ, lun);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (dev);
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AHD_LINUX_MAX_RETURNED_ERRORS 4
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ahd_cmd *
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_run_complete_queue(struct ahd_softc *ahd)
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_cmd *acmd;
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long	done_flags;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	with_errors;
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	with_errors = 0;
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_done_lock(ahd, &done_flags);
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((acmd = TAILQ_FIRST(&ahd->platform_data->completeq)) != NULL) {
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		Scsi_Cmnd *cmd;
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (with_errors > AHD_LINUX_MAX_RETURNED_ERRORS) {
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Linux uses stack recursion to requeue
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * commands that need to be retried.  Avoid
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * blowing out the stack by "spoon feeding"
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * commands that completed with error back
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * the operating system in case they are going
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * to be retried. "ick"
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_schedule_completeq(ahd);
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		TAILQ_REMOVE(&ahd->platform_data->completeq,
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     acmd, acmd_links.tqe);
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmd = &acmd_scsi_cmd(acmd);
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmd->host_scribble = NULL;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ahd_cmd_get_transaction_status(cmd) != DID_OK
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 || (cmd->result & 0xFF) != SCSI_STATUS_OK)
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			with_errors++;
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmd->scsi_done(cmd);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_done_unlock(ahd, &done_flags);
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (acmd);
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline void
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_check_device_queue(struct ahd_softc *ahd,
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct ahd_linux_device *dev)
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) != 0
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && dev->active == 0) {
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->flags &= ~AHD_DEV_FREEZE_TIL_EMPTY;
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->qfrozen--;
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (TAILQ_FIRST(&dev->busyq) == NULL
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 || dev->openings == 0 || dev->qfrozen != 0)
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_run_device_queue(ahd, dev);
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline struct ahd_linux_device *
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_next_device_to_run(struct ahd_softc *ahd)
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ahd->flags & AHD_RESOURCE_SHORTAGE) != 0
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 || (ahd->platform_data->qfrozen != 0
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  && AHD_DV_SIMQ_FROZEN(ahd) == 0))
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (NULL);
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (TAILQ_FIRST(&ahd->platform_data->device_runq));
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline void
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_run_device_queues(struct ahd_softc *ahd)
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_linux_device *dev;
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((dev = ahd_linux_next_device_to_run(ahd)) != NULL) {
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		TAILQ_REMOVE(&ahd->platform_data->device_runq, dev, links);
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->flags &= ~AHD_DEV_ON_RUN_LIST;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_check_device_queue(ahd, dev);
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline void
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb)
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Scsi_Cmnd *cmd;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int direction;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd = scb->io_ctx;
690be7db055dd7261522557046370f49160728e3847<hch@lst.de>	direction = cmd->sc_data_direction;
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_sync_sglist(ahd, scb, BUS_DMASYNC_POSTWRITE);
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cmd->use_sg != 0) {
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct scatterlist *sg;
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sg = (struct scatterlist *)cmd->request_buffer;
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_unmap_sg(ahd->dev_softc, sg, cmd->use_sg, direction);
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (cmd->request_bufflen != 0) {
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_unmap_single(ahd->dev_softc,
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 scb->platform_data->buf_busaddr,
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 cmd->request_bufflen, direction);
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/******************************** Macros **************************************/
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BUILD_SCSIID(ahd, cmd)						\
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	((((cmd)->device->id << TID_SHIFT) & TID) | (ahd)->our_id)
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************  Host template entry points *************************/
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int	   ahd_linux_detect(Scsi_Host_Template *);
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *ahd_linux_info(struct Scsi_Host *);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int	   ahd_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int	   ahd_linux_slave_alloc(Scsi_Device *);
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int	   ahd_linux_slave_configure(Scsi_Device *);
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void	   ahd_linux_slave_destroy(Scsi_Device *);
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(__i386__)
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int	   ahd_linux_biosparam(struct scsi_device*,
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       struct block_device*, sector_t, int[]);
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int	   ahd_linux_release(struct Scsi_Host *);
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void	   ahd_linux_select_queue_depth(struct Scsi_Host *host,
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						Scsi_Device *scsi_devs);
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(__i386__)
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int	   ahd_linux_biosparam(Disk *, kdev_t, int[]);
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int	   ahd_linux_bus_reset(Scsi_Cmnd *);
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int	   ahd_linux_dev_reset(Scsi_Cmnd *);
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int	   ahd_linux_abort(Scsi_Cmnd *);
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calculate a safe value for AHD_NSEG (as expressed through ahd_linux_nseg).
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In pre-2.5.X...
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The midlayer allocates an S/G array dynamically when a command is issued
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * using SCSI malloc.  This array, which is in an OS dependent format that
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * must later be copied to our private S/G list, is sized to house just the
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * number of segments needed for the current transfer.  Since the code that
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sizes the SCSI malloc pool does not take into consideration fragmentation
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the pool, executing transactions numbering just a fraction of our
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * concurrent transaction limit with SG list lengths aproaching AHC_NSEG will
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * quickly depleat the SCSI malloc pool of usable space.  Unfortunately, the
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mid-layer does not properly handle this scsi malloc failures for the S/G
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * array and the result can be a lockup of the I/O subsystem.  We try to size
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * our S/G list so that it satisfies our drivers allocation requirements in
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * addition to avoiding fragmentation of the SCSI malloc pool.
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_size_nseg(void)
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int cur_size;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int best_size;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The SCSI allocator rounds to the nearest 512 bytes
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * an cannot allocate across a page boundary.  Our algorithm
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * is to start at 1K of scsi malloc space per-command and
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * loop through all factors of the PAGE_SIZE and pick the best.
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	best_size = 0;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (cur_size = 1024; cur_size <= PAGE_SIZE; cur_size *= 2) {
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u_int nseg;
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nseg = cur_size / sizeof(struct scatterlist);
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (nseg < AHD_LINUX_MIN_NSEG)
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (best_size == 0) {
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			best_size = cur_size;
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_linux_nseg = nseg;
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u_int best_rem;
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u_int cur_rem;
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Compare the traits of the current "best_size"
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * with the current size to determine if the
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * current size is a better size.
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			best_rem = best_size % sizeof(struct scatterlist);
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cur_rem = cur_size % sizeof(struct scatterlist);
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cur_rem < best_rem) {
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				best_size = cur_size;
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ahd_linux_nseg = nseg;
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to detect an Adaptec 79XX controller.
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_detect(Scsi_Host_Template *template)
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_softc *ahd;
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int     found;
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	error = 0;
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * It is a bug that the upper layer takes
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * this lock just prior to calling us.
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&io_request_lock);
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Sanity checking of Linux SCSI data structures so
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * that some of our hacks^H^H^H^H^Hassumptions aren't
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * violated.
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (offsetof(struct ahd_cmd_internal, end)
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  > offsetof(struct scsi_cmnd, host_scribble)) {
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("ahd_linux_detect: SCSI data structures changed.\n");
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("ahd_linux_detect: Unable to attach\n");
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Determine an appropriate size for our Scatter Gatther lists.
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_size_nseg();
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If we've been passed any parameters, process them now.
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (aic79xx)
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		aic79xx_setup(aic79xx);
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	template->proc_name = "aic79xx";
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Initialize our softc list lock prior to
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * probing for any adapters.
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_list_lockinit();
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PCI
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = ahd_linux_pci_init();
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (error)
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return error;
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Register with the SCSI layer all
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * controllers we've found.
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	found = 0;
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TAILQ_FOREACH(ahd, &ahd_tailq, links) {
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ahd_linux_register_host(ahd, template) == 0)
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			found++;
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&io_request_lock);
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	aic79xx_detect_complete++;
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free the passed in Scsi_Host memory structures prior to unloading the
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * module.
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_release(struct Scsi_Host * host)
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_softc *ahd;
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long l;
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_list_lock(&l);
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (host != NULL) {
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * We should be able to just perform
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the free directly, but check our
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * list for extra sanity.
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd = ahd_find_softc(*(struct ahd_softc **)host->hostdata);
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ahd != NULL) {
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u_long s;
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_lock(ahd, &s);
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_intr_enable(ahd, FALSE);
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_unlock(ahd, &s);
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_free(ahd);
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_list_unlock(&l);
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return a string describing the driver.
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_info(struct Scsi_Host *host)
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static char buffer[512];
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char	ahd_info[256];
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char   *bp;
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_softc *ahd;
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp = &buffer[0];
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd = *(struct ahd_softc **)host->hostdata;
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(bp, 0, sizeof(buffer));
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(bp, "Adaptec AIC79XX PCI-X SCSI HBA DRIVER, Rev ");
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(bp, AIC79XX_DRIVER_VERSION);
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(bp, "\n");
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(bp, "        <");
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(bp, ahd->description);
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(bp, ">\n");
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(bp, "        ");
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_controller_info(ahd, ahd_info);
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(bp, ahd_info);
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(bp, "\n");
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (bp);
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Queue an SCB to the controller.
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	 ahd_softc *ahd;
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	 ahd_linux_device *dev;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long	 flags;
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Save the callback on completion function.
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->scsi_done = scsi_done;
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9448fa728a26886f56a9ee10a44fea0ddda301d21c3Jeff Garzik	ahd_lock(ahd, &flags);
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Close the race of a command that was in the process of
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * being queued to us just as our simq was frozen.  Let
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * DV commands through so long as we are only frozen to
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * perform DV.
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd->platform_data->qfrozen != 0
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && AHD_DV_CMD(cmd) == 0) {
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ);
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_queue_cmd_complete(ahd, cmd);
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_schedule_completeq(ahd);
9588fa728a26886f56a9ee10a44fea0ddda301d21c3Jeff Garzik		ahd_unlock(ahd, &flags);
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = ahd_linux_get_device(ahd, cmd->device->channel,
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   cmd->device->id, cmd->device->lun,
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   /*alloc*/TRUE);
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev == NULL) {
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL);
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_queue_cmd_complete(ahd, cmd);
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_schedule_completeq(ahd);
9688fa728a26886f56a9ee10a44fea0ddda301d21c3Jeff Garzik		ahd_unlock(ahd, &flags);
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s: aic79xx_linux_queue - Unable to allocate device!\n",
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       ahd_name(ahd));
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cmd->cmd_len > MAX_CDB_LEN)
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (-EINVAL);
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->result = CAM_REQ_INPROG << 16;
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TAILQ_INSERT_TAIL(&dev->busyq, (struct ahd_cmd *)cmd, acmd_links.tqe);
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) {
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links);
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->flags |= AHD_DEV_ON_RUN_LIST;
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_run_device_queues(ahd);
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9828fa728a26886f56a9ee10a44fea0ddda301d21c3Jeff Garzik	ahd_unlock(ahd, &flags);
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_slave_alloc(Scsi_Device *device)
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_softc *ahd;
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd = *((struct ahd_softc **)device->host->hostdata);
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bootverbose)
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s: Slave Alloc %d\n", ahd_name(ahd), device->id);
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_slave_configure(Scsi_Device *device)
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_softc *ahd;
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_linux_device *dev;
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long	flags;
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd = *((struct ahd_softc **)device->host->hostdata);
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bootverbose)
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s: Slave Configure %d\n", ahd_name(ahd), device->id);
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_midlayer_entrypoint_lock(ahd, &flags);
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Since Linux has attached to the device, configure
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * it so we don't free and allocate the device
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * structure on every command.
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = ahd_linux_get_device(ahd, device->channel,
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   device->id, device->lun,
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   /*alloc*/TRUE);
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev != NULL) {
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->flags &= ~AHD_DEV_UNCONFIGURED;
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->flags |= AHD_DEV_SLAVE_CONFIGURED;
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->scsi_device = device;
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_device_queue_depth(ahd, dev);
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_midlayer_entrypoint_unlock(ahd, &flags);
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_slave_destroy(Scsi_Device *device)
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_softc *ahd;
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_linux_device *dev;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long	flags;
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd = *((struct ahd_softc **)device->host->hostdata);
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bootverbose)
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s: Slave Destroy %d\n", ahd_name(ahd), device->id);
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_midlayer_entrypoint_lock(ahd, &flags);
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = ahd_linux_get_device(ahd, device->channel,
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   device->id, device->lun,
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   /*alloc*/FALSE);
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Filter out "silly" deletions of real devices by only
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * deleting devices that have had slave_configure()
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * called on them.  All other devices that have not
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * been configured will automatically be deleted by
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the refcounting process.
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev != NULL
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && (dev->flags & AHD_DEV_SLAVE_CONFIGURED) != 0) {
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->flags |= AHD_DEV_UNCONFIGURED;
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (TAILQ_EMPTY(&dev->busyq)
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && dev->active == 0
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0)
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_linux_free_device(ahd, dev);
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_midlayer_entrypoint_unlock(ahd, &flags);
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sets the queue depth for each SCSI device hanging
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * off the input host adapter.
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_select_queue_depth(struct Scsi_Host * host,
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     Scsi_Device * scsi_devs)
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Scsi_Device *device;
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Scsi_Device *ldev;
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_softc *ahd;
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long	flags;
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd = *((struct ahd_softc **)host->hostdata);
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_lock(ahd, &flags);
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (device = scsi_devs; device != NULL; device = device->next) {
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Watch out for duplicate devices.  This works around
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * some quirks in how the SCSI scanning code does its
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * device management.
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (ldev = scsi_devs; ldev != device; ldev = ldev->next) {
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ldev->host == device->host
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 && ldev->channel == device->channel
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 && ldev->id == device->id
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 && ldev->lun == device->lun)
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Skip duplicate. */
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ldev != device)
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (device->host == host) {
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct	 ahd_linux_device *dev;
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Since Linux has attached to the device, configure
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * it so we don't free and allocate the device
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * structure on every command.
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev = ahd_linux_get_device(ahd, device->channel,
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   device->id, device->lun,
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   /*alloc*/TRUE);
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (dev != NULL) {
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev->flags &= ~AHD_DEV_UNCONFIGURED;
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev->scsi_device = device;
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ahd_linux_device_queue_depth(ahd, dev);
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				device->queue_depth = dev->openings
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    + dev->active;
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((dev->flags & (AHD_DEV_Q_BASIC
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						| AHD_DEV_Q_TAGGED)) == 0) {
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/*
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 * We allow the OS to queue 2 untagged
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 * transactions to us at any time even
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 * though we can only execute them
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 * serially on the controller/device.
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 * This should remove some latency.
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 */
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					device->queue_depth = 2;
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_unlock(ahd, &flags);
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(__i386__)
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return the disk geometry for the given SCSI device.
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev,
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    sector_t capacity, int geom[])
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t *bh;
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_biosparam(Disk *disk, kdev_t dev, int geom[])
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	scsi_device *sdev = disk->device;
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long	capacity = disk->capacity;
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	buffer_head *bh;
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	 heads;
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	 sectors;
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	 cylinders;
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	 ret;
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	 extended;
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	 ahd_softc *ahd;
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd = *((struct ahd_softc **)sdev->host->hostdata);
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bh = scsi_bios_ptable(bdev);
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev));
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024);
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bh) {
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = scsi_partsize(bh, capacity,
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    &geom[2], &geom[0], &geom[1]);
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(bh);
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		brelse(bh);
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret != -1)
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (ret);
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	heads = 64;
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sectors = 32;
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cylinders = aic_sector_div(capacity, heads, sectors);
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (aic79xx_extended != 0)
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		extended = 1;
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		extended = (ahd->flags & AHD_EXTENDED_TRANS_A) != 0;
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (extended && cylinders >= 1024) {
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		heads = 255;
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sectors = 63;
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cylinders = aic_sector_div(capacity, heads, sectors);
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	geom[0] = heads;
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	geom[1] = sectors;
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	geom[2] = cylinders;
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Abort the current SCSI command(s).
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_abort(Scsi_Cmnd *cmd)
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_softc *ahd;
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_cmd *acmd;
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_cmd *list_acmd;
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_linux_device *dev;
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scb *pending_scb;
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long s;
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int  saved_scbptr;
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int  active_scbptr;
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int  last_phase;
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int  cdb_byte;
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int    retval;
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int    was_paused;
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int    paused;
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int    wait;
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int    disconnected;
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_mode_state saved_modes;
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pending_scb = NULL;
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	paused = FALSE;
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait = FALSE;
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acmd = (struct ahd_cmd *)cmd;
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printf("%s:%d:%d:%d: Attempting to abort cmd %p:",
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       ahd_name(ahd), cmd->device->channel, cmd->device->id,
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       cmd->device->lun, cmd);
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf(" 0x%x", cmd->cmnd[cdb_byte]);
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printf("\n");
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * In all versions of Linux, we have to work around
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * a major flaw in how the mid-layer is locked down
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * if we are to sleep successfully in our error handler
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * while allowing our interrupt handler to run.  Since
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the midlayer acquires either the io_request_lock or
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * our lock prior to calling us, we must use the
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * spin_unlock_irq() method for unlocking our lock.
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * This will force interrupts to be enabled on the
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * current CPU.  Since the EH thread should not have
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * been running with CPU interrupts disabled other than
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * by acquiring either the io_request_lock or our own
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * lock, this *should* be safe.
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_midlayer_entrypoint_lock(ahd, &s);
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * First determine if we currently own this command.
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Start by searching the device queue.  If not found
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * there, check the pending_scb list.  If not found
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * at all, and the system wanted us to just abort the
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * command, return success.
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = ahd_linux_get_device(ahd, cmd->device->channel,
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   cmd->device->id, cmd->device->lun,
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   /*alloc*/FALSE);
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev == NULL) {
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * No target device for this command exists,
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * so we must not still own the command.
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s:%d:%d:%d: Is not an active device\n",
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       ahd_name(ahd), cmd->device->channel, cmd->device->id,
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       cmd->device->lun);
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = SUCCESS;
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto no_cmd;
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TAILQ_FOREACH(list_acmd, &dev->busyq, acmd_links.tqe) {
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (list_acmd == acmd)
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (list_acmd != NULL) {
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s:%d:%d:%d: Command found on device queue\n",
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       ahd_name(ahd), cmd->device->channel, cmd->device->id,
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       cmd->device->lun);
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe);
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmd->result = DID_ABORT << 16;
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_queue_cmd_complete(ahd, cmd);
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = SUCCESS;
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * See if we can find a matching cmd in the pending list.
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) {
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pending_scb->io_ctx == cmd)
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pending_scb == NULL) {
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s:%d:%d:%d: Command not found\n",
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       ahd_name(ahd), cmd->device->channel, cmd->device->id,
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       cmd->device->lun);
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto no_cmd;
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((pending_scb->flags & SCB_RECOVERY_SCB) != 0) {
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * We can't queue two recovery actions using the same SCB
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = FAILED;
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto  done;
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Ensure that the card doesn't do anything
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * behind our back.  Also make sure that we
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * didn't "just" miss an interrupt that would
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * affect this cmd.
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	was_paused = ahd_is_paused(ahd);
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_pause_and_flushwork(ahd);
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	paused = TRUE;
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((pending_scb->flags & SCB_ACTIVE) == 0) {
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s:%d:%d:%d: Command already completed\n",
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       ahd_name(ahd), cmd->device->channel, cmd->device->id,
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       cmd->device->lun);
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto no_cmd;
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printf("%s: At time of recovery, card was %spaused\n",
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       ahd_name(ahd), was_paused ? "" : "not ");
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_dump_card_state(ahd);
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	disconnected = TRUE;
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_search_qinfifo(ahd, cmd->device->id, cmd->device->channel + 'A',
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       cmd->device->lun, SCB_GET_TAG(pending_scb),
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       ROLE_INITIATOR, CAM_REQ_ABORTED,
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       SEARCH_COMPLETE) > 0) {
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       ahd_name(ahd), cmd->device->channel, cmd->device->id,
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cmd->device->lun);
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = SUCCESS;
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saved_modes = ahd_save_modes(ahd);
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	last_phase = ahd_inb(ahd, LASTPHASE);
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saved_scbptr = ahd_get_scbptr(ahd);
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	active_scbptr = saved_scbptr;
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (disconnected && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) {
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct scb *bus_scb;
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bus_scb = ahd_lookup_scb(ahd, active_scbptr);
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bus_scb == pending_scb)
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			disconnected = FALSE;
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * At this point, pending_scb is the scb associated with the
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * passed in command.  That command is currently active on the
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * bus or is in the disconnected state.
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (last_phase != P_BUSFREE
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && SCB_GET_TAG(pending_scb) == active_scbptr) {
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * We're active on the bus, so assert ATN
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * and hope that the target responds.
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pending_scb = ahd_lookup_scb(ahd, active_scbptr);
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT;
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_outb(ahd, MSG_OUT, HOST_MSG);
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_outb(ahd, SCSISIGO, last_phase|ATNO);
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s:%d:%d:%d: Device is active, asserting ATN\n",
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       ahd_name(ahd), cmd->device->channel,
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       cmd->device->id, cmd->device->lun);
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wait = TRUE;
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (disconnected) {
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Actually re-queue this SCB in an attempt
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * to select the device before it reconnects.
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT;
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_set_scbptr(ahd, SCB_GET_TAG(pending_scb));
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pending_scb->hscb->cdb_len = 0;
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pending_scb->hscb->task_attribute = 0;
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pending_scb->hscb->task_management = SIU_TASKMGMT_ABORT_TASK;
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((pending_scb->flags & SCB_PACKETIZED) != 0) {
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Mark the SCB has having an outstanding
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * task management function.  Should the command
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * complete normally before the task management
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * function can be sent, the host will be notified
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * to abort our requeued SCB.
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_outb(ahd, SCB_TASK_MANAGEMENT,
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 pending_scb->hscb->task_management);
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * If non-packetized, set the MK_MESSAGE control
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * bit indicating that we desire to send a message.
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * We also set the disconnected flag since there is
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * no guarantee that our SCB control byte matches
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * the version on the card.  We don't want the
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * sequencer to abort the command thinking an
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * unsolicited reselection occurred.
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED;
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * The sequencer will never re-reference the
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * in-core SCB.  To make sure we are notified
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * during reslection, set the MK_MESSAGE flag in
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * the card's copy of the SCB.
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_outb(ahd, SCB_CONTROL,
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 ahd_inb(ahd, SCB_CONTROL)|MK_MESSAGE);
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Clear out any entries in the QINFIFO first
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * so we are the next SCB for this target
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * to run.
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_search_qinfifo(ahd, cmd->device->id,
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   cmd->device->channel + 'A', cmd->device->lun,
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   SCB_LIST_NULL, ROLE_INITIATOR,
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   CAM_REQUEUE_REQ, SEARCH_COMPLETE);
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_qinfifo_requeue_tail(ahd, pending_scb);
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_set_scbptr(ahd, saved_scbptr);
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_print_path(ahd, pending_scb);
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("Device is disconnected, re-queuing SCB\n");
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wait = TRUE;
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s:%d:%d:%d: Unable to deliver message\n",
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       ahd_name(ahd), cmd->device->channel,
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       cmd->device->id, cmd->device->lun);
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = FAILED;
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsno_cmd:
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Our assumption is that if we don't have the command, no
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * recovery action was required, so we return success.  Again,
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the semantics of the mid-layer recovery engine are not
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * well defined, so this may change in time.
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = SUCCESS;
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (paused)
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_unpause(ahd);
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (wait) {
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct timer_list timer;
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int ret;
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pending_scb->platform_data->flags |= AHD_SCB_UP_EH_SEM;
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irq(&ahd->platform_data->spin_lock);
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		init_timer(&timer);
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timer.data = (u_long)pending_scb;
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timer.expires = jiffies + (5 * HZ);
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timer.function = ahd_linux_sem_timeout;
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		add_timer(&timer);
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("Recovery code sleeping\n");
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		down(&ahd->platform_data->eh_sem);
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("Recovery code awake\n");
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        	ret = del_timer_sync(&timer);
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret == 0) {
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf("Timer Expired\n");
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = FAILED;
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irq(&ahd->platform_data->spin_lock);
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_schedule_runq(ahd);
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_run_complete_queue(ahd);
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_midlayer_entrypoint_unlock(ahd, &s);
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (retval);
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_dev_reset_complete(Scsi_Cmnd *cmd)
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free(cmd, M_DEVBUF);
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Attempt to send a target reset message to the device that timed out.
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_dev_reset(Scsi_Cmnd *cmd)
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_softc *ahd;
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	scsi_cmnd *recovery_cmd;
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_linux_device *dev;
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_initiator_tinfo *tinfo;
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_tmode_tstate *tstate;
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	scb *scb;
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	hardware_scb *hscb;
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long	s;
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	timer_list timer;
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	retval;
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	recovery_cmd = malloc(sizeof(struct scsi_cmnd), M_DEVBUF, M_WAITOK);
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!recovery_cmd)
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (FAILED);
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(recovery_cmd, 0, sizeof(struct scsi_cmnd));
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	recovery_cmd->device = cmd->device;
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	recovery_cmd->scsi_done = ahd_linux_dev_reset_complete;
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if AHD_DEBUG
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s:%d:%d:%d: Device reset called for cmd %p\n",
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       ahd_name(ahd), cmd->device->channel, cmd->device->id,
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       cmd->device->lun, cmd);
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
151494d0e7b805961c44e4dc486ffc21075084bb7175Jeff Garzik	ahd_lock(ahd, &s);
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = ahd_linux_get_device(ahd, cmd->device->channel, cmd->device->id,
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   cmd->device->lun, /*alloc*/FALSE);
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev == NULL) {
151994d0e7b805961c44e4dc486ffc21075084bb7175Jeff Garzik		ahd_unlock(ahd, &s);
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(recovery_cmd);
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (FAILED);
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((scb = ahd_get_scb(ahd, AHD_NEVER_COL_IDX)) == NULL) {
152494d0e7b805961c44e4dc486ffc21075084bb7175Jeff Garzik		ahd_unlock(ahd, &s);
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(recovery_cmd);
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (FAILED);
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    cmd->device->id, &tstate);
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	recovery_cmd->result = CAM_REQ_INPROG << 16;
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	recovery_cmd->host_scribble = (char *)scb;
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scb->io_ctx = recovery_cmd;
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scb->platform_data->dev = dev;
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scb->sg_count = 0;
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_set_residual(scb, 0);
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_set_sense_residual(scb, 0);
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hscb = scb->hscb;
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hscb->control = 0;
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hscb->scsiid = BUILD_SCSIID(ahd, cmd);
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hscb->lun = cmd->device->lun;
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hscb->cdb_len = 0;
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hscb->task_management = SIU_TASKMGMT_LUN_RESET;
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scb->flags |= SCB_DEVICE_RESET|SCB_RECOVERY_SCB|SCB_ACTIVE;
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		scb->flags |= SCB_PACKETIZED;
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hscb->control |= MK_MESSAGE;
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->openings--;
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->active++;
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->commands_issued++;
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_queue_scb(ahd, scb);
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scb->platform_data->flags |= AHD_SCB_UP_EH_SEM;
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&ahd->platform_data->spin_lock);
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer(&timer);
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timer.data = (u_long)scb;
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timer.expires = jiffies + (5 * HZ);
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timer.function = ahd_linux_sem_timeout;
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_timer(&timer);
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printf("Recovery code sleeping\n");
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&ahd->platform_data->eh_sem);
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printf("Recovery code awake\n");
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = SUCCESS;
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (del_timer_sync(&timer) == 0) {
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("Timer Expired\n");
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = FAILED;
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&ahd->platform_data->spin_lock);
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_schedule_runq(ahd);
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_run_complete_queue(ahd);
157394d0e7b805961c44e4dc486ffc21075084bb7175Jeff Garzik	ahd_unlock(ahd, &s);
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval);
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (retval);
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset the SCSI bus.
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_bus_reset(Scsi_Cmnd *cmd)
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_softc *ahd;
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long s;
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int    found;
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s: Bus reset called for cmd %p\n",
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       ahd_name(ahd), cmd);
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
159468b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik	ahd_lock(ahd, &s);
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	found = ahd_reset_channel(ahd, cmd->device->channel + 'A',
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  /*initiate reset*/TRUE);
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_run_complete_queue(ahd);
159868b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik	ahd_unlock(ahd, &s);
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bootverbose)
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s: SCSI bus reset delivered. "
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "%d SCBs aborted.\n", ahd_name(ahd), found);
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (SUCCESS);
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsScsi_Host_Template aic79xx_driver_template = {
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.module			= THIS_MODULE,
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name			= "aic79xx",
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.proc_info		= ahd_linux_proc_info,
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.info			= ahd_linux_info,
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.queuecommand		= ahd_linux_queue,
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.eh_abort_handler	= ahd_linux_abort,
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.eh_device_reset_handler = ahd_linux_dev_reset,
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.eh_bus_reset_handler	= ahd_linux_bus_reset,
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(__i386__)
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.bios_param		= ahd_linux_biosparam,
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.can_queue		= AHD_MAX_QUEUE,
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.this_id		= -1,
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.cmd_per_lun		= 2,
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.use_clustering		= ENABLE_CLUSTERING,
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.slave_alloc		= ahd_linux_slave_alloc,
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.slave_configure	= ahd_linux_slave_configure,
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.slave_destroy		= ahd_linux_slave_destroy,
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**************************** Tasklet Handler *********************************/
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In 2.4.X and above, this routine is called from a tasklet,
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so we must re-acquire our lock prior to executing this code.
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In all prior kernels, ahd_schedule_runq() calls this routine
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * directly and ahd_schedule_runq() is called with our lock held.
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_runq_tasklet(unsigned long data)
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_softc* ahd;
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_linux_device *dev;
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long flags;
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd = (struct ahd_softc *)data;
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_lock(ahd, &flags);
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((dev = ahd_linux_next_device_to_run(ahd)) != NULL) {
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		TAILQ_REMOVE(&ahd->platform_data->device_runq, dev, links);
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->flags &= ~AHD_DEV_ON_RUN_LIST;
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_check_device_queue(ahd, dev);
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Yeild to our interrupt handler */
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_unlock(ahd, &flags);
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_lock(ahd, &flags);
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_unlock(ahd, &flags);
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/******************************** Bus DMA *************************************/
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent,
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   bus_size_t alignment, bus_size_t boundary,
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   dma_addr_t lowaddr, dma_addr_t highaddr,
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   bus_dma_filter_t *filter, void *filterarg,
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   bus_size_t maxsize, int nsegments,
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag)
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bus_dma_tag_t dmat;
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT);
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dmat == NULL)
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (ENOMEM);
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Linux is very simplistic about DMA memory.  For now don't
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * maintain all specification information.  Once Linux supplies
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * better facilities for doing these operations, or the
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * needs of this particular driver change, we might need to do
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * more here.
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dmat->alignment = alignment;
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dmat->boundary = boundary;
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dmat->maxsize = maxsize;
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*ret_tag = dmat;
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_dma_tag_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat)
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free(dmat, M_DEVBUF);
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_dmamem_alloc(struct ahd_softc *ahd, bus_dma_tag_t dmat, void** vaddr,
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 int flags, bus_dmamap_t *mapp)
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bus_dmamap_t map;
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT);
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (map == NULL)
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (ENOMEM);
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Although we can dma data above 4GB, our
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * "consistent" memory is below 4GB for
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * space efficiency reasons (only need a 4byte
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * address).  For this reason, we have to reset
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * our dma mask when doing allocations.
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd->dev_softc != NULL)
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pci_set_dma_mask(ahd->dev_softc, 0xFFFFFFFF)) {
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_WARNING "aic79xx: No suitable DMA available.\n");
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(map);
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (ENODEV);
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*vaddr = pci_alloc_consistent(ahd->dev_softc,
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      dmat->maxsize, &map->bus_addr);
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd->dev_softc != NULL)
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pci_set_dma_mask(ahd->dev_softc,
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ahd->platform_data->hw_dma_mask)) {
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_WARNING "aic79xx: No suitable DMA available.\n");
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(map);
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (ENODEV);
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*vaddr == NULL)
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (ENOMEM);
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*mapp = map;
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return(0);
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_dmamem_free(struct ahd_softc *ahd, bus_dma_tag_t dmat,
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		void* vaddr, bus_dmamap_t map)
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_free_consistent(ahd->dev_softc, dmat->maxsize,
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    vaddr, map->bus_addr);
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_dmamap_load(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map,
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb,
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		void *cb_arg, int flags)
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Assume for now that this will only be used during
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * initialization and not for per-transaction buffer mapping.
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bus_dma_segment_t stack_sg;
17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	stack_sg.ds_addr = map->bus_addr;
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	stack_sg.ds_len = dmat->maxsize;
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0);
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_dmamap_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map)
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The map may is NULL in our < 2.3.X implementation.
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (map != NULL)
17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free(map, M_DEVBUF);
17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_dmamap_unload(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map)
17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Nothing to do */
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********************* Platform Dependent Functions ***************************/
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Compare "left hand" softc with "right hand" softc, returning:
17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * < 0 - lahd has a lower priority than rahd
17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   0 - Softcs are equal
17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * > 0 - lahd has a higher priority than rahd
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd)
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	value;
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Under Linux, cards are ordered as follows:
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	1) PCI devices that are marked as the boot controller.
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	2) PCI devices with BIOS enabled sorted by bus/slot/func.
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	3) All remaining PCI devices sorted by bus/slot/func.
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	value = (lahd->flags & AHD_BOOT_CHANNEL)
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      - (rahd->flags & AHD_BOOT_CHANNEL);
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (value != 0)
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Controllers set for boot have a *higher* priority */
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (value);
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	value = (lahd->flags & AHD_BIOS_ENABLED)
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      - (rahd->flags & AHD_BIOS_ENABLED);
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (value != 0)
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Controllers with BIOS enabled have a *higher* priority */
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (value);
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Still equal.  Sort by bus/slot/func. */
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (aic79xx_reverse_scan != 0)
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		value = ahd_get_pci_bus(lahd->dev_softc)
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      - ahd_get_pci_bus(rahd->dev_softc);
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		value = ahd_get_pci_bus(rahd->dev_softc)
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      - ahd_get_pci_bus(lahd->dev_softc);
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (value != 0)
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (value);
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (aic79xx_reverse_scan != 0)
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		value = ahd_get_pci_slot(lahd->dev_softc)
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      - ahd_get_pci_slot(rahd->dev_softc);
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		value = ahd_get_pci_slot(rahd->dev_softc)
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      - ahd_get_pci_slot(lahd->dev_softc);
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (value != 0)
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (value);
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	value = rahd->channel - lahd->channel;
18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (value);
18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value)
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((instance >= 0) && (targ >= 0)
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && (instance < NUM_ELEMENTS(aic79xx_tag_info))
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && (targ < AHD_NUM_TARGETS)) {
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		aic79xx_tag_info[instance].tag_commands[targ] = value & 0x1FF;
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bootverbose)
18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf("tag_info[%d:%d] = %d\n", instance, targ, value);
18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_setup_rd_strm_info(u_long arg, int instance, int targ, int32_t value)
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((instance >= 0)
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && (instance < NUM_ELEMENTS(aic79xx_rd_strm_info))) {
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		aic79xx_rd_strm_info[instance] = value & 0xFFFF;
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bootverbose)
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf("rd_strm[%d] = 0x%x\n", instance, value);
18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_setup_dv(u_long arg, int instance, int targ, int32_t value)
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((instance >= 0)
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && (instance < NUM_ELEMENTS(aic79xx_dv_settings))) {
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		aic79xx_dv_settings[instance] = value;
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bootverbose)
18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf("dv[%d] = %d\n", instance, value);
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value)
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((instance >= 0)
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && (instance < NUM_ELEMENTS(aic79xx_iocell_info))) {
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uint8_t *iocell_info;
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iocell_info = (uint8_t*)&aic79xx_iocell_info[instance];
18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iocell_info[index] = value & 0xFFFF;
18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bootverbose)
18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf("iocell[%d:%ld] = %d\n", instance, index, value);
18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_setup_tag_info_global(char *p)
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tags, i, j;
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tags = simple_strtoul(p + 1, NULL, 0) & 0xff;
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printf("Setting Global Tags= %d\n", tags);
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < NUM_ELEMENTS(aic79xx_tag_info); i++) {
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (j = 0; j < AHD_NUM_TARGETS; j++) {
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			aic79xx_tag_info[i].tag_commands[j] = tags;
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle Linux boot parameters. This routine allows for assigning a value
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to a parameter with a ':' between the parameter and the value.
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ie. aic79xx=stpwlev:1,extended
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaic79xx_setup(char *s)
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	i, n;
18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char   *p;
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char   *end;
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static struct {
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		const char *name;
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uint32_t *flag;
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} options[] = {
19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ "extended", &aic79xx_extended },
19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ "no_reset", &aic79xx_no_reset },
19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ "verbose", &aic79xx_verbose },
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ "allow_memio", &aic79xx_allow_memio},
19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ "debug", &ahd_debug },
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ "reverse_scan", &aic79xx_reverse_scan },
19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ "periodic_otag", &aic79xx_periodic_otag },
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ "pci_parity", &aic79xx_pci_parity },
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ "seltime", &aic79xx_seltime },
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ "tag_info", NULL },
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ "global_tag_depth", NULL},
19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ "rd_strm", NULL },
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ "dv", NULL },
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ "slewrate", NULL },
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ "precomp", NULL },
19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ "amplitude", NULL },
19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	};
19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	end = strchr(s, '\0');
19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * XXX ia64 gcc isn't smart enough to know that NUM_ELEMENTS
19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * will never be 0 in this case.
19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	n = 0;
19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((p = strsep(&s, ",.")) != NULL) {
19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (*p == '\0')
19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < NUM_ELEMENTS(options); i++) {
19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			n = strlen(options[i].name);
19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (strncmp(options[i].name, p, n) == 0)
19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (i == NUM_ELEMENTS(options))
19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strncmp(p, "global_tag_depth", n) == 0) {
19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_linux_setup_tag_info_global(p + n);
19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (strncmp(p, "tag_info", n) == 0) {
19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			s = aic_parse_brace_option("tag_info", p + n, end,
19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    2, ahd_linux_setup_tag_info, 0);
19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (strncmp(p, "rd_strm", n) == 0) {
19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			s = aic_parse_brace_option("rd_strm", p + n, end,
19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    1, ahd_linux_setup_rd_strm_info, 0);
19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (strncmp(p, "dv", n) == 0) {
19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			s = aic_parse_brace_option("dv", p + n, end, 1,
19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ahd_linux_setup_dv, 0);
19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (strncmp(p, "slewrate", n) == 0) {
19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			s = aic_parse_brace_option("slewrate",
19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    p + n, end, 1, ahd_linux_setup_iocell_info,
19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    AIC79XX_SLEWRATE_INDEX);
19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (strncmp(p, "precomp", n) == 0) {
19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			s = aic_parse_brace_option("precomp",
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    p + n, end, 1, ahd_linux_setup_iocell_info,
19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    AIC79XX_PRECOMP_INDEX);
19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (strncmp(p, "amplitude", n) == 0) {
19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			s = aic_parse_brace_option("amplitude",
19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    p + n, end, 1, ahd_linux_setup_iocell_info,
19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    AIC79XX_AMPLITUDE_INDEX);
19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (p[n] == ':') {
19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (!strncmp(p, "verbose", n)) {
19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*(options[i].flag) = 1;
19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*(options[i].flag) ^= 0xFFFFFFFF;
19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("aic79xx=", aic79xx_setup);
19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuint32_t aic79xx_verbose;
19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template)
19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char	buf[80];
19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	Scsi_Host *host;
19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char	*new_name;
19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long	s;
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long	target;
19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	template->name = ahd->description;
19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host = scsi_host_alloc(template, sizeof(struct ahd_softc *));
19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (host == NULL)
19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (ENOMEM);
19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*((struct ahd_softc **)host->hostdata) = ahd;
19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_lock(ahd, &s);
20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_assign_lock(host, &ahd->platform_data->spin_lock);
20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#elif AHD_SCSI_HAS_HOST_LOCK != 0
20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->lock = &ahd->platform_data->spin_lock;
20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd->platform_data->host = host;
20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->can_queue = AHD_MAX_QUEUE;
20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->cmd_per_lun = 2;
20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->sg_tablesize = AHD_NSEG;
20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->this_id = ahd->our_id;
20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->irq = ahd->platform_data->irq;
20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->max_id = (ahd->features & AHD_WIDE) ? 16 : 8;
20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->max_lun = AHD_NUM_LUNS;
20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->max_channel = 0;
20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->sg_tablesize = AHD_NSEG;
20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_set_unit(ahd, ahd_linux_next_unit());
20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sprintf(buf, "scsi%d", host->host_no);
20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (new_name != NULL) {
20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strcpy(new_name, buf);
20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_set_name(ahd, new_name);
20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->unique_id = ahd->unit;
20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_set_pci_device(host, ahd->dev_softc);
20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_setup_user_rd_strm_settings(ahd);
20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_initialize_scsi_bus(ahd);
20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_unlock(ahd, &s);
20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd->platform_data->dv_pid = kernel_thread(ahd_linux_dv_thread, ahd, 0);
20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_lock(ahd, &s);
20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd->platform_data->dv_pid < 0) {
20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s: Failed to create DV thread, error= %d\n",
20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       ahd_name(ahd), ahd->platform_data->dv_pid);
20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (-ahd->platform_data->dv_pid);
20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Initially allocate *all* of our linux target objects
20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * so that the DV thread will scan them all in parallel
20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * just after driver initialization.  Any device that
20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * does not exist will have its target object destroyed
20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * by the selection timeout handler.  In the case of a
20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * device that appears after the initial DV scan, async
20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * negotiation will occur for the first command, and DV
20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * will comence should that first command be successful.
20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (target = 0; target < host->max_id; target++) {
20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Skip our own ID.  Some Compaq/HP storage devices
20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * have enclosure management devices that respond to
20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * single bit selection (i.e. selecting ourselves).
20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * It is expected that either an external application
20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * or a modified kernel will be used to probe this
20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * ID if it is appropriate.  To accommodate these
20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * installations, ahc_linux_alloc_target() will allocate
20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * for our ID if asked to do so.
20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (target == ahd->our_id)
20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_alloc_target(ahd, 0, target);
20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_intr_enable(ahd, TRUE);
20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_start_dv(ahd);
20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_unlock(ahd, &s);
20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_add_host(host, &ahd->dev_softc->dev); /* XXX handle failure */
20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_scan_host(host);
20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuint64_t
20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_get_memsize(void)
20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sysinfo si;
20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	si_meminfo(&si);
20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ((uint64_t)si.totalram << PAGE_SHIFT);
20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Find the smallest available unit number to use
20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for a new device.  We don't just use a static
20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * count to handle the "repeated hot-(un)plug"
20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scenario.
20881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_next_unit(void)
20911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_softc *ahd;
20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int unit;
20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unit = 0;
20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsretry:
20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TAILQ_FOREACH(ahd, &ahd_tailq, links) {
20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ahd->unit == unit) {
20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unit++;
21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto retry;
21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (unit);
21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Place the SCSI bus into a known state by either resetting it,
21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or forcing transfer negotiations on the next command to any
21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * target.
21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_initialize_scsi_bus(struct ahd_softc *ahd)
21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int target_id;
21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int numtarg;
21161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	target_id = 0;
21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	numtarg = 0;
21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (aic79xx_no_reset != 0)
21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd->flags &= ~AHD_RESET_BUS_A;
21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ahd->flags & AHD_RESET_BUS_A) != 0)
21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_reset_channel(ahd, 'A', /*initiate_reset*/TRUE);
21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		numtarg = (ahd->features & AHD_WIDE) ? 16 : 8;
21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
21291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Force negotiation to async for all targets that
21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * will not see an initial bus reset.
21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (; target_id < numtarg; target_id++) {
21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct ahd_devinfo devinfo;
21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct ahd_initiator_tinfo *tinfo;
21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct ahd_tmode_tstate *tstate;
21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    target_id, &tstate);
21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_compile_devinfo(&devinfo, ahd->our_id, target_id,
21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    CAM_LUN_WILDCARD, 'A', ROLE_INITIATOR);
21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_update_neg_request(ahd, &devinfo, tstate,
21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       tinfo, AHD_NEG_ALWAYS);
21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Give the bus some time to recover */
21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ahd->flags & AHD_RESET_BUS_A) != 0) {
21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_freeze_simq(ahd);
21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		init_timer(&ahd->platform_data->reset_timer);
21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd->platform_data->reset_timer.data = (u_long)ahd;
21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd->platform_data->reset_timer.expires =
21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    jiffies + (AIC79XX_RESET_DELAY * HZ)/1000;
21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd->platform_data->reset_timer.function =
21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (ahd_linux_callback_t *)ahd_release_simq;
21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		add_timer(&ahd->platform_data->reset_timer);
21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg)
21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd->platform_data =
21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    malloc(sizeof(struct ahd_platform_data), M_DEVBUF, M_NOWAIT);
21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd->platform_data == NULL)
21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (ENOMEM);
21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data));
21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TAILQ_INIT(&ahd->platform_data->completeq);
21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TAILQ_INIT(&ahd->platform_data->device_runq);
21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd->platform_data->irq = AHD_LINUX_NOIRQ;
21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd->platform_data->hw_dma_mask = 0xFFFFFFFF;
21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_lockinit(ahd);
21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_done_lockinit(ahd);
21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer(&ahd->platform_data->completeq_timer);
21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd->platform_data->completeq_timer.data = (u_long)ahd;
21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd->platform_data->completeq_timer.function =
21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (ahd_linux_callback_t *)ahd_linux_thread_run_complete_queue;
21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_MUTEX_LOCKED(&ahd->platform_data->eh_sem);
21761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_MUTEX_LOCKED(&ahd->platform_data->dv_sem);
21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_MUTEX_LOCKED(&ahd->platform_data->dv_cmd_sem);
21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_setup_runq_tasklet(ahd);
21791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd->seltime = (aic79xx_seltime & 0x3) << 4;
21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_platform_free(struct ahd_softc *ahd)
21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_linux_target *targ;
21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_linux_device *dev;
21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, j;
21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd->platform_data != NULL) {
21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		del_timer_sync(&ahd->platform_data->completeq_timer);
21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_kill_dv_thread(ahd);
21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_teardown_runq_tasklet(ahd);
21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ahd->platform_data->host != NULL) {
21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scsi_remove_host(ahd->platform_data->host);
21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scsi_host_put(ahd->platform_data->host);
21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* destroy all of the device and target objects */
22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < AHD_NUM_TARGETS; i++) {
22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			targ = ahd->platform_data->targets[i];
22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (targ != NULL) {
22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Keep target around through the loop. */
22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->refcount++;
22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				for (j = 0; j < AHD_NUM_LUNS; j++) {
22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (targ->devices[j] == NULL)
22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						continue;
22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dev = targ->devices[j];
22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ahd_linux_free_device(ahd, dev);
22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/*
22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * Forcibly free the target now that
22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * all devices are gone.
22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ahd_linux_free_target(ahd, targ);
22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ahd->platform_data->irq != AHD_LINUX_NOIRQ)
22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			free_irq(ahd->platform_data->irq, ahd);
22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ahd->tags[0] == BUS_SPACE_PIO
22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && ahd->bshs[0].ioport != 0)
22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			release_region(ahd->bshs[0].ioport, 256);
22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ahd->tags[1] == BUS_SPACE_PIO
22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && ahd->bshs[1].ioport != 0)
22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			release_region(ahd->bshs[1].ioport, 256);
22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ahd->tags[0] == BUS_SPACE_MEMIO
22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && ahd->bshs[0].maddr != NULL) {
22321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			iounmap(ahd->bshs[0].maddr);
22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			release_mem_region(ahd->platform_data->mem_busaddr,
22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   0x1000);
22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    		/*
22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * In 2.4 we detach from the scsi midlayer before the PCI
22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * layer invokes our remove callback.  No per-instance
22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * detach is provided, so we must reach inside the PCI
22411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * subsystem's internals and detach our driver manually.
22421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
22431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ahd->dev_softc != NULL)
22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd->dev_softc->driver = NULL;
22451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free(ahd->platform_data, M_DEVBUF);
22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_platform_init(struct ahd_softc *ahd)
22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Lookup and commit any modified IO Cell options.
22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd->unit < NUM_ELEMENTS(aic79xx_iocell_info)) {
22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct ahd_linux_iocell_opts *iocell_opts;
22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iocell_opts = &aic79xx_iocell_info[ahd->unit];
22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (iocell_opts->precomp != AIC79XX_DEFAULT_PRECOMP)
22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_PRECOMP(ahd, iocell_opts->precomp);
22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (iocell_opts->slewrate != AIC79XX_DEFAULT_SLEWRATE)
22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_SLEWRATE(ahd, iocell_opts->slewrate);
22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (iocell_opts->amplitude != AIC79XX_DEFAULT_AMPLITUDE)
22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_AMPLITUDE(ahd, iocell_opts->amplitude);
22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb)
22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_platform_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb),
22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				SCB_GET_CHANNEL(ahd, scb),
22751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				SCB_GET_LUN(scb), SCB_LIST_NULL,
22761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ROLE_UNKNOWN, CAM_REQUEUE_REQ);
22771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      ahd_queue_alg alg)
22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_linux_device *dev;
22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int was_queuing;
22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int now_queuing;
22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = ahd_linux_get_device(ahd, devinfo->channel - 'A',
22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   devinfo->target,
22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   devinfo->lun, /*alloc*/FALSE);
22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev == NULL)
22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	was_queuing = dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED);
22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (alg) {
22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case AHD_QUEUE_NONE:
22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		now_queuing = 0;
22971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
22981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case AHD_QUEUE_BASIC:
22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		now_queuing = AHD_DEV_Q_BASIC;
23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case AHD_QUEUE_TAGGED:
23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		now_queuing = AHD_DEV_Q_TAGGED;
23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) == 0
23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && (was_queuing != now_queuing)
23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && (dev->active != 0)) {
23081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->flags |= AHD_DEV_FREEZE_TIL_EMPTY;
23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->qfrozen++;
23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->flags &= ~(AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED|AHD_DEV_PERIODIC_OTAG);
23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (now_queuing) {
23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u_int usertags;
23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usertags = ahd_linux_user_tagdepth(ahd, devinfo);
23171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!was_queuing) {
23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
23191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Start out agressively and allow our
23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * dynamic queue depth algorithm to take
23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * care of the rest.
23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->maxtags = usertags;
23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->openings = dev->maxtags - dev->active;
23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
23261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dev->maxtags == 0) {
23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Queueing is disabled by the user.
23291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
23301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->openings = 1;
23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (alg == AHD_QUEUE_TAGGED) {
23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->flags |= AHD_DEV_Q_TAGGED;
23331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (aic79xx_periodic_otag != 0)
23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev->flags |= AHD_DEV_PERIODIC_OTAG;
23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->flags |= AHD_DEV_Q_BASIC;
23371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* We can only have one opening. */
23391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->maxtags = 0;
23401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->openings =  1 - dev->active;
23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
23431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->scsi_device != NULL) {
23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) {
23451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case AHD_DEV_Q_BASIC:
23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scsi_adjust_queue_depth(dev->scsi_device,
23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						MSG_SIMPLE_TASK,
23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						dev->openings + dev->active);
23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case AHD_DEV_Q_TAGGED:
23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scsi_adjust_queue_depth(dev->scsi_device,
23521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						MSG_ORDERED_TASK,
23531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						dev->openings + dev->active);
23541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
23551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
23561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
23571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * We allow the OS to queue 2 untagged transactions to
23581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * us at any time even though we can only execute them
23591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * serially on the controller/device.  This should
23601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * remove some latency.
23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
23621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scsi_adjust_queue_depth(dev->scsi_device,
23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						/*NON-TAGGED*/0,
23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						/*queue depth*/2);
23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
23661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
23691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel,
23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int lun, u_int tag, role_t role, uint32_t status)
23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int targ;
23761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int maxtarg;
23771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int maxlun;
23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int clun;
23791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count;
23801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tag != SCB_LIST_NULL)
23821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ = 0;
23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (target != CAM_TARGET_WILDCARD) {
23861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		targ = target;
23871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		maxtarg = targ + 1;
23881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
23891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		maxtarg = (ahd->features & AHD_WIDE) ? 16 : 8;
23901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clun = 0;
23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lun != CAM_LUN_WILDCARD) {
23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		clun = lun;
23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		maxlun = clun + 1;
23951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
23961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		maxlun = AHD_NUM_LUNS;
23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count = 0;
24001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (; targ < maxtarg; targ++) {
24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (; clun < maxlun; clun++) {
24031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct ahd_linux_device *dev;
24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct ahd_busyq *busyq;
24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct ahd_cmd *acmd;
24061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev = ahd_linux_get_device(ahd, /*chan*/0, targ,
24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   clun, /*alloc*/FALSE);
24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (dev == NULL)
24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			busyq = &dev->busyq;
24131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while ((acmd = TAILQ_FIRST(busyq)) != NULL) {
24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				Scsi_Cmnd *cmd;
24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cmd = &acmd_scsi_cmd(acmd);
24171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				TAILQ_REMOVE(busyq, acmd,
24181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     acmd_links.tqe);
24191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				count++;
24201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cmd->result = status << 16;
24211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ahd_linux_queue_cmd_complete(ahd, cmd);
24221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
24231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
24241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
24251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (count);
24271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_thread_run_complete_queue(struct ahd_softc *ahd)
24311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
24321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long flags;
24331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_lock(ahd, &flags);
24351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer(&ahd->platform_data->completeq_timer);
24361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd->platform_data->flags &= ~AHD_RUN_CMPLT_Q_TIMER;
24371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_run_complete_queue(ahd);
24381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_unlock(ahd, &flags);
24391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
24421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_start_dv(struct ahd_softc *ahd)
24431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
24441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
24461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Freeze the simq and signal ahd_linux_queue to not let any
24471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * more commands through
24481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
24491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ahd->platform_data->flags & AHD_DV_ACTIVE) == 0) {
24501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
24511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ahd_debug & AHD_SHOW_DV)
24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf("%s: Starting DV\n", ahd_name(ahd));
24531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
24541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd->platform_data->flags |= AHD_DV_ACTIVE;
24561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_freeze_simq(ahd);
24571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Wake up the DV kthread */
24591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up(&ahd->platform_data->dv_sem);
24601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
24611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
24641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_dv_thread(void *data)
24651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
24661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_softc *ahd;
24671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	target;
24681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long	s;
24691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd = (struct ahd_softc *)data;
24711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
24731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_debug & AHD_SHOW_DV)
24741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("In DV Thread\n");
24751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
24761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
24781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Complete thread creation.
24791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
24801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lock_kernel();
24811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60)
24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
24831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Don't care about any signals.
24841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
24851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	siginitsetinv(&current->blocked, 0);
24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	daemonize();
24881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sprintf(current->comm, "ahd_dv_%d", ahd->unit);
24891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
24901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	daemonize("ahd_dv_%d", ahd->unit);
24911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current->flags |= PF_FREEZE;
24921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unlock_kernel();
24941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (1) {
24961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
24971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Use down_interruptible() rather than down() to
24981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * avoid inclusion in the load average.
24991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
25001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		down_interruptible(&ahd->platform_data->dv_sem);
25011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Check to see if we've been signaled to exit */
25031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_lock(ahd, &s);
25041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((ahd->platform_data->flags & AHD_DV_SHUTDOWN) != 0) {
25051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_unlock(ahd, &s);
25061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
25071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
25081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_unlock(ahd, &s);
25091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
25111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ahd_debug & AHD_SHOW_DV)
25121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf("%s: Beginning Domain Validation\n",
25131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       ahd_name(ahd));
25141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
25151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
25171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Wait for any pending commands to drain before proceeding.
25181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
25191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_lock(ahd, &s);
25201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (LIST_FIRST(&ahd->pending_scbs) != NULL) {
25211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_EMPTY;
25221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_unlock(ahd, &s);
25231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			down_interruptible(&ahd->platform_data->dv_sem);
25241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_lock(ahd, &s);
25251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
25261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
25281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Wait for the SIMQ to be released so that DV is the
25291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * only reason the queue is frozen.
25301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
25311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (AHD_DV_SIMQ_FROZEN(ahd) == 0) {
25321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_RELEASE;
25331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_unlock(ahd, &s);
25341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			down_interruptible(&ahd->platform_data->dv_sem);
25351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_lock(ahd, &s);
25361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
25371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_unlock(ahd, &s);
25381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (target = 0; target < AHD_NUM_TARGETS; target++)
25401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_linux_dv_target(ahd, target);
25411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_lock(ahd, &s);
25431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd->platform_data->flags &= ~AHD_DV_ACTIVE;
25441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_unlock(ahd, &s);
25451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
25471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Release the SIMQ so that normal commands are
25481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * allowed to continue on the bus.
25491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
25501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_release_simq(ahd);
25511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
25521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&ahd->platform_data->eh_sem);
25531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
25541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
25551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
25571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_kill_dv_thread(struct ahd_softc *ahd)
25581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
25591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long s;
25601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_lock(ahd, &s);
25621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd->platform_data->dv_pid != 0) {
25631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd->platform_data->flags |= AHD_DV_SHUTDOWN;
25641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_unlock(ahd, &s);
25651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up(&ahd->platform_data->dv_sem);
25661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
25681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Use the eh_sem as an indicator that the
25691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * dv thread is exiting.  Note that the dv
25701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * thread must still return after performing
25711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the up on our semaphore before it has
25721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * completely exited this module.  Unfortunately,
25731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * there seems to be no easy way to wait for the
25741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * exit of a thread for which you are not the
25751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * parent (dv threads are parented by init).
25761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Cross your fingers...
25771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
25781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		down(&ahd->platform_data->eh_sem);
25791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
25811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Mark the dv thread as already dead.  This
25821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * avoids attempting to kill it a second time.
25831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * This is necessary because we must kill the
25841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * DV thread before calling ahd_free() in the
25851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * module shutdown case to avoid bogus locking
25861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * in the SCSI mid-layer, but we ahd_free() is
25871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * called without killing the DV thread in the
25881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * instance detach case, so ahd_platform_free()
25891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * calls us again to verify that the DV thread
25901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * is dead.
25911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
25921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd->platform_data->dv_pid = 0;
25931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
25941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_unlock(ahd, &s);
25951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
25961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
25971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AHD_LINUX_DV_INQ_SHORT_LEN	36
25991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AHD_LINUX_DV_INQ_LEN		256
26001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AHD_LINUX_DV_TIMEOUT		(HZ / 4)
26011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AHD_SET_DV_STATE(ahd, targ, newstate) \
26031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_set_dv_state(ahd, targ, newstate, __LINE__)
26041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline void
26061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_set_dv_state(struct ahd_softc *ahd, struct ahd_linux_target *targ,
26071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 ahd_dv_state newstate, u_int line)
26081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_dv_state oldstate;
26101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	oldstate = targ->dv_state;
26121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
26131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_debug & AHD_SHOW_DV)
26141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s:%d: Going from state %d to state %d\n",
26151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       ahd_name(ahd), line, oldstate, newstate);
26161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
26171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (oldstate == newstate)
26191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		targ->dv_state_retry++;
26201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
26211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		targ->dv_state_retry = 0;
26221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ->dv_state = newstate;
26231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
26241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
26261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_dv_target(struct ahd_softc *ahd, u_int target_offset)
26271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	 ahd_devinfo devinfo;
26291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	 ahd_linux_target *targ;
26301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	 scsi_cmnd *cmd;
26311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	 scsi_device *scsi_dev;
26321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	 scsi_sense_data *sense;
26331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t *buffer;
26341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long	 s;
26351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	 timeout;
26361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	 echo_size;
26371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sense = NULL;
26391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buffer = NULL;
26401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	echo_size = 0;
26411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_lock(ahd, &s);
26421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ = ahd->platform_data->targets[target_offset];
26431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ == NULL || (targ->flags & AHD_DV_REQUIRED) == 0) {
26441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_unlock(ahd, &s);
26451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
26461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
26471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_compile_devinfo(&devinfo, ahd->our_id, targ->target, /*lun*/0,
26481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    targ->channel + 'A', ROLE_INITIATOR);
26491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
26501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_debug & AHD_SHOW_DV) {
26511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_print_devinfo(ahd, &devinfo);
26521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("Performing DV\n");
26531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
26541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
26551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_unlock(ahd, &s);
26571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd = malloc(sizeof(struct scsi_cmnd), M_DEVBUF, M_WAITOK);
26591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_dev = malloc(sizeof(struct scsi_device), M_DEVBUF, M_WAITOK);
26601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_dev->host = ahd->platform_data->host;
26611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_dev->id = devinfo.target;
26621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_dev->lun = devinfo.lun;
26631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_dev->channel = devinfo.channel - 'A';
26641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd->platform_data->dv_scsi_dev = scsi_dev;
26651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_INQ_SHORT_ASYNC);
26671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (targ->dv_state != AHD_DV_STATE_EXIT) {
26691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timeout = AHD_LINUX_DV_TIMEOUT;
26701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (targ->dv_state) {
26711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case AHD_DV_STATE_INQ_SHORT_ASYNC:
26721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case AHD_DV_STATE_INQ_ASYNC:
26731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case AHD_DV_STATE_INQ_ASYNC_VERIFY:
26741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
26751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Set things to async narrow to reduce the
26761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * chance that the INQ will fail.
26771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
26781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_lock(ahd, &s);
26791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_set_syncrate(ahd, &devinfo, 0, 0, 0,
26801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 AHD_TRANS_GOAL, /*paused*/FALSE);
26811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
26821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      AHD_TRANS_GOAL, /*paused*/FALSE);
26831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_unlock(ahd, &s);
26841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			timeout = 10 * HZ;
26851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			targ->flags &= ~AHD_INQ_VALID;
26861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FALLTHROUGH */
26871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case AHD_DV_STATE_INQ_VERIFY:
26881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
26891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u_int inq_len;
26901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (targ->dv_state == AHD_DV_STATE_INQ_SHORT_ASYNC)
26921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				inq_len = AHD_LINUX_DV_INQ_SHORT_LEN;
26931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
26941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				inq_len = targ->inq_data->additional_length + 5;
26951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_linux_dv_inq(ahd, cmd, &devinfo, targ, inq_len);
26961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
26971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
26981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case AHD_DV_STATE_TUR:
26991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case AHD_DV_STATE_BUSY:
27001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			timeout = 5 * HZ;
27011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_linux_dv_tur(ahd, cmd, &devinfo);
27021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
27031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case AHD_DV_STATE_REBD:
27041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_linux_dv_rebd(ahd, cmd, &devinfo, targ);
27051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
27061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case AHD_DV_STATE_WEB:
27071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_linux_dv_web(ahd, cmd, &devinfo, targ);
27081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
27091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case AHD_DV_STATE_REB:
27111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_linux_dv_reb(ahd, cmd, &devinfo, targ);
27121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
27131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case AHD_DV_STATE_SU:
27151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_linux_dv_su(ahd, cmd, &devinfo, targ);
27161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			timeout = 50 * HZ;
27171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
27181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
27201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_print_devinfo(ahd, &devinfo);
27211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf("Unknown DV state %d\n", targ->dv_state);
27221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
27231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
27241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Queue the command and wait for it to complete */
27261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Abuse eh_timeout in the scsi_cmnd struct for our purposes */
27271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		init_timer(&cmd->eh_timeout);
27281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
27291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
27301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
27311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * All of the printfs during negotiation
27321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * really slow down the negotiation.
27331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Add a bit of time just to be safe.
27341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
27351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			timeout += HZ;
27361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
27371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		scsi_add_timer(cmd, timeout, ahd_linux_dv_timeout);
27381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
27391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * In 2.5.X, it is assumed that all calls from the
27401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * "midlayer" (which we are emulating) will have the
27411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * ahd host lock held.  For other kernels, the
27421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * io_request_lock must be held.
27431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
27441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if AHD_SCSI_HAS_HOST_LOCK != 0
27451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_lock(ahd, &s);
27461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
27471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irqsave(&io_request_lock, s);
27481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
27491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_queue(cmd, ahd_linux_dv_complete);
27501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if AHD_SCSI_HAS_HOST_LOCK != 0
27511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_unlock(ahd, &s);
27521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
27531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&io_request_lock, s);
27541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
27551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		down_interruptible(&ahd->platform_data->dv_cmd_sem);
27561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
27571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Wait for the SIMQ to be released so that DV is the
27581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * only reason the queue is frozen.
27591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
27601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_lock(ahd, &s);
27611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (AHD_DV_SIMQ_FROZEN(ahd) == 0) {
27621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_RELEASE;
27631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_unlock(ahd, &s);
27641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			down_interruptible(&ahd->platform_data->dv_sem);
27651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_lock(ahd, &s);
27661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
27671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_unlock(ahd, &s);
27681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_dv_transition(ahd, cmd, &devinfo, targ);
27701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
27711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
27731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((targ->flags & AHD_INQ_VALID) != 0
27741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && ahd_linux_get_device(ahd, devinfo.channel - 'A',
27751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 devinfo.target, devinfo.lun,
27761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 /*alloc*/FALSE) == NULL) {
27771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
27781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * The DV state machine failed to configure this device.
27791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * This is normal if DV is disabled.  Since we have inquiry
27801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * data, filter it and use the "optimistic" negotiation
27811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * parameters found in the inquiry string.
27821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
27831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_filter_inquiry(ahd, &devinfo);
27841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((targ->flags & (AHD_BASIC_DV|AHD_ENHANCED_DV)) != 0) {
27851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_print_devinfo(ahd, &devinfo);
27861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf("DV failed to configure device.  "
27871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "Please file a bug report against "
27881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "this driver.\n");
27891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
27901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
27911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cmd != NULL)
27931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free(cmd, M_DEVBUF);
27941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd->platform_data->dv_scsi_dev != NULL) {
27961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free(ahd->platform_data->dv_scsi_dev, M_DEVBUF);
27971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd->platform_data->dv_scsi_dev = NULL;
27981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
27991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_lock(ahd, &s);
28011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->dv_buffer != NULL) {
28021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free(targ->dv_buffer, M_DEVBUF);
28031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		targ->dv_buffer = NULL;
28041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
28051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->dv_buffer1 != NULL) {
28061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free(targ->dv_buffer1, M_DEVBUF);
28071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		targ->dv_buffer1 = NULL;
28081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
28091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ->flags &= ~AHD_DV_REQUIRED;
28101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->refcount == 0)
28111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_free_target(ahd, targ);
28121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_unlock(ahd, &s);
28131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
28141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline int
28161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_dv_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
28171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
28181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long s;
28191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
28201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_lock(ahd, &s);
28221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = ahd_linux_fallback(ahd, devinfo);
28231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_unlock(ahd, &s);
28241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (retval);
28261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
28271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
28291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_dv_transition(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
28301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct ahd_devinfo *devinfo,
28311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct ahd_linux_target *targ)
28321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
28331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int32_t status;
28341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = aic_error_action(cmd, targ->inq_data,
28361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  ahd_cmd_get_transaction_status(cmd),
28371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  ahd_cmd_get_scsi_status(cmd));
28381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
28411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_debug & AHD_SHOW_DV) {
28421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_print_devinfo(ahd, devinfo);
28431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("Entering ahd_linux_dv_transition, state= %d, "
28441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "status= 0x%x, cmd->result= 0x%x\n", targ->dv_state,
28451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       status, cmd->result);
28461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
28471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
28481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (targ->dv_state) {
28501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case AHD_DV_STATE_INQ_SHORT_ASYNC:
28511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case AHD_DV_STATE_INQ_ASYNC:
28521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (status & SS_MASK) {
28531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_NOP:
28541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
28551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, targ->dv_state+1);
28561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
28571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
28581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_INQ_REFRESH:
28591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ,
28601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 AHD_DV_STATE_INQ_SHORT_ASYNC);
28611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
28621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_TUR:
28631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_RETRY:
28641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
28651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_cmd_get_transaction_status(cmd)
28661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 == CAM_REQUEUE_REQ)
28671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->dv_state_retry--;
28681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((status & SS_ERRMASK) == EBUSY)
28691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY);
28701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (targ->dv_state_retry < 10)
28711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
28721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FALLTHROUGH */
28731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
28741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
28751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
28761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_debug & AHD_SHOW_DV) {
28771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ahd_print_devinfo(ahd, devinfo);
28781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printf("Failed DV inquiry, skipping\n");
28791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
28801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
28811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
28821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
28831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
28841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case AHD_DV_STATE_INQ_ASYNC_VERIFY:
28851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (status & SS_MASK) {
28861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_NOP:
28871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
28881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u_int xportflags;
28891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u_int spi3data;
28901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (memcmp(targ->inq_data, targ->dv_buffer,
28921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   AHD_LINUX_DV_INQ_LEN) != 0) {
28931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/*
28941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * Inquiry data must have changed.
28951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * Try from the top again.
28961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
28971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				AHD_SET_DV_STATE(ahd, targ,
28981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						 AHD_DV_STATE_INQ_SHORT_ASYNC);
28991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
29001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
29011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, targ->dv_state+1);
29031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			targ->flags |= AHD_INQ_VALID;
29041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_linux_user_dv_setting(ahd) == 0)
29051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
29061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			xportflags = targ->inq_data->flags;
29081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((xportflags & (SID_Sync|SID_WBus16)) == 0)
29091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
29101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spi3data = targ->inq_data->spi3data;
29121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (spi3data & SID_SPI_CLOCK_DT_ST) {
29131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			default:
29141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case SID_SPI_CLOCK_ST:
29151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Assume only basic DV is supported. */
29161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->flags |= AHD_BASIC_DV;
29171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
29181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case SID_SPI_CLOCK_DT:
29191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case SID_SPI_CLOCK_DT_ST:
29201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->flags |= AHD_ENHANCED_DV;
29211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
29221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
29231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
29241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
29251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_INQ_REFRESH:
29261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ,
29271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 AHD_DV_STATE_INQ_SHORT_ASYNC);
29281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
29291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_TUR:
29301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_RETRY:
29311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
29321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_cmd_get_transaction_status(cmd)
29331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 == CAM_REQUEUE_REQ)
29341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->dv_state_retry--;
29351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((status & SS_ERRMASK) == EBUSY)
29371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY);
29381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (targ->dv_state_retry < 10)
29391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
29401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FALLTHROUGH */
29411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
29421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
29431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
29441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_debug & AHD_SHOW_DV) {
29451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ahd_print_devinfo(ahd, devinfo);
29461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printf("Failed DV inquiry, skipping\n");
29471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
29481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
29491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
29501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
29511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
29521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case AHD_DV_STATE_INQ_VERIFY:
29531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (status & SS_MASK) {
29541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_NOP:
29551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
29561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (memcmp(targ->inq_data, targ->dv_buffer,
29581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   AHD_LINUX_DV_INQ_LEN) == 0) {
29591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
29601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
29611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
29621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
29641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_debug & AHD_SHOW_DV) {
29651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				int i;
29661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ahd_print_devinfo(ahd, devinfo);
29681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printf("Inquiry buffer mismatch:");
29691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				for (i = 0; i < AHD_LINUX_DV_INQ_LEN; i++) {
29701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if ((i & 0xF) == 0)
29711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						printf("\n        ");
29721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printf("0x%x:0x0%x ",
29731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       ((uint8_t *)targ->inq_data)[i],
29741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       targ->dv_buffer[i]);
29751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
29761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printf("\n");
29771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
29781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
29791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_linux_dv_fallback(ahd, devinfo) != 0) {
29811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
29821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
29831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
29841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
29851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Do not count "falling back"
29861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * against our retries.
29871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
29881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			targ->dv_state_retry = 0;
29891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
29901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
29911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
29921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_INQ_REFRESH:
29931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ,
29941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 AHD_DV_STATE_INQ_SHORT_ASYNC);
29951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
29961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_TUR:
29971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_RETRY:
29981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
29991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_cmd_get_transaction_status(cmd)
30001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 == CAM_REQUEUE_REQ) {
30011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->dv_state_retry--;
30021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if ((status & SSQ_FALLBACK) != 0) {
30031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (ahd_linux_dv_fallback(ahd, devinfo) != 0) {
30041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					AHD_SET_DV_STATE(ahd, targ,
30051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							 AHD_DV_STATE_EXIT);
30061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
30071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
30081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/*
30091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * Do not count "falling back"
30101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * against our retries.
30111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
30121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->dv_state_retry = 0;
30131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if ((status & SS_ERRMASK) == EBUSY)
30141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY);
30151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (targ->dv_state_retry < 10)
30161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
30171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FALLTHROUGH */
30181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
30191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
30201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
30211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_debug & AHD_SHOW_DV) {
30221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ahd_print_devinfo(ahd, devinfo);
30231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printf("Failed DV inquiry, skipping\n");
30241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
30251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
30261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
30271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
30281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
30291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case AHD_DV_STATE_TUR:
30311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (status & SS_MASK) {
30321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_NOP:
30331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((targ->flags & AHD_BASIC_DV) != 0) {
30341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ahd_linux_filter_inquiry(ahd, devinfo);
30351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				AHD_SET_DV_STATE(ahd, targ,
30361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						 AHD_DV_STATE_INQ_VERIFY);
30371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if ((targ->flags & AHD_ENHANCED_DV) != 0) {
30381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_REBD);
30391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
30401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
30411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
30421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
30431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_RETRY:
30441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_TUR:
30451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((status & SS_ERRMASK) == EBUSY) {
30461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY);
30471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
30481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
30491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
30501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_cmd_get_transaction_status(cmd)
30511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 == CAM_REQUEUE_REQ) {
30521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->dv_state_retry--;
30531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if ((status & SSQ_FALLBACK) != 0) {
30541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (ahd_linux_dv_fallback(ahd, devinfo) != 0) {
30551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					AHD_SET_DV_STATE(ahd, targ,
30561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							 AHD_DV_STATE_EXIT);
30571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
30581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
30591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/*
30601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * Do not count "falling back"
30611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * against our retries.
30621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
30631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->dv_state_retry = 0;
30641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
30651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (targ->dv_state_retry >= 10) {
30661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
30671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (ahd_debug & AHD_SHOW_DV) {
30681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ahd_print_devinfo(ahd, devinfo);
30691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printf("DV TUR reties exhausted\n");
30701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
30711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
30721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
30731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
30741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
30751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status & SSQ_DELAY)
30761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ssleep(1);
30771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
30791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_START:
30801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_SU);
30811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
30821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_INQ_REFRESH:
30831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ,
30841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 AHD_DV_STATE_INQ_SHORT_ASYNC);
30851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
30861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
30871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
30881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
30891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
30901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
30911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case AHD_DV_STATE_REBD:
30931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (status & SS_MASK) {
30941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_NOP:
30951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
30961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			uint32_t echo_size;
30971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_WEB);
30991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			echo_size = scsi_3btoul(&targ->dv_buffer[1]);
31001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			echo_size &= 0x1FFF;
31011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
31021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_debug & AHD_SHOW_DV) {
31031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ahd_print_devinfo(ahd, devinfo);
31041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printf("Echo buffer size= %d\n", echo_size);
31051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
31061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
31071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (echo_size == 0) {
31081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
31091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
31101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
31111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Generate the buffer pattern */
31131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			targ->dv_echo_size = echo_size;
31141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_linux_generate_dv_pattern(targ);
31151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
31161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Setup initial negotiation values.
31171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
31181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_linux_filter_inquiry(ahd, devinfo);
31191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
31201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
31211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_INQ_REFRESH:
31221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ,
31231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 AHD_DV_STATE_INQ_SHORT_ASYNC);
31241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
31251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_RETRY:
31261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
31271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_cmd_get_transaction_status(cmd)
31281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 == CAM_REQUEUE_REQ)
31291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->dv_state_retry--;
31301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (targ->dv_state_retry <= 10)
31311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
31321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
31331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_debug & AHD_SHOW_DV) {
31341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ahd_print_devinfo(ahd, devinfo);
31351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printf("DV REBD reties exhausted\n");
31361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
31371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
31381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FALLTHROUGH */
31391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_FATAL:
31401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
31411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
31421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Setup initial negotiation values
31431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * and try level 1 DV.
31441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
31451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_linux_filter_inquiry(ahd, devinfo);
31461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_INQ_VERIFY);
31471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			targ->dv_echo_size = 0;
31481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
31491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
31501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
31511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case AHD_DV_STATE_WEB:
31531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (status & SS_MASK) {
31541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_NOP:
31551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_REB);
31561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
31571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_INQ_REFRESH:
31581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ,
31591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 AHD_DV_STATE_INQ_SHORT_ASYNC);
31601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
31611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_RETRY:
31621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
31631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_cmd_get_transaction_status(cmd)
31641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 == CAM_REQUEUE_REQ) {
31651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->dv_state_retry--;
31661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if ((status & SSQ_FALLBACK) != 0) {
31671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (ahd_linux_dv_fallback(ahd, devinfo) != 0) {
31681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					AHD_SET_DV_STATE(ahd, targ,
31691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							 AHD_DV_STATE_EXIT);
31701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
31711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
31721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/*
31731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * Do not count "falling back"
31741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * against our retries.
31751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
31761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->dv_state_retry = 0;
31771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
31781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (targ->dv_state_retry <= 10)
31791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
31801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FALLTHROUGH */
31811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
31821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_debug & AHD_SHOW_DV) {
31831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ahd_print_devinfo(ahd, devinfo);
31841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printf("DV WEB reties exhausted\n");
31851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
31861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
31871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
31881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
31891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
31901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
31911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
31921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case AHD_DV_STATE_REB:
31941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (status & SS_MASK) {
31951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_NOP:
31961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (memcmp(targ->dv_buffer, targ->dv_buffer1,
31971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   targ->dv_echo_size) != 0) {
31981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (ahd_linux_dv_fallback(ahd, devinfo) != 0)
31991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					AHD_SET_DV_STATE(ahd, targ,
32001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							 AHD_DV_STATE_EXIT);
32011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
32021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					AHD_SET_DV_STATE(ahd, targ,
32031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							 AHD_DV_STATE_WEB);
32041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
32051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
32061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (targ->dv_buffer != NULL) {
32081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				free(targ->dv_buffer, M_DEVBUF);
32091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->dv_buffer = NULL;
32101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
32111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (targ->dv_buffer1 != NULL) {
32121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				free(targ->dv_buffer1, M_DEVBUF);
32131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->dv_buffer1 = NULL;
32141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
32151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
32161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
32171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_INQ_REFRESH:
32181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ,
32191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 AHD_DV_STATE_INQ_SHORT_ASYNC);
32201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
32211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_RETRY:
32221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
32231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_cmd_get_transaction_status(cmd)
32241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 == CAM_REQUEUE_REQ) {
32251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->dv_state_retry--;
32261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if ((status & SSQ_FALLBACK) != 0) {
32271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (ahd_linux_dv_fallback(ahd, devinfo) != 0) {
32281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					AHD_SET_DV_STATE(ahd, targ,
32291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							 AHD_DV_STATE_EXIT);
32301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
32311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
32321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_WEB);
32331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
32341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (targ->dv_state_retry <= 10) {
32351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((status & (SSQ_DELAY_RANDOM|SSQ_DELAY))!= 0)
32361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					msleep(ahd->our_id*1000/10);
32371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
32381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
32391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
32401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_debug & AHD_SHOW_DV) {
32411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ahd_print_devinfo(ahd, devinfo);
32421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printf("DV REB reties exhausted\n");
32431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
32441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
32451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FALLTHROUGH */
32461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
32471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
32481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
32491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
32501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
32511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case AHD_DV_STATE_SU:
32531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (status & SS_MASK) {
32541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_NOP:
32551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_INQ_REFRESH:
32561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ,
32571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 AHD_DV_STATE_INQ_SHORT_ASYNC);
32581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
32591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
32601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
32611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
32621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
32631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
32641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case AHD_DV_STATE_BUSY:
32661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (status & SS_MASK) {
32671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_NOP:
32681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_INQ_REFRESH:
32691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ,
32701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 AHD_DV_STATE_INQ_SHORT_ASYNC);
32711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
32721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_TUR:
32731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SS_RETRY:
32741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
32751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_cmd_get_transaction_status(cmd)
32761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 == CAM_REQUEUE_REQ) {
32771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->dv_state_retry--;
32781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (targ->dv_state_retry < 60) {
32791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((status & SSQ_DELAY) != 0)
32801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ssleep(1);
32811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
32821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
32831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (ahd_debug & AHD_SHOW_DV) {
32841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ahd_print_devinfo(ahd, devinfo);
32851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printf("DV BUSY reties exhausted\n");
32861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
32871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
32881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
32891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
32901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
32911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
32921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
32931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
32941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
32951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
32961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
32981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s: Invalid DV completion state %d\n", ahd_name(ahd),
32991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       targ->dv_state);
33001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
33011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
33021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
33031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
33041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
33061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_dv_fill_cmd(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
33071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      struct ahd_devinfo *devinfo)
33081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
33091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(cmd, 0, sizeof(struct scsi_cmnd));
33101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->device = ahd->platform_data->dv_scsi_dev;
33111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->scsi_done = ahd_linux_dv_complete;
33121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
33131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
33151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Synthesize an inquiry command.  On the return trip, it'll be
33161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sniffed and the device transfer settings set for us.
33171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
33181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
33191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_dv_inq(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
33201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 struct ahd_devinfo *devinfo, struct ahd_linux_target *targ,
33211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 u_int request_length)
33221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
33231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
33251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_debug & AHD_SHOW_DV) {
33261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_print_devinfo(ahd, devinfo);
33271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("Sending INQ\n");
33281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
33291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
33301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->inq_data == NULL)
33311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		targ->inq_data = malloc(AHD_LINUX_DV_INQ_LEN,
33321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					M_DEVBUF, M_WAITOK);
33331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->dv_state > AHD_DV_STATE_INQ_ASYNC) {
33341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (targ->dv_buffer != NULL)
33351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			free(targ->dv_buffer, M_DEVBUF);
33361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		targ->dv_buffer = malloc(AHD_LINUX_DV_INQ_LEN,
33371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 M_DEVBUF, M_WAITOK);
33381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
33391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
3341be7db055dd7261522557046370f49160728e3847<hch@lst.de>	cmd->sc_data_direction = DMA_FROM_DEVICE;
33421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->cmd_len = 6;
33431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->cmnd[0] = INQUIRY;
33441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->cmnd[4] = request_length;
33451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->request_bufflen = request_length;
33461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->dv_state > AHD_DV_STATE_INQ_ASYNC)
33471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmd->request_buffer = targ->dv_buffer;
33481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
33491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmd->request_buffer = targ->inq_data;
33501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(cmd->request_buffer, 0, AHD_LINUX_DV_INQ_LEN);
33511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
33521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
33541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_dv_tur(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
33551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 struct ahd_devinfo *devinfo)
33561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
33571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
33591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_debug & AHD_SHOW_DV) {
33601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_print_devinfo(ahd, devinfo);
33611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("Sending TUR\n");
33621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
33631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
33641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Do a TUR to clear out any non-fatal transitional state */
33651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
3366be7db055dd7261522557046370f49160728e3847<hch@lst.de>	cmd->sc_data_direction = DMA_NONE;
33671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->cmd_len = 6;
33681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->cmnd[0] = TEST_UNIT_READY;
33691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
33701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AHD_REBD_LEN 4
33721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
33741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_dv_rebd(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
33751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 struct ahd_devinfo *devinfo, struct ahd_linux_target *targ)
33761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
33771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
33791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_debug & AHD_SHOW_DV) {
33801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_print_devinfo(ahd, devinfo);
33811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("Sending REBD\n");
33821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
33831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
33841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->dv_buffer != NULL)
33851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free(targ->dv_buffer, M_DEVBUF);
33861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ->dv_buffer = malloc(AHD_REBD_LEN, M_DEVBUF, M_WAITOK);
33871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
3388be7db055dd7261522557046370f49160728e3847<hch@lst.de>	cmd->sc_data_direction = DMA_FROM_DEVICE;
33891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->cmd_len = 10;
33901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->cmnd[0] = READ_BUFFER;
33911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->cmnd[1] = 0x0b;
33921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_ulto3b(AHD_REBD_LEN, &cmd->cmnd[6]);
33931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->request_bufflen = AHD_REBD_LEN;
33941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->underflow = cmd->request_bufflen;
33951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->request_buffer = targ->dv_buffer;
33961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
33971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
33991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_dv_web(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
34001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 struct ahd_devinfo *devinfo, struct ahd_linux_target *targ)
34011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
34021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
34041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_debug & AHD_SHOW_DV) {
34051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_print_devinfo(ahd, devinfo);
34061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("Sending WEB\n");
34071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
34081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
34091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
3410be7db055dd7261522557046370f49160728e3847<hch@lst.de>	cmd->sc_data_direction = DMA_TO_DEVICE;
34111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->cmd_len = 10;
34121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->cmnd[0] = WRITE_BUFFER;
34131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->cmnd[1] = 0x0a;
34141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_ulto3b(targ->dv_echo_size, &cmd->cmnd[6]);
34151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->request_bufflen = targ->dv_echo_size;
34161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->underflow = cmd->request_bufflen;
34171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->request_buffer = targ->dv_buffer;
34181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
34191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
34211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_dv_reb(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
34221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 struct ahd_devinfo *devinfo, struct ahd_linux_target *targ)
34231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
34241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
34261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_debug & AHD_SHOW_DV) {
34271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_print_devinfo(ahd, devinfo);
34281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("Sending REB\n");
34291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
34301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
34311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
3432be7db055dd7261522557046370f49160728e3847<hch@lst.de>	cmd->sc_data_direction = DMA_FROM_DEVICE;
34331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->cmd_len = 10;
34341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->cmnd[0] = READ_BUFFER;
34351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->cmnd[1] = 0x0a;
34361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_ulto3b(targ->dv_echo_size, &cmd->cmnd[6]);
34371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->request_bufflen = targ->dv_echo_size;
34381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->underflow = cmd->request_bufflen;
34391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->request_buffer = targ->dv_buffer1;
34401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
34411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
34431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_dv_su(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
34441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct ahd_devinfo *devinfo,
34451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct ahd_linux_target *targ)
34461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
34471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int le;
34481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	le = SID_IS_REMOVABLE(targ->inq_data) ? SSS_LOEJ : 0;
34501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
34521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_debug & AHD_SHOW_DV) {
34531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_print_devinfo(ahd, devinfo);
34541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("Sending SU\n");
34551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
34561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
34571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
3458be7db055dd7261522557046370f49160728e3847<hch@lst.de>	cmd->sc_data_direction = DMA_NONE;
34591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->cmd_len = 6;
34601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->cmnd[0] = START_STOP_UNIT;
34611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->cmnd[4] = le | SSS_START;
34621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
34631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
34651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
34661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
34671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_linux_target *targ;
34681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_initiator_tinfo *tinfo;
34691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_transinfo *goal;
34701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_tmode_tstate *tstate;
34711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	width;
34721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	period;
34731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	offset;
34741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	ppr_options;
34751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	cur_speed;
34761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	wide_speed;
34771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	narrow_speed;
34781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	fallback_speed;
34791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
34811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_debug & AHD_SHOW_DV) {
34821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_print_devinfo(ahd, devinfo);
34831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("Trying to fallback\n");
34841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
34851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
34861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ = ahd->platform_data->targets[devinfo->target_offset];
34871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tinfo = ahd_fetch_transinfo(ahd, devinfo->channel,
34881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    devinfo->our_scsiid,
34891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    devinfo->target, &tstate);
34901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goal = &tinfo->goal;
34911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	width = goal->width;
34921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	period = goal->period;
34931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	offset = goal->offset;
34941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ppr_options = goal->ppr_options;
34951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (offset == 0)
34961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		period = AHD_ASYNC_XFER_PERIOD;
34971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->dv_next_narrow_period == 0)
34981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		targ->dv_next_narrow_period = MAX(period, AHD_SYNCRATE_ULTRA2);
34991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->dv_next_wide_period == 0)
35001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		targ->dv_next_wide_period = period;
35011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->dv_max_width == 0)
35021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		targ->dv_max_width = width;
35031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->dv_max_ppr_options == 0)
35041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		targ->dv_max_ppr_options = ppr_options;
35051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->dv_last_ppr_options == 0)
35061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		targ->dv_last_ppr_options = ppr_options;
35071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cur_speed = aic_calc_speed(width, period, offset, AHD_SYNCRATE_MIN);
35091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wide_speed = aic_calc_speed(MSG_EXT_WDTR_BUS_16_BIT,
35101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  targ->dv_next_wide_period,
35111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  MAX_OFFSET, AHD_SYNCRATE_MIN);
35121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	narrow_speed = aic_calc_speed(MSG_EXT_WDTR_BUS_8_BIT,
35131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    targ->dv_next_narrow_period,
35141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    MAX_OFFSET, AHD_SYNCRATE_MIN);
35151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fallback_speed = aic_calc_speed(width, period+1, offset,
35161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      AHD_SYNCRATE_MIN);
35171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
35181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_debug & AHD_SHOW_DV) {
35191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("cur_speed= %d, wide_speed= %d, narrow_speed= %d, "
35201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "fallback_speed= %d\n", cur_speed, wide_speed,
35211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       narrow_speed, fallback_speed);
35221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
35231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
35241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cur_speed > 160000) {
35261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
35271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Paced/DT/IU_REQ only transfer speeds.  All we
35281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * can do is fallback in terms of syncrate.
35291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
35301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		period++;
35311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (cur_speed > 80000) {
35321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
35331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
35341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Try without IU_REQ as it may be confusing
35351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * an expander.
35361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
35371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ppr_options &= ~MSG_EXT_PPR_IU_REQ;
35381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
35391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
35401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Paced/DT only transfer speeds.  All we
35411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * can do is fallback in terms of syncrate.
35421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
35431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			period++;
35441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ppr_options = targ->dv_max_ppr_options;
35451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
35461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (cur_speed > 3300) {
35471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
35491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * In this range we the following
35501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * options ordered from highest to
35511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * lowest desireability:
35521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
35531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * o Wide/DT
35541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * o Wide/non-DT
35551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * o Narrow at a potentally higher sync rate.
35561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
35571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * All modes are tested with and without IU_REQ
35581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * set since using IUs may confuse an expander.
35591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
35601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
35611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ppr_options &= ~MSG_EXT_PPR_IU_REQ;
35631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) {
35641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
35651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Try going non-DT.
35661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
35671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ppr_options = targ->dv_max_ppr_options;
35681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ppr_options &= ~MSG_EXT_PPR_DT_REQ;
35691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (targ->dv_last_ppr_options != 0) {
35701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
35711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Try without QAS or any other PPR options.
35721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * We may need a non-PPR message to work with
35731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * an expander.  We look at the "last PPR options"
35741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * so we will perform this fallback even if the
35751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * target responded to our PPR negotiation with
35761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * no option bits set.
35771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
35781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ppr_options = 0;
35791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (width == MSG_EXT_WDTR_BUS_16_BIT) {
35801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
35811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * If the next narrow speed is greater than
35821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * the next wide speed, fallback to narrow.
35831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Otherwise fallback to the next DT/Wide setting.
35841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * The narrow async speed will always be smaller
35851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * than the wide async speed, so handle this case
35861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * specifically.
35871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
35881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ppr_options = targ->dv_max_ppr_options;
35891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (narrow_speed > fallback_speed
35901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 || period >= AHD_ASYNC_XFER_PERIOD) {
35911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->dv_next_wide_period = period+1;
35921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				width = MSG_EXT_WDTR_BUS_8_BIT;
35931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				period = targ->dv_next_narrow_period;
35941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
35951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				period++;
35961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
35971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if ((ahd->features & AHD_WIDE) != 0
35981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			&& targ->dv_max_width != 0
35991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			&& wide_speed >= fallback_speed
36001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			&& (targ->dv_next_wide_period <= AHD_ASYNC_XFER_PERIOD
36011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 || period >= AHD_ASYNC_XFER_PERIOD)) {
36021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
36041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * We are narrow.  Try falling back
36051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * to the next wide speed with
36061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * all supported ppr options set.
36071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
36081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			targ->dv_next_narrow_period = period+1;
36091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			width = MSG_EXT_WDTR_BUS_16_BIT;
36101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			period = targ->dv_next_wide_period;
36111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ppr_options = targ->dv_max_ppr_options;
36121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
36131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Only narrow fallback is allowed. */
36141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			period++;
36151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ppr_options = targ->dv_max_ppr_options;
36161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
36171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
36181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (-1);
36191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
36201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	offset = MAX_OFFSET;
36211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_PACED);
36221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_set_width(ahd, devinfo, width, AHD_TRANS_GOAL, FALSE);
36231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (period == 0) {
36241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		period = 0;
36251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		offset = 0;
36261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ppr_options = 0;
36271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (width == MSG_EXT_WDTR_BUS_8_BIT)
36281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			targ->dv_next_narrow_period = AHD_ASYNC_XFER_PERIOD;
36291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
36301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			targ->dv_next_wide_period = AHD_ASYNC_XFER_PERIOD;
36311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
36321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_set_syncrate(ahd, devinfo, period, offset,
36331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 ppr_options, AHD_TRANS_GOAL, FALSE);
36341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ->dv_last_ppr_options = ppr_options;
36351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
36361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
36371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
36391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_dv_timeout(struct scsi_cmnd *cmd)
36401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
36411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_softc *ahd;
36421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	scb *scb;
36431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long	flags;
36441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd = *((struct ahd_softc **)cmd->device->host->hostdata);
36461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_lock(ahd, &flags);
36471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
36491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_debug & AHD_SHOW_DV) {
36501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s: Timeout while doing DV command %x.\n",
36511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       ahd_name(ahd), cmd->cmnd[0]);
36521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_dump_card_state(ahd);
36531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
36541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
36551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
36571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Guard against "done race".  No action is
36581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * required if we just completed.
36591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
36601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((scb = (struct scb *)cmd->host_scribble) == NULL) {
36611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_unlock(ahd, &flags);
36621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
36631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
36641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
36661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Command has not completed.  Mark this
36671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SCB as having failing status prior to
36681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * resetting the bus, so we get the correct
36691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * error code.
36701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
36711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((scb->flags & SCB_SENSE) != 0)
36721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_set_transaction_status(scb, CAM_AUTOSENSE_FAIL);
36731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
36741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT);
36751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_reset_channel(ahd, cmd->device->channel + 'A', /*initiate*/TRUE);
36761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
36781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Add a minimal bus settle delay for devices that are slow to
36791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * respond after bus resets.
36801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
36811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_freeze_simq(ahd);
36821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer(&ahd->platform_data->reset_timer);
36831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd->platform_data->reset_timer.data = (u_long)ahd;
36841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd->platform_data->reset_timer.expires = jiffies + HZ / 2;
36851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd->platform_data->reset_timer.function =
36861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (ahd_linux_callback_t *)ahd_release_simq;
36871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_timer(&ahd->platform_data->reset_timer);
36881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_linux_next_device_to_run(ahd) != NULL)
36891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_schedule_runq(ahd);
36901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_run_complete_queue(ahd);
36911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_unlock(ahd, &flags);
36921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
36931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
36951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_dv_complete(struct scsi_cmnd *cmd)
36961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
36971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_softc *ahd;
36981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd = *((struct ahd_softc **)cmd->device->host->hostdata);
37001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Delete the DV timer before it goes off! */
37021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_delete_timer(cmd);
37031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
37051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_debug & AHD_SHOW_DV)
37061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s:%c:%d: Command completed, status= 0x%x\n",
37071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       ahd_name(ahd), cmd->device->channel, cmd->device->id,
37081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       cmd->result);
37091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
37101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wake up the state machine */
37121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&ahd->platform_data->dv_cmd_sem);
37131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
37141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
37161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_generate_dv_pattern(struct ahd_linux_target *targ)
37171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
37181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint16_t b;
37191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	 i;
37201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	 j;
37211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->dv_buffer != NULL)
37231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free(targ->dv_buffer, M_DEVBUF);
37241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ->dv_buffer = malloc(targ->dv_echo_size, M_DEVBUF, M_WAITOK);
37251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->dv_buffer1 != NULL)
37261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free(targ->dv_buffer1, M_DEVBUF);
37271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ->dv_buffer1 = malloc(targ->dv_echo_size, M_DEVBUF, M_WAITOK);
37281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = 0;
37301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b = 0x0001;
37321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (j = 0 ; i < targ->dv_echo_size; j++) {
37331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (j < 32) {
37341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
37351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * 32bytes of sequential numbers.
37361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
37371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			targ->dv_buffer[i++] = j & 0xff;
37381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (j < 48) {
37391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
37401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * 32bytes of repeating 0x0000, 0xffff.
37411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
37421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			targ->dv_buffer[i++] = (j & 0x02) ? 0xff : 0x00;
37431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (j < 64) {
37441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
37451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * 32bytes of repeating 0x5555, 0xaaaa.
37461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
37471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			targ->dv_buffer[i++] = (j & 0x02) ? 0xaa : 0x55;
37481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
37491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
37501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Remaining buffer is filled with a repeating
37511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * patter of:
37521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 *
37531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 *	 0xffff
37541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 *	~0x0001 << shifted once in each loop.
37551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
37561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (j & 0x02) {
37571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (j & 0x01) {
37581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					targ->dv_buffer[i++] = ~(b >> 8) & 0xff;
37591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					b <<= 1;
37601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (b == 0x0000)
37611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						b = 0x0001;
37621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
37631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					targ->dv_buffer[i++] = (~b & 0xff);
37641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
37651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
37661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				targ->dv_buffer[i++] = 0xff;
37671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
37681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
37691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
37701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
37711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int
37731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
37741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
37751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int warned_user;
37761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int tags;
37771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tags = 0;
37791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ahd->user_discenable & devinfo->target_mask) != 0) {
37801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ahd->unit >= NUM_ELEMENTS(aic79xx_tag_info)) {
37811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (warned_user == 0) {
37831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printf(KERN_WARNING
37841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"aic79xx: WARNING: Insufficient tag_info instances\n"
37851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"aic79xx: for installed controllers.  Using defaults\n"
37861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"aic79xx: Please update the aic79xx_tag_info array in\n"
37871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"aic79xx: the aic79xx_osm.c source file.\n");
37881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				warned_user++;
37891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
37901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tags = AHD_MAX_QUEUE;
37911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
37921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			adapter_tag_info_t *tag_info;
37931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tag_info = &aic79xx_tag_info[ahd->unit];
37951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tags = tag_info->tag_commands[devinfo->target_offset];
37961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tags > AHD_MAX_QUEUE)
37971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tags = AHD_MAX_QUEUE;
37981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
37991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
38001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (tags);
38011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
38021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int
38041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_user_dv_setting(struct ahd_softc *ahd)
38051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
38061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int warned_user;
38071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dv;
38081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd->unit >= NUM_ELEMENTS(aic79xx_dv_settings)) {
38101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (warned_user == 0) {
38121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf(KERN_WARNING
38131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"aic79xx: WARNING: Insufficient dv settings instances\n"
38141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"aic79xx: for installed controllers. Using defaults\n"
38151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"aic79xx: Please update the aic79xx_dv_settings array in"
38161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"aic79xx: the aic79xx_osm.c source file.\n");
38171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			warned_user++;
38181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
38191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dv = -1;
38201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
38211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dv = aic79xx_dv_settings[ahd->unit];
38231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
38241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dv < 0) {
38261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
38271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Apply the default.
38281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
38291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dv = 1;
38301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ahd->seep_config != 0)
38311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dv = (ahd->seep_config->bios_control & CFENABLEDV);
38321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
38331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (dv);
38341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
38351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
38371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_setup_user_rd_strm_settings(struct ahd_softc *ahd)
38381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
38391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static	int warned_user;
38401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	rd_strm_mask;
38411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	target_id;
38421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
38441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If we have specific read streaming info for this controller,
38451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * apply it.  Otherwise use the defaults.
38461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
38471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 if (ahd->unit >= NUM_ELEMENTS(aic79xx_rd_strm_info)) {
38481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (warned_user == 0) {
38501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf(KERN_WARNING
38521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"aic79xx: WARNING: Insufficient rd_strm instances\n"
38531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"aic79xx: for installed controllers. Using defaults\n"
38541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"aic79xx: Please update the aic79xx_rd_strm_info array\n"
38551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"aic79xx: in the aic79xx_osm.c source file.\n");
38561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			warned_user++;
38571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
38581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rd_strm_mask = AIC79XX_CONFIGED_RD_STRM;
38591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
38601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rd_strm_mask = aic79xx_rd_strm_info[ahd->unit];
38621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
38631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (target_id = 0; target_id < 16; target_id++) {
38641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct ahd_devinfo devinfo;
38651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct ahd_initiator_tinfo *tinfo;
38661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct ahd_tmode_tstate *tstate;
38671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
38691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    target_id, &tstate);
38701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_compile_devinfo(&devinfo, ahd->our_id, target_id,
38711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    CAM_LUN_WILDCARD, 'A', ROLE_INITIATOR);
38721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tinfo->user.ppr_options &= ~MSG_EXT_PPR_RD_STRM;
38731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((rd_strm_mask & devinfo.target_mask) != 0)
38741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tinfo->user.ppr_options |= MSG_EXT_PPR_RD_STRM;
38751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
38761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
38771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
38791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Determines the queue depth for a given device.
38801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
38811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
38821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_device_queue_depth(struct ahd_softc *ahd,
38831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct ahd_linux_device *dev)
38841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
38851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_devinfo devinfo;
38861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	tags;
38871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_compile_devinfo(&devinfo,
38891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ahd->our_id,
38901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    dev->target->target, dev->lun,
38911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    dev->target->channel == 0 ? 'A' : 'B',
38921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ROLE_INITIATOR);
38931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tags = ahd_linux_user_tagdepth(ahd, &devinfo);
38941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tags != 0
38951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && dev->scsi_device != NULL
38961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && dev->scsi_device->tagged_supported != 0) {
38971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED);
38991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_print_devinfo(ahd, &devinfo);
39001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("Tagged Queuing enabled.  Depth %d\n", tags);
39011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
39021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_set_tags(ahd, &devinfo, AHD_QUEUE_NONE);
39031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
39041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
39051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
39071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_run_device_queue(struct ahd_softc *ahd, struct ahd_linux_device *dev)
39081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
39091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	 ahd_cmd *acmd;
39101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	 scsi_cmnd *cmd;
39111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	 scb *scb;
39121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	 hardware_scb *hscb;
39131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	 ahd_initiator_tinfo *tinfo;
39141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	 ahd_tmode_tstate *tstate;
39151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	 col_idx;
39161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint16_t mask;
39171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((dev->flags & AHD_DEV_ON_RUN_LIST) != 0)
39191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		panic("running device on run list");
39201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL
39221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    && dev->openings > 0 && dev->qfrozen == 0) {
39231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
39251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Schedule us to run later.  The only reason we are not
39261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * running is because the whole controller Q is frozen.
39271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
39281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ahd->platform_data->qfrozen != 0
39291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && AHD_DV_SIMQ_FROZEN(ahd) == 0) {
39301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq,
39321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  dev, links);
39331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->flags |= AHD_DEV_ON_RUN_LIST;
39341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
39351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
39361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmd = &acmd_scsi_cmd(acmd);
39381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
39401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Get an scb to use.
39411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
39421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
39431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    cmd->device->id, &tstate);
39441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) == 0
39451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 || (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
39461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			col_idx = AHD_NEVER_COL_IDX;
39471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
39481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			col_idx = AHD_BUILD_COL_IDX(cmd->device->id,
39491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    cmd->device->lun);
39501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
39511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) {
39521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq,
39531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 dev, links);
39541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->flags |= AHD_DEV_ON_RUN_LIST;
39551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd->flags |= AHD_RESOURCE_SHORTAGE;
39561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
39571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
39581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		TAILQ_REMOVE(&dev->busyq, acmd, acmd_links.tqe);
39591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		scb->io_ctx = cmd;
39601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		scb->platform_data->dev = dev;
39611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hscb = scb->hscb;
39621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmd->host_scribble = (char *)scb;
39631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
39651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Fill out basics of the HSCB.
39661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
39671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hscb->control = 0;
39681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hscb->scsiid = BUILD_SCSIID(ahd, cmd);
39691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hscb->lun = cmd->device->lun;
39701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		scb->hscb->task_management = 0;
39711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask = SCB_GET_TARGET_MASK(ahd, scb);
39721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((ahd->user_discenable & mask) != 0)
39741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			hscb->control |= DISCENB;
39751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 	if (AHD_DV_CMD(cmd) != 0)
39771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scb->flags |= SCB_SILENT;
39781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0)
39801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scb->flags |= SCB_PACKETIZED;
39811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((tstate->auto_negotiate & mask) != 0) {
39831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scb->flags |= SCB_AUTO_NEGOTIATE;
39841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scb->hscb->control |= MK_MESSAGE;
39851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
39861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) {
39881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
39891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int	msg_bytes;
39901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			uint8_t tag_msgs[2];
39911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs);
39931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) {
39941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				hscb->control |= tag_msgs[0];
39951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (tag_msgs[0] == MSG_ORDERED_TASK)
39961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dev->commands_since_idle_or_otag = 0;
39971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else
39981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
39991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (dev->commands_since_idle_or_otag == AHD_OTAG_THRESH
40001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 && (dev->flags & AHD_DEV_Q_TAGGED) != 0) {
40011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				hscb->control |= MSG_ORDERED_TASK;
40021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev->commands_since_idle_or_otag = 0;
40031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
40041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				hscb->control |= MSG_SIMPLE_TASK;
40051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
40061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
40071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hscb->cdb_len = cmd->cmd_len;
40091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(hscb->shared_data.idata.cdb, cmd->cmnd, hscb->cdb_len);
40101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		scb->sg_count = 0;
40121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_set_residual(scb, 0);
40131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_set_sense_residual(scb, 0);
40141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cmd->use_sg != 0) {
40151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			void	*sg;
40161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct	 scatterlist *cur_seg;
40171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u_int	 nseg;
40181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int	 dir;
40191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cur_seg = (struct scatterlist *)cmd->request_buffer;
4021be7db055dd7261522557046370f49160728e3847<hch@lst.de>			dir = cmd->sc_data_direction;
40221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nseg = pci_map_sg(ahd->dev_softc, cur_seg,
40231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  cmd->use_sg, dir);
40241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scb->platform_data->xfer_len = 0;
40251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (sg = scb->sg_list; nseg > 0; nseg--, cur_seg++) {
40261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dma_addr_t addr;
40271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bus_size_t len;
40281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				addr = sg_dma_address(cur_seg);
40301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len = sg_dma_len(cur_seg);
40311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				scb->platform_data->xfer_len += len;
40321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sg = ahd_sg_setup(ahd, scb, sg, addr, len,
40331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  /*last*/nseg == 1);
40341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
40351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (cmd->request_bufflen != 0) {
40361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			void *sg;
40371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dma_addr_t addr;
40381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int dir;
40391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sg = scb->sg_list;
4041be7db055dd7261522557046370f49160728e3847<hch@lst.de>			dir = cmd->sc_data_direction;
40421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			addr = pci_map_single(ahd->dev_softc,
40431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      cmd->request_buffer,
40441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      cmd->request_bufflen, dir);
40451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scb->platform_data->xfer_len = cmd->request_bufflen;
40461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scb->platform_data->buf_busaddr = addr;
40471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sg = ahd_sg_setup(ahd, scb, sg, addr,
40481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  cmd->request_bufflen, /*last*/TRUE);
40491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
40501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);
40521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->openings--;
40531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->active++;
40541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->commands_issued++;
40551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Update the error counting bucket and dump if needed */
40571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dev->target->cmds_since_error) {
40581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->target->cmds_since_error++;
40591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (dev->target->cmds_since_error >
40601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    AHD_LINUX_ERR_THRESH)
40611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev->target->cmds_since_error = 0;
40621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
40631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((dev->flags & AHD_DEV_PERIODIC_OTAG) != 0)
40651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->commands_since_idle_or_otag++;
40661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		scb->flags |= SCB_ACTIVE;
40671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_queue_scb(ahd, scb);
40681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
40691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
40701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
40721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCSI controller interrupt handler.
40731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
40741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsirqreturn_t
40751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
40761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
40771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_softc *ahd;
40781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long	flags;
40791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	ours;
40801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd = (struct ahd_softc *) dev_id;
40821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_lock(ahd, &flags);
40831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ours = ahd_intr(ahd);
40841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_linux_next_device_to_run(ahd) != NULL)
40851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_schedule_runq(ahd);
40861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_run_complete_queue(ahd);
40871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_unlock(ahd, &flags);
40881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_RETVAL(ours);
40891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
40901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
40921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_platform_flushwork(struct ahd_softc *ahd)
40931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
40941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (ahd_linux_run_complete_queue(ahd) != NULL)
40961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		;
40971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
40981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ahd_linux_target*
41001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_alloc_target(struct ahd_softc *ahd, u_int channel, u_int target)
41011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
41021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_linux_target *targ;
41031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ = malloc(sizeof(*targ), M_DEVBUF, M_NOWAIT);
41051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ == NULL)
41061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (NULL);
41071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(targ, 0, sizeof(*targ));
41081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ->channel = channel;
41091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ->target = target;
41101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ->ahd = ahd;
41111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ->flags = AHD_DV_REQUIRED;
41121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd->platform_data->targets[target] = targ;
41131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (targ);
41141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
41151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
41171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_free_target(struct ahd_softc *ahd, struct ahd_linux_target *targ)
41181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
41191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_devinfo devinfo;
41201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_initiator_tinfo *tinfo;
41211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_tmode_tstate *tstate;
41221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int our_id;
41231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int target_offset;
41241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char channel;
41251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
41271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Force a negotiation to async/narrow on any
41281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * future command to this device unless a bus
41291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * reset occurs between now and that command.
41301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
41311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	channel = 'A' + targ->channel;
41321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	our_id = ahd->our_id;
41331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	target_offset = targ->target;
41341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tinfo = ahd_fetch_transinfo(ahd, channel, our_id,
41351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    targ->target, &tstate);
41361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_compile_devinfo(&devinfo, our_id, targ->target, CAM_LUN_WILDCARD,
41371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    channel, ROLE_INITIATOR);
41381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_set_syncrate(ahd, &devinfo, 0, 0, 0,
41391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 AHD_TRANS_GOAL, /*paused*/FALSE);
41401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
41411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      AHD_TRANS_GOAL, /*paused*/FALSE);
41421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_update_neg_request(ahd, &devinfo, tstate, tinfo, AHD_NEG_ALWAYS);
41431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 	ahd->platform_data->targets[target_offset] = NULL;
41441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->inq_data != NULL)
41451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free(targ->inq_data, M_DEVBUF);
41461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->dv_buffer != NULL)
41471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free(targ->dv_buffer, M_DEVBUF);
41481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->dv_buffer1 != NULL)
41491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free(targ->dv_buffer1, M_DEVBUF);
41501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free(targ, M_DEVBUF);
41511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
41521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ahd_linux_device*
41541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_alloc_device(struct ahd_softc *ahd,
41551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 struct ahd_linux_target *targ, u_int lun)
41561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
41571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_linux_device *dev;
41581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = malloc(sizeof(*dev), M_DEVBUG, M_NOWAIT);
41601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev == NULL)
41611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (NULL);
41621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(dev, 0, sizeof(*dev));
41631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer(&dev->timer);
41641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TAILQ_INIT(&dev->busyq);
41651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->flags = AHD_DEV_UNCONFIGURED;
41661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->lun = lun;
41671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->target = targ;
41681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
41701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We start out life using untagged
41711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * transactions of which we allow one.
41721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
41731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->openings = 1;
41741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
41761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Set maxtags to 0.  This will be changed if we
41771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * later determine that we are dealing with
41781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * a tagged queuing capable device.
41791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
41801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->maxtags = 0;
41811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ->refcount++;
41831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ->devices[lun] = dev;
41841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (dev);
41851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
41861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
41881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_free_device(struct ahd_softc *ahd, struct ahd_linux_device *dev)
41891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
41901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_linux_target *targ;
41911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer(&dev->timer);
41931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ = dev->target;
41941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ->devices[dev->lun] = NULL;
41951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free(dev, M_DEVBUF);
41961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	targ->refcount--;
41971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (targ->refcount == 0
41981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && (targ->flags & AHD_DV_REQUIRED) == 0)
41991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_free_target(ahd, targ);
42001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
42011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
42031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_send_async(struct ahd_softc *ahd, char channel,
42041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       u_int target, u_int lun, ac_code code, void *arg)
42051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
42061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (code) {
42071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case AC_TRANSFER_NEG:
42081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
42091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char	buf[80];
42101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct	ahd_linux_target *targ;
42111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct	info_str info;
42121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct	ahd_initiator_tinfo *tinfo;
42131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct	ahd_tmode_tstate *tstate;
42141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.buffer = buf;
42161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.length = sizeof(buf);
42171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.offset = 0;
42181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.pos = 0;
42191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tinfo = ahd_fetch_transinfo(ahd, channel, ahd->our_id,
42201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    target, &tstate);
42211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
42231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Don't bother reporting results while
42241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * negotiations are still pending.
42251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
42261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tinfo->curr.period != tinfo->goal.period
42271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 || tinfo->curr.width != tinfo->goal.width
42281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 || tinfo->curr.offset != tinfo->goal.offset
42291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 || tinfo->curr.ppr_options != tinfo->goal.ppr_options)
42301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (bootverbose == 0)
42311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
42321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
42341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Don't bother reporting results that
42351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * are identical to those last reported.
42361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
42371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		targ = ahd->platform_data->targets[target];
42381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (targ == NULL)
42391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
42401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tinfo->curr.period == targ->last_tinfo.period
42411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && tinfo->curr.width == targ->last_tinfo.width
42421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && tinfo->curr.offset == targ->last_tinfo.offset
42431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && tinfo->curr.ppr_options == targ->last_tinfo.ppr_options)
42441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (bootverbose == 0)
42451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
42461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		targ->last_tinfo.period = tinfo->curr.period;
42481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		targ->last_tinfo.width = tinfo->curr.width;
42491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		targ->last_tinfo.offset = tinfo->curr.offset;
42501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		targ->last_tinfo.ppr_options = tinfo->curr.ppr_options;
42511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("(%s:%c:", ahd_name(ahd), channel);
42531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (target == CAM_TARGET_WILDCARD)
42541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf("*): ");
42551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
42561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf("%d): ", target);
42571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_format_transinfo(&info, &tinfo->curr);
42581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (info.pos < info.length)
42591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*info.buffer = '\0';
42601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
42611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			buf[info.length - 1] = '\0';
42621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("%s", buf);
42631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
42641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
42651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case AC_SENT_BDR:
42661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
42671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
42681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		WARN_ON(lun != CAM_LUN_WILDCARD);
42691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		scsi_report_device_reset(ahd->platform_data->host,
42701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 channel - 'A', target);
42711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
42721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		Scsi_Device *scsi_dev;
42731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
42751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Find the SCSI device associated with this
42761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * request and indicate that a UA is expected.
42771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
42781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (scsi_dev = ahd->platform_data->host->host_queue;
42791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     scsi_dev != NULL; scsi_dev = scsi_dev->next) {
42801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (channel - 'A' == scsi_dev->channel
42811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 && target == scsi_dev->id
42821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 && (lun == CAM_LUN_WILDCARD
42831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  || lun == scsi_dev->lun)) {
42841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				scsi_dev->was_reset = 1;
42851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				scsi_dev->expecting_cc_ua = 1;
42861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
42871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
42881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
42891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
42901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
42911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case AC_BUS_RESET:
42921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ahd->platform_data->host != NULL) {
42931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scsi_report_bus_reset(ahd->platform_data->host,
42941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      channel - 'A');
42951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
42961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
42971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        default:
42981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                panic("ahd_send_async: Unexpected async event");
42991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
43001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
43011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
43031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calls the higher level scsi done function and frees the scb.
43041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
43051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
43061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_done(struct ahd_softc *ahd, struct scb *scb)
43071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
43081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Scsi_Cmnd *cmd;
43091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	  ahd_linux_device *dev;
43101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((scb->flags & SCB_ACTIVE) == 0) {
43121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("SCB %d done'd twice\n", SCB_GET_TAG(scb));
43131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_dump_card_state(ahd);
43141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		panic("Stopping for safety");
43151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
43161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LIST_REMOVE(scb, pending_links);
43171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd = scb->io_ctx;
43181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = scb->platform_data->dev;
43191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->active--;
43201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->openings++;
43211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((cmd->result & (CAM_DEV_QFRZN << 16)) != 0) {
43221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmd->result &= ~(CAM_DEV_QFRZN << 16);
43231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->qfrozen--;
43241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
43251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_unmap_scb(ahd, scb);
43261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
43281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Guard against stale sense data.
43291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The Linux mid-layer assumes that sense
43301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * was retrieved anytime the first byte of
43311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the sense buffer looks "sane".
43321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
43331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->sense_buffer[0] = 0;
43341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_get_transaction_status(scb) == CAM_REQ_INPROG) {
43351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uint32_t amount_xferred;
43361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		amount_xferred =
43381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ahd_get_transfer_length(scb) - ahd_get_residual(scb);
43391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((scb->flags & SCB_TRANSMISSION_ERROR) != 0) {
43401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
43411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((ahd_debug & AHD_SHOW_MISC) != 0) {
43421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ahd_print_path(ahd, scb);
43431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printf("Set CAM_UNCOR_PARITY\n");
43441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
43451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
43461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_set_transaction_status(scb, CAM_UNCOR_PARITY);
43471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_REPORT_UNDERFLOWS
43481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
43491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * This code is disabled by default as some
43501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * clients of the SCSI system do not properly
43511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * initialize the underflow parameter.  This
43521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * results in spurious termination of commands
43531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * that complete as expected (e.g. underflow is
43541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * allowed as command can return variable amounts
43551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * of data.
43561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
43571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (amount_xferred < scb->io_ctx->underflow) {
43581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u_int i;
43591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_print_path(ahd, scb);
43611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf("CDB:");
43621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < scb->io_ctx->cmd_len; i++)
43631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printf(" 0x%x", scb->io_ctx->cmnd[i]);
43641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf("\n");
43651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_print_path(ahd, scb);
43661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf("Saw underflow (%ld of %ld bytes). "
43671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "Treated as error\n",
43681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ahd_get_residual(scb),
43691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ahd_get_transfer_length(scb));
43701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR);
43711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
43721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
43731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_set_transaction_status(scb, CAM_REQ_CMP);
43741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
43751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (ahd_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) {
43761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_handle_scsi_status(ahd, dev, scb);
43771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (ahd_get_transaction_status(scb) == CAM_SEL_TIMEOUT) {
43781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->flags |= AHD_DEV_UNCONFIGURED;
43791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (AHD_DV_CMD(cmd) == FALSE)
43801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->target->flags &= ~AHD_DV_REQUIRED;
43811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
43821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
43831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Start DV for devices that require it assuming the first command
43841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * sent does not result in a selection timeout.
43851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
43861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd_get_transaction_status(scb) != CAM_SEL_TIMEOUT
43871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && (dev->target->flags & AHD_DV_REQUIRED) != 0)
43881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_start_dv(ahd);
43891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->openings == 1
43911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && ahd_get_transaction_status(scb) == CAM_REQ_CMP
43921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && ahd_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL)
43931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->tag_success_count++;
43941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
43951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Some devices deal with temporary internal resource
43961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * shortages by returning queue full.  When the queue
43971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * full occurrs, we throttle back.  Slowly try to get
43981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * back to our previous queue depth.
43991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
44001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((dev->openings + dev->active) < dev->maxtags
44011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && dev->tag_success_count > AHD_TAG_SUCCESS_INTERVAL) {
44021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->tag_success_count = 0;
44031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->openings++;
44041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
44051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->active == 0)
44071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->commands_since_idle_or_otag = 0;
44081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (TAILQ_EMPTY(&dev->busyq)) {
44101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0
44111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && dev->active == 0
44121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0)
44131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_linux_free_device(ahd, dev);
44141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) {
44151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links);
44161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->flags |= AHD_DEV_ON_RUN_LIST;
44171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
44181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
44201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printf("Recovery SCB completes\n");
44211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ahd_get_transaction_status(scb) == CAM_BDR_SENT
44221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED)
44231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT);
44241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((scb->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) {
44251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scb->platform_data->flags &= ~AHD_SCB_UP_EH_SEM;
44261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			up(&ahd->platform_data->eh_sem);
44271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
44281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
44291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_free_scb(ahd, scb);
44311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_queue_cmd_complete(ahd, cmd);
44321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ahd->platform_data->flags & AHD_DV_WAIT_SIMQ_EMPTY) != 0
44341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && LIST_FIRST(&ahd->pending_scbs) == NULL) {
44351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd->platform_data->flags &= ~AHD_DV_WAIT_SIMQ_EMPTY;
44361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up(&ahd->platform_data->dv_sem);
44371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
44381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
44391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
44411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_handle_scsi_status(struct ahd_softc *ahd,
44421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct ahd_linux_device *dev, struct scb *scb)
44431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
44441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_devinfo devinfo;
44451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_compile_devinfo(&devinfo,
44471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ahd->our_id,
44481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    dev->target->target, dev->lun,
44491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    dev->target->channel == 0 ? 'A' : 'B',
44501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ROLE_INITIATOR);
44511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
44531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We don't currently trust the mid-layer to
44541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * properly deal with queue full or busy.  So,
44551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * when one occurs, we tell the mid-layer to
44561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * unconditionally requeue the command to us
44571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * so that we can retry it ourselves.  We also
44581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * implement our own throttling mechanism so
44591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * we don't clobber the device with too many
44601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * commands.
44611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
44621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (ahd_get_scsi_status(scb)) {
44631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
44641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
44651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SCSI_STATUS_CHECK_COND:
44661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SCSI_STATUS_CMD_TERMINATED:
44671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
44681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		Scsi_Cmnd *cmd;
44691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
44711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Copy sense information to the OS's cmd
44721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * structure if it is available.
44731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
44741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmd = scb->io_ctx;
44751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((scb->flags & (SCB_SENSE|SCB_PKT_SENSE)) != 0) {
44761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct scsi_status_iu_header *siu;
44771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u_int sense_size;
44781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u_int sense_offset;
44791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (scb->flags & SCB_SENSE) {
44811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sense_size = MIN(sizeof(struct scsi_sense_data)
44821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       - ahd_get_sense_residual(scb),
44831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						 sizeof(cmd->sense_buffer));
44841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sense_offset = 0;
44851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
44861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/*
44871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * Copy only the sense data into the provided
44881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * buffer.
44891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
44901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				siu = (struct scsi_status_iu_header *)
44911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    scb->sense_data;
44921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sense_size = MIN(scsi_4btoul(siu->sense_length),
44931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						sizeof(cmd->sense_buffer));
44941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sense_offset = SIU_SENSE_OFFSET(siu);
44951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
44961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
44981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(cmd->sense_buffer,
44991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       ahd_get_sense_buf(ahd, scb)
45001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       + sense_offset, sense_size);
45011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cmd->result |= (DRIVER_SENSE << 24);
45021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
45041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ahd_debug & AHD_SHOW_SENSE) {
45051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				int i;
45061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printf("Copied %d bytes of sense data at %d:",
45081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       sense_size, sense_offset);
45091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				for (i = 0; i < sense_size; i++) {
45101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if ((i & 0xF) == 0)
45111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						printf("\n");
45121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printf("0x%x ", cmd->sense_buffer[i]);
45131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
45141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printf("\n");
45151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
45161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
45171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
45181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
45191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
45201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SCSI_STATUS_QUEUE_FULL:
45211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
45221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
45231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * By the time the core driver has returned this
45241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * command, all other commands that were queued
45251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * to us but not the device have been returned.
45261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * This ensures that dev->active is equal to
45271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the number of commands actually queued to
45281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the device.
45291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
45301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->tag_success_count = 0;
45311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dev->active != 0) {
45321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
45331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Drop our opening count to the number
45341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * of commands currently outstanding.
45351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
45361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->openings = 0;
45371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef AHD_DEBUG
45381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((ahd_debug & AHD_SHOW_QFULL) != 0) {
45391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ahd_print_path(ahd, scb);
45401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printf("Dropping tag count to %d\n",
45411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       dev->active);
45421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
45431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
45441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (dev->active == dev->tags_on_last_queuefull) {
45451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev->last_queuefull_same_count++;
45471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/*
45481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * If we repeatedly see a queue full
45491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * at the same queue depth, this
45501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * device has a fixed number of tag
45511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * slots.  Lock in this tag depth
45521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * so we stop seeing queue fulls from
45531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * this device.
45541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
45551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (dev->last_queuefull_same_count
45561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 == AHD_LOCK_TAGS_COUNT) {
45571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dev->maxtags = dev->active;
45581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ahd_print_path(ahd, scb);
45591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printf("Locking max tag count at %d\n",
45601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       dev->active);
45611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
45621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
45631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev->tags_on_last_queuefull = dev->active;
45641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev->last_queuefull_same_count = 0;
45651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
45661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_set_transaction_status(scb, CAM_REQUEUE_REQ);
45671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_set_scsi_status(scb, SCSI_STATUS_OK);
45681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_platform_set_tags(ahd, &devinfo,
45691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     (dev->flags & AHD_DEV_Q_BASIC)
45701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED);
45711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
45721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
45731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
45741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Drop down to a single opening, and treat this
45751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * as if the target returned BUSY SCSI status.
45761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
45771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->openings = 1;
45781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_platform_set_tags(ahd, &devinfo,
45791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     (dev->flags & AHD_DEV_Q_BASIC)
45801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED);
45811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_set_scsi_status(scb, SCSI_STATUS_BUSY);
45821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FALLTHROUGH */
45831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
45841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SCSI_STATUS_BUSY:
45851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
45861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Set a short timer to defer sending commands for
45871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * a bit since Linux will not delay in this case.
45881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
45891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((dev->flags & AHD_DEV_TIMER_ACTIVE) != 0) {
45901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf("%s:%c:%d: Device Timer still active during "
45911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "busy processing\n", ahd_name(ahd),
45921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev->target->channel, dev->target->target);
45931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
45941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
45951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->flags |= AHD_DEV_TIMER_ACTIVE;
45961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->qfrozen++;
45971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		init_timer(&dev->timer);
45981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->timer.data = (u_long)dev;
45991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->timer.expires = jiffies + (HZ/2);
46001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->timer.function = ahd_linux_dev_timed_unfreeze;
46011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		add_timer(&dev->timer);
46021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
46031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
46041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
46051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
46071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_queue_cmd_complete(struct ahd_softc *ahd, Scsi_Cmnd *cmd)
46081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
46091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
46101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Typically, the complete queue has very few entries
46111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * queued to it before the queue is emptied by
46121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * ahd_linux_run_complete_queue, so sorting the entries
46131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * by generation number should be inexpensive.
46141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We perform the sort so that commands that complete
46151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * with an error are retuned in the order origionally
46161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * queued to the controller so that any subsequent retries
46171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * are performed in order.  The underlying ahd routines do
46181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * not guarantee the order that aborted commands will be
46191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * returned to us.
46201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
46211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_completeq *completeq;
46221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_cmd *list_cmd;
46231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_cmd *acmd;
46241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
46261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Map CAM error codes into Linux Error codes.  We
46271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * avoid the conversion so that the DV code has the
46281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * full error information available when making
46291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * state change decisions.
46301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
46311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (AHD_DV_CMD(cmd) == FALSE) {
46321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uint32_t status;
46331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u_int new_status;
46341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = ahd_cmd_get_transaction_status(cmd);
46361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status != CAM_REQ_CMP) {
46371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct ahd_linux_device *dev;
46381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct ahd_devinfo devinfo;
46391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cam_status cam_status;
46401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			uint32_t action;
46411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u_int scsi_status;
46421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev = ahd_linux_get_device(ahd, cmd->device->channel,
46441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   cmd->device->id,
46451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   cmd->device->lun,
46461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   /*alloc*/FALSE);
46471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (dev == NULL)
46491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto no_fallback;
46501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_compile_devinfo(&devinfo,
46521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    ahd->our_id,
46531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    dev->target->target, dev->lun,
46541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    dev->target->channel == 0 ? 'A':'B',
46551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    ROLE_INITIATOR);
46561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scsi_status = ahd_cmd_get_scsi_status(cmd);
46581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cam_status = ahd_cmd_get_transaction_status(cmd);
46591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			action = aic_error_action(cmd, dev->target->inq_data,
46601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  cam_status, scsi_status);
46611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((action & SSQ_FALLBACK) != 0) {
46621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Update stats */
46641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev->target->errors_detected++;
46651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (dev->target->cmds_since_error == 0)
46661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dev->target->cmds_since_error++;
46671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else {
46681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dev->target->cmds_since_error = 0;
46691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ahd_linux_fallback(ahd, &devinfo);
46701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
46711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
46721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
46731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsno_fallback:
46741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (status) {
46751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_REQ_INPROG:
46761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_REQ_CMP:
46771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_SCSI_STATUS_ERROR:
46781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_status = DID_OK;
46791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
46801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_REQ_ABORTED:
46811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_status = DID_ABORT;
46821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
46831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_BUSY:
46841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_status = DID_BUS_BUSY;
46851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
46861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_REQ_INVALID:
46871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_PATH_INVALID:
46881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_status = DID_BAD_TARGET;
46891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
46901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_SEL_TIMEOUT:
46911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_status = DID_NO_CONNECT;
46921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
46931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_SCSI_BUS_RESET:
46941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_BDR_SENT:
46951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_status = DID_RESET;
46961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
46971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_UNCOR_PARITY:
46981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_status = DID_PARITY;
46991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
47001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_CMD_TIMEOUT:
47011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_status = DID_TIME_OUT;
47021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
47031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_UA_ABORT:
47041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_REQ_CMP_ERR:
47051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_AUTOSENSE_FAIL:
47061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_NO_HBA:
47071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_DATA_RUN_ERR:
47081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_UNEXP_BUSFREE:
47091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_SEQUENCE_FAIL:
47101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_CCB_LEN_ERR:
47111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_PROVIDE_FAIL:
47121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_REQ_TERMIO:
47131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_UNREC_HBA_ERROR:
47141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_REQ_TOO_BIG:
47151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_status = DID_ERROR;
47161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
47171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CAM_REQUEUE_REQ:
47181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
47191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * If we want the request requeued, make sure there
47201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * are sufficent retries.  In the old scsi error code,
47211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * we used to be able to specify a result code that
47221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * bypassed the retry count.  Now we must use this
47231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * hack.  We also "fake" a check condition with
47241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * a sense code of ABORTED COMMAND.  This seems to
47251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * evoke a retry even if this command is being sent
47261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * via the eh thread.  Ick!  Ick!  Ick!
47271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
47281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cmd->retries > 0)
47291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cmd->retries--;
47301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_status = DID_OK;
47311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ahd_cmd_set_scsi_status(cmd, SCSI_STATUS_CHECK_COND);
47321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cmd->result |= (DRIVER_SENSE << 24);
47331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memset(cmd->sense_buffer, 0,
47341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       sizeof(cmd->sense_buffer));
47351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cmd->sense_buffer[0] = SSD_ERRCODE_VALID
47361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     | SSD_CURRENT_ERROR;
47371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cmd->sense_buffer[2] = SSD_KEY_ABORTED_COMMAND;
47381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
47391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
47401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* We should never get here */
47411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_status = DID_ERROR;
47421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
47431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
47441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_cmd_set_transaction_status(cmd, new_status);
47461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
47471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	completeq = &ahd->platform_data->completeq;
47491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_cmd = TAILQ_FIRST(completeq);
47501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acmd = (struct ahd_cmd *)cmd;
47511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (list_cmd != NULL
47521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    && acmd_scsi_cmd(list_cmd).serial_number
47531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     < acmd_scsi_cmd(acmd).serial_number)
47541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_cmd = TAILQ_NEXT(list_cmd, acmd_links.tqe);
47551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (list_cmd != NULL)
47561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		TAILQ_INSERT_BEFORE(list_cmd, acmd, acmd_links.tqe);
47571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
47581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		TAILQ_INSERT_TAIL(completeq, acmd, acmd_links.tqe);
47591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
47601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
47621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_filter_inquiry(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
47631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
47641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	scsi_inquiry_data *sid;
47651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_initiator_tinfo *tinfo;
47661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_transinfo *user;
47671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_transinfo *goal;
47681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_transinfo *curr;
47691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_tmode_tstate *tstate;
47701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_linux_device *dev;
47711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	width;
47721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	period;
47731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	offset;
47741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	ppr_options;
47751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	trans_version;
47761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int	prot_version;
47771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
47791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Determine if this lun actually exists.  If so,
47801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * hold on to its corresponding device structure.
47811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If not, make sure we release the device and
47821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * don't bother processing the rest of this inquiry
47831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * command.
47841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
47851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = ahd_linux_get_device(ahd, devinfo->channel - 'A',
47861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   devinfo->target, devinfo->lun,
47871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   /*alloc*/TRUE);
47881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sid = (struct scsi_inquiry_data *)dev->target->inq_data;
47901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) {
47911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->flags &= ~AHD_DEV_UNCONFIGURED;
47931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
47941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->flags |= AHD_DEV_UNCONFIGURED;
47951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
47961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
47971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
47991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Update our notion of this device's transfer
48001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * negotiation capabilities.
48011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
48021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tinfo = ahd_fetch_transinfo(ahd, devinfo->channel,
48031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    devinfo->our_scsiid,
48041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    devinfo->target, &tstate);
48051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	user = &tinfo->user;
48061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goal = &tinfo->goal;
48071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	curr = &tinfo->curr;
48081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	width = user->width;
48091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	period = user->period;
48101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	offset = user->offset;
48111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ppr_options = user->ppr_options;
48121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	trans_version = user->transport_version;
48131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	prot_version = MIN(user->protocol_version, SID_ANSI_REV(sid));
48141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
48161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Only attempt SPI3/4 once we've verified that
48171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the device claims to support SPI3/4 features.
48181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
48191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (prot_version < SCSI_REV_2)
48201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		trans_version = SID_ANSI_REV(sid);
48211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
48221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		trans_version = SCSI_REV_2;
48231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((sid->flags & SID_WBus16) == 0)
48251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		width = MSG_EXT_WDTR_BUS_8_BIT;
48261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((sid->flags & SID_Sync) == 0) {
48271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		period = 0;
48281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		offset = 0;
48291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ppr_options = 0;
48301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
48311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((sid->spi3data & SID_SPI_QAS) == 0)
48321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ppr_options &= ~MSG_EXT_PPR_QAS_REQ;
48331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((sid->spi3data & SID_SPI_CLOCK_DT) == 0)
48341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ppr_options &= MSG_EXT_PPR_QAS_REQ;
48351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((sid->spi3data & SID_SPI_IUS) == 0)
48361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ppr_options &= (MSG_EXT_PPR_DT_REQ
48371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      | MSG_EXT_PPR_QAS_REQ);
48381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (prot_version > SCSI_REV_2
48401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && ppr_options != 0)
48411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		trans_version = user->transport_version;
48421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_validate_width(ahd, /*tinfo limit*/NULL, &width, ROLE_UNKNOWN);
48441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX);
48451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_validate_offset(ahd, /*tinfo limit*/NULL, period,
48461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    &offset, width, ROLE_UNKNOWN);
48471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (offset == 0 || period == 0) {
48481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		period = 0;
48491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		offset = 0;
48501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ppr_options = 0;
48511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
48521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Apply our filtered user settings. */
48531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	curr->transport_version = trans_version;
48541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	curr->protocol_version = prot_version;
48551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_set_width(ahd, devinfo, width, AHD_TRANS_GOAL, /*paused*/FALSE);
48561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_set_syncrate(ahd, devinfo, period, offset, ppr_options,
48571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 AHD_TRANS_GOAL, /*paused*/FALSE);
48581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
48591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
48611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_freeze_simq(struct ahd_softc *ahd)
48621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
48631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd->platform_data->qfrozen++;
48641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd->platform_data->qfrozen == 1) {
48651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		scsi_block_requests(ahd->platform_data->host);
48661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_platform_abort_scbs(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS,
48671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					CAM_LUN_WILDCARD, SCB_LIST_NULL,
48681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ROLE_INITIATOR, CAM_REQUEUE_REQ);
48691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
48701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
48711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
48731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_release_simq(struct ahd_softc *ahd)
48741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
48751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long s;
48761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int    unblock_reqs;
48771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unblock_reqs = 0;
48791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_lock(ahd, &s);
48801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd->platform_data->qfrozen > 0)
48811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd->platform_data->qfrozen--;
48821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ahd->platform_data->qfrozen == 0) {
48831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unblock_reqs = 1;
48841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
48851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (AHD_DV_SIMQ_FROZEN(ahd)
48861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && ((ahd->platform_data->flags & AHD_DV_WAIT_SIMQ_RELEASE) != 0)) {
48871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd->platform_data->flags &= ~AHD_DV_WAIT_SIMQ_RELEASE;
48881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up(&ahd->platform_data->dv_sem);
48891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
48901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_schedule_runq(ahd);
48911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_unlock(ahd, &s);
48921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
48931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * There is still a race here.  The mid-layer
48941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * should keep its own freeze count and use
48951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * a bottom half handler to run the queues
48961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * so we can unblock with our own lock held.
48971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
48981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unblock_reqs)
48991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		scsi_unblock_requests(ahd->platform_data->host);
49001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
49011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
49031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_sem_timeout(u_long arg)
49041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
49051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	scb *scb;
49061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct	ahd_softc *ahd;
49071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long	s;
49081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scb = (struct scb *)arg;
49101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd = scb->ahd_softc;
49111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_lock(ahd, &s);
49121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((scb->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) {
49131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		scb->platform_data->flags &= ~AHD_SCB_UP_EH_SEM;
49141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up(&ahd->platform_data->eh_sem);
49151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
49161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_unlock(ahd, &s);
49171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
49181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
49201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_dev_timed_unfreeze(u_long arg)
49211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
49221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_linux_device *dev;
49231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_softc *ahd;
49241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long s;
49251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = (struct ahd_linux_device *)arg;
49271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd = dev->target->ahd;
49281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_lock(ahd, &s);
49291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->flags &= ~AHD_DEV_TIMER_ACTIVE;
49301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->qfrozen > 0)
49311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->qfrozen--;
49321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->qfrozen == 0
49331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && (dev->flags & AHD_DEV_ON_RUN_LIST) == 0)
49341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_run_device_queue(ahd, dev);
49351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0
49361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 && dev->active == 0)
49371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_free_device(ahd, dev);
49381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_unlock(ahd, &s);
49391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
49401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
49421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_platform_dump_card_state(struct ahd_softc *ahd)
49431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
49441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_linux_device *dev;
49451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int target;
49461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int maxtarget;
49471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int lun;
49481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
49491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	maxtarget = (ahd->features & AHD_WIDE) ? 15 : 7;
49511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (target = 0; target <=maxtarget; target++) {
49521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (lun = 0; lun < AHD_NUM_LUNS; lun++) {
49541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct ahd_cmd *acmd;
49551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev = ahd_linux_get_device(ahd, 0, target,
49571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   lun, /*alloc*/FALSE);
49581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (dev == NULL)
49591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
49601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf("DevQ(%d:%d:%d): ", 0, target, lun);
49621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			i = 0;
49631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			TAILQ_FOREACH(acmd, &dev->busyq, acmd_links.tqe) {
49641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (i++ > AHD_SCB_MAX)
49651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
49661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
49671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printf("%d waiting\n", i);
49681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
49691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
49701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
49711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init
49731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_init(void)
49741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
49751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
49761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ahd_linux_detect(&aic79xx_driver_template);
49771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
49781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_register_module(MODULE_SCSI_HA, &aic79xx_driver_template);
49791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (aic79xx_driver_template.present == 0) {
49801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		scsi_unregister_module(MODULE_SCSI_HA,
49811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       &aic79xx_driver_template);
49821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (-ENODEV);
49831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
49841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
49861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
49871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
49881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit
49901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsahd_linux_exit(void)
49911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
49921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ahd_softc *ahd;
49931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
49951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Shutdown DV threads before going into the SCSI mid-layer.
49961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * This avoids situations where the mid-layer locks the entire
49971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * kernel so that waiting for our DV threads to exit leads
49981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to deadlock.
49991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
50001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TAILQ_FOREACH(ahd, &ahd_tailq, links) {
50011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
50021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ahd_linux_kill_dv_thread(ahd);
50031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
50041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
50051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
50061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
50071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * In 2.4 we have to unregister from the PCI core _after_
50081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * unregistering from the scsi midlayer to avoid dangling
50091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * references.
50101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
50111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_unregister_module(MODULE_SCSI_HA, &aic79xx_driver_template);
50121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
50131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ahd_linux_pci_exit();
50141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
50151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
50161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(ahd_linux_init);
50171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(ahd_linux_exit);
5018