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