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