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