13e0a4e85SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* aha152x.c -- Adaptec AHA-152x driver 396de0e25SJan Engelhardt * Author: Jürgen E. Fischer, fischer@norbit.de 496de0e25SJan Engelhardt * Copyright 1993-2004 Jürgen E. Fischer 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * $Id: aha152x.c,v 2.7 2004/01/24 11:42:59 fischer Exp $ 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * $Log: aha152x.c,v $ 91da177e4SLinus Torvalds * Revision 2.7 2004/01/24 11:42:59 fischer 101da177e4SLinus Torvalds * - gather code that is not used by PCMCIA at the end 111da177e4SLinus Torvalds * - move request_region for !PCMCIA case to detection 121da177e4SLinus Torvalds * - migration to new scsi host api (remove legacy code) 131da177e4SLinus Torvalds * - free host scribble before scsi_done 141da177e4SLinus Torvalds * - fix error handling 151da177e4SLinus Torvalds * - one isapnp device added to id_table 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * Revision 2.6 2003/10/30 20:52:47 fischer 181da177e4SLinus Torvalds * - interfaces changes for kernel 2.6 191da177e4SLinus Torvalds * - aha152x_probe_one introduced for pcmcia stub 201da177e4SLinus Torvalds * - fixed pnpdev handling 211da177e4SLinus Torvalds * - instead of allocation a new one, reuse command for request sense after check condition and reset 221da177e4SLinus Torvalds * - fixes race in is_complete 231da177e4SLinus Torvalds * 241da177e4SLinus Torvalds * Revision 2.5 2002/04/14 11:24:53 fischer 251da177e4SLinus Torvalds * - isapnp support 261da177e4SLinus Torvalds * - abort fixed 271da177e4SLinus Torvalds * - 2.5 support 281da177e4SLinus Torvalds * 291da177e4SLinus Torvalds * Revision 2.4 2000/12/16 12:53:56 fischer 301da177e4SLinus Torvalds * - allow REQUEST SENSE to be queued 311da177e4SLinus Torvalds * - handle shared PCI interrupts 321da177e4SLinus Torvalds * 331da177e4SLinus Torvalds * Revision 2.3 2000/11/04 16:40:26 fischer 341da177e4SLinus Torvalds * - handle data overruns 351da177e4SLinus Torvalds * - extend timeout for data phases 361da177e4SLinus Torvalds * 371da177e4SLinus Torvalds * Revision 2.2 2000/08/08 19:54:53 fischer 381da177e4SLinus Torvalds * - minor changes 391da177e4SLinus Torvalds * 401da177e4SLinus Torvalds * Revision 2.1 2000/05/17 16:23:17 fischer 411da177e4SLinus Torvalds * - signature update 421da177e4SLinus Torvalds * - fix for data out w/o scatter gather 431da177e4SLinus Torvalds * 441da177e4SLinus Torvalds * Revision 2.0 1999/12/25 15:07:32 fischer 451da177e4SLinus Torvalds * - interrupt routine completly reworked 461da177e4SLinus Torvalds * - basic support for new eh code 471da177e4SLinus Torvalds * 481da177e4SLinus Torvalds * Revision 1.21 1999/11/10 23:46:36 fischer 491da177e4SLinus Torvalds * - default to synchronous operation 501da177e4SLinus Torvalds * - synchronous negotiation fixed 511da177e4SLinus Torvalds * - added timeout to loops 521da177e4SLinus Torvalds * - debugging output can be controlled through procfs 531da177e4SLinus Torvalds * 541da177e4SLinus Torvalds * Revision 1.20 1999/11/07 18:37:31 fischer 551da177e4SLinus Torvalds * - synchronous operation works 561da177e4SLinus Torvalds * - resid support for sg driver 571da177e4SLinus Torvalds * 581da177e4SLinus Torvalds * Revision 1.19 1999/11/02 22:39:59 fischer 591da177e4SLinus Torvalds * - moved leading comments to README.aha152x 601da177e4SLinus Torvalds * - new additional module parameters 611da177e4SLinus Torvalds * - updates for 2.3 621da177e4SLinus Torvalds * - support for the Tripace TC1550 controller 631da177e4SLinus Torvalds * - interrupt handling changed 641da177e4SLinus Torvalds * 651da177e4SLinus Torvalds * Revision 1.18 1996/09/07 20:10:40 fischer 661da177e4SLinus Torvalds * - fixed can_queue handling (multiple outstanding commands working again) 671da177e4SLinus Torvalds * 681da177e4SLinus Torvalds * Revision 1.17 1996/08/17 16:05:14 fischer 691da177e4SLinus Torvalds * - biosparam improved 701da177e4SLinus Torvalds * - interrupt verification 711da177e4SLinus Torvalds * - updated documentation 721da177e4SLinus Torvalds * - cleanups 731da177e4SLinus Torvalds * 741da177e4SLinus Torvalds * Revision 1.16 1996/06/09 00:04:56 root 751da177e4SLinus Torvalds * - added configuration symbols for insmod (aha152x/aha152x1) 761da177e4SLinus Torvalds * 771da177e4SLinus Torvalds * Revision 1.15 1996/04/30 14:52:06 fischer 781da177e4SLinus Torvalds * - proc info fixed 791da177e4SLinus Torvalds * - support for extended translation for >1GB disks 801da177e4SLinus Torvalds * 811da177e4SLinus Torvalds * Revision 1.14 1996/01/17 15:11:20 fischer 821da177e4SLinus Torvalds * - fixed lockup in MESSAGE IN phase after reconnection 831da177e4SLinus Torvalds * 841da177e4SLinus Torvalds * Revision 1.13 1996/01/09 02:15:53 fischer 851da177e4SLinus Torvalds * - some cleanups 861da177e4SLinus Torvalds * - moved request_irq behind controller initialization 871da177e4SLinus Torvalds * (to avoid spurious interrupts) 881da177e4SLinus Torvalds * 891da177e4SLinus Torvalds * Revision 1.12 1995/12/16 12:26:07 fischer 901da177e4SLinus Torvalds * - barrier()s added 911da177e4SLinus Torvalds * - configurable RESET delay added 921da177e4SLinus Torvalds * 931da177e4SLinus Torvalds * Revision 1.11 1995/12/06 21:18:35 fischer 941da177e4SLinus Torvalds * - some minor updates 951da177e4SLinus Torvalds * 961da177e4SLinus Torvalds * Revision 1.10 1995/07/22 19:18:45 fischer 971da177e4SLinus Torvalds * - support for 2 controllers 981da177e4SLinus Torvalds * - started synchronous data transfers (not working yet) 991da177e4SLinus Torvalds * 1001da177e4SLinus Torvalds * Revision 1.9 1995/03/18 09:20:24 root 1011da177e4SLinus Torvalds * - patches for PCMCIA and modules 1021da177e4SLinus Torvalds * 1031da177e4SLinus Torvalds * Revision 1.8 1995/01/21 22:07:19 root 1041da177e4SLinus Torvalds * - snarf_region => request_region 1051da177e4SLinus Torvalds * - aha152x_intr interface change 1061da177e4SLinus Torvalds * 1071da177e4SLinus Torvalds * Revision 1.7 1995/01/02 23:19:36 root 1081da177e4SLinus Torvalds * - updated COMMAND_SIZE to cmd_len 1091da177e4SLinus Torvalds * - changed sti() to restore_flags() 1101da177e4SLinus Torvalds * - fixed some #ifdef which generated warnings 1111da177e4SLinus Torvalds * 1121da177e4SLinus Torvalds * Revision 1.6 1994/11/24 20:35:27 root 1131da177e4SLinus Torvalds * - problem with odd number of bytes in fifo fixed 1141da177e4SLinus Torvalds * 1151da177e4SLinus Torvalds * Revision 1.5 1994/10/30 14:39:56 root 1161da177e4SLinus Torvalds * - abort code fixed 1171da177e4SLinus Torvalds * - debugging improved 1181da177e4SLinus Torvalds * 1191da177e4SLinus Torvalds * Revision 1.4 1994/09/12 11:33:01 root 1201da177e4SLinus Torvalds * - irqaction to request_irq 1211da177e4SLinus Torvalds * - abortion updated 1221da177e4SLinus Torvalds * 1231da177e4SLinus Torvalds * Revision 1.3 1994/08/04 13:53:05 root 1241da177e4SLinus Torvalds * - updates for mid-level-driver changes 1251da177e4SLinus Torvalds * - accept unexpected BUSFREE phase as error condition 1261da177e4SLinus Torvalds * - parity check now configurable 1271da177e4SLinus Torvalds * 1281da177e4SLinus Torvalds * Revision 1.2 1994/07/03 12:56:36 root 1291da177e4SLinus Torvalds * - cleaned up debugging code 1301da177e4SLinus Torvalds * - more tweaking on reset delays 1311da177e4SLinus Torvalds * - updated abort/reset code (pretty untested...) 1321da177e4SLinus Torvalds * 1331da177e4SLinus Torvalds * Revision 1.1 1994/05/28 21:18:49 root 1341da177e4SLinus Torvalds * - update for mid-level interface change (abort-reset) 1351da177e4SLinus Torvalds * - delays after resets adjusted for some slow devices 1361da177e4SLinus Torvalds * 1371da177e4SLinus Torvalds * Revision 1.0 1994/03/25 12:52:00 root 1381da177e4SLinus Torvalds * - Fixed "more data than expected" problem 1391da177e4SLinus Torvalds * - added new BIOS signatures 1401da177e4SLinus Torvalds * 1411da177e4SLinus Torvalds * Revision 0.102 1994/01/31 20:44:12 root 1421da177e4SLinus Torvalds * - minor changes in insw/outsw handling 1431da177e4SLinus Torvalds * 1441da177e4SLinus Torvalds * Revision 0.101 1993/12/13 01:16:27 root 1451da177e4SLinus Torvalds * - fixed STATUS phase (non-GOOD stati were dropped sometimes; 1461da177e4SLinus Torvalds * fixes problems with CD-ROM sector size detection & media change) 1471da177e4SLinus Torvalds * 1481da177e4SLinus Torvalds * Revision 0.100 1993/12/10 16:58:47 root 1491da177e4SLinus Torvalds * - fix for unsuccessful selections in case of non-continuous id assignments 1501da177e4SLinus Torvalds * on the scsi bus. 1511da177e4SLinus Torvalds * 1521da177e4SLinus Torvalds * Revision 0.99 1993/10/24 16:19:59 root 1531da177e4SLinus Torvalds * - fixed DATA IN (rare read errors gone) 1541da177e4SLinus Torvalds * 1551da177e4SLinus Torvalds * Revision 0.98 1993/10/17 12:54:44 root 1561da177e4SLinus Torvalds * - fixed some recent fixes (shame on me) 1571da177e4SLinus Torvalds * - moved initialization of scratch area to aha152x_queue 1581da177e4SLinus Torvalds * 1591da177e4SLinus Torvalds * Revision 0.97 1993/10/09 18:53:53 root 1601da177e4SLinus Torvalds * - DATA IN fixed. Rarely left data in the fifo. 1611da177e4SLinus Torvalds * 1621da177e4SLinus Torvalds * Revision 0.96 1993/10/03 00:53:59 root 1631da177e4SLinus Torvalds * - minor changes on DATA IN 1641da177e4SLinus Torvalds * 1651da177e4SLinus Torvalds * Revision 0.95 1993/09/24 10:36:01 root 1661da177e4SLinus Torvalds * - change handling of MSGI after reselection 1671da177e4SLinus Torvalds * - fixed sti/cli 1681da177e4SLinus Torvalds * - minor changes 1691da177e4SLinus Torvalds * 1701da177e4SLinus Torvalds * Revision 0.94 1993/09/18 14:08:22 root 1711da177e4SLinus Torvalds * - fixed bug in multiple outstanding command code 1721da177e4SLinus Torvalds * - changed detection 1731da177e4SLinus Torvalds * - support for kernel command line configuration 1741da177e4SLinus Torvalds * - reset corrected 1751da177e4SLinus Torvalds * - changed message handling 1761da177e4SLinus Torvalds * 1771da177e4SLinus Torvalds * Revision 0.93 1993/09/15 20:41:19 root 1781da177e4SLinus Torvalds * - fixed bugs with multiple outstanding commands 1791da177e4SLinus Torvalds * 1801da177e4SLinus Torvalds * Revision 0.92 1993/09/13 02:46:33 root 1811da177e4SLinus Torvalds * - multiple outstanding commands work (no problems with IBM drive) 1821da177e4SLinus Torvalds * 1831da177e4SLinus Torvalds * Revision 0.91 1993/09/12 20:51:46 root 1841da177e4SLinus Torvalds * added multiple outstanding commands 1851da177e4SLinus Torvalds * (some problem with this $%&? IBM device remain) 1861da177e4SLinus Torvalds * 1871da177e4SLinus Torvalds * Revision 0.9 1993/09/12 11:11:22 root 1881da177e4SLinus Torvalds * - corrected auto-configuration 1891da177e4SLinus Torvalds * - changed the auto-configuration (added some '#define's) 1901da177e4SLinus Torvalds * - added support for dis-/reconnection 1911da177e4SLinus Torvalds * 1921da177e4SLinus Torvalds * Revision 0.8 1993/09/06 23:09:39 root 1931da177e4SLinus Torvalds * - added support for the drive activity light 1941da177e4SLinus Torvalds * - minor changes 1951da177e4SLinus Torvalds * 1961da177e4SLinus Torvalds * Revision 0.7 1993/09/05 14:30:15 root 1971da177e4SLinus Torvalds * - improved phase detection 1981da177e4SLinus Torvalds * - now using the new snarf_region code of 0.99pl13 1991da177e4SLinus Torvalds * 2001da177e4SLinus Torvalds * Revision 0.6 1993/09/02 11:01:38 root 2011da177e4SLinus Torvalds * first public release; added some signatures and biosparam() 2021da177e4SLinus Torvalds * 2031da177e4SLinus Torvalds * Revision 0.5 1993/08/30 10:23:30 root 2041da177e4SLinus Torvalds * fixed timing problems with my IBM drive 2051da177e4SLinus Torvalds * 2061da177e4SLinus Torvalds * Revision 0.4 1993/08/29 14:06:52 root 2071da177e4SLinus Torvalds * fixed some problems with timeouts due incomplete commands 2081da177e4SLinus Torvalds * 2091da177e4SLinus Torvalds * Revision 0.3 1993/08/28 15:55:03 root 2101da177e4SLinus Torvalds * writing data works too. mounted and worked on a dos partition 2111da177e4SLinus Torvalds * 2121da177e4SLinus Torvalds * Revision 0.2 1993/08/27 22:42:07 root 2131da177e4SLinus Torvalds * reading data works. Mounted a msdos partition. 2141da177e4SLinus Torvalds * 2151da177e4SLinus Torvalds * Revision 0.1 1993/08/25 13:38:30 root 2161da177e4SLinus Torvalds * first "damn thing doesn't work" version 2171da177e4SLinus Torvalds * 2181da177e4SLinus Torvalds * Revision 0.0 1993/08/14 19:54:25 root 2191da177e4SLinus Torvalds * empty function bodies; detect() works. 2201da177e4SLinus Torvalds * 2211da177e4SLinus Torvalds ************************************************************************** 2221da177e4SLinus Torvalds 22394b5530fSMauro Carvalho Chehab see Documentation/scsi/aha152x.rst for configuration details 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds **************************************************************************/ 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds #include <linux/module.h> 2281da177e4SLinus Torvalds #include <asm/irq.h> 22953d5ed62SMatthew Wilcox #include <linux/io.h> 2301da177e4SLinus Torvalds #include <linux/blkdev.h> 2310f06bb34SChristoph Hellwig #include <linux/completion.h> 2321da177e4SLinus Torvalds #include <linux/errno.h> 2331da177e4SLinus Torvalds #include <linux/string.h> 2341da177e4SLinus Torvalds #include <linux/wait.h> 2351da177e4SLinus Torvalds #include <linux/ioport.h> 2361da177e4SLinus Torvalds #include <linux/delay.h> 2371da177e4SLinus Torvalds #include <linux/proc_fs.h> 2381da177e4SLinus Torvalds #include <linux/interrupt.h> 2391da177e4SLinus Torvalds #include <linux/init.h> 2401da177e4SLinus Torvalds #include <linux/kernel.h> 2411da177e4SLinus Torvalds #include <linux/isapnp.h> 2421da177e4SLinus Torvalds #include <linux/spinlock.h> 2431da177e4SLinus Torvalds #include <linux/workqueue.h> 2445fcda422SJames Bottomley #include <linux/list.h> 2455a0e3ad6STejun Heo #include <linux/slab.h> 2461da177e4SLinus Torvalds #include <scsi/scsicam.h> 2471da177e4SLinus Torvalds 2481da177e4SLinus Torvalds #include "scsi.h" 249db9dff36S #include <scsi/scsi_dbg.h> 2501da177e4SLinus Torvalds #include <scsi/scsi_host.h> 2511abfd370SMatthew Wilcox #include <scsi/scsi_transport_spi.h> 25273d2cb16SBoaz Harrosh #include <scsi/scsi_eh.h> 2531da177e4SLinus Torvalds #include "aha152x.h" 2541da177e4SLinus Torvalds 2555fcda422SJames Bottomley static LIST_HEAD(aha152x_host_list); 2565fcda422SJames Bottomley 2571da177e4SLinus Torvalds 2581da177e4SLinus Torvalds /* DEFINES */ 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds /* For PCMCIA cards, always use AUTOCONF */ 2613eb2ebcbSChristoph Hellwig #if defined(AHA152X_PCMCIA) || defined(MODULE) 2621da177e4SLinus Torvalds #if !defined(AUTOCONF) 2631da177e4SLinus Torvalds #define AUTOCONF 2641da177e4SLinus Torvalds #endif 2651da177e4SLinus Torvalds #endif 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds #if !defined(AUTOCONF) && !defined(SETUP0) 2681da177e4SLinus Torvalds #error define AUTOCONF or SETUP0 2691da177e4SLinus Torvalds #endif 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds #define DO_LOCK(flags) spin_lock_irqsave(&QLOCK,flags) 2721da177e4SLinus Torvalds #define DO_UNLOCK(flags) spin_unlock_irqrestore(&QLOCK,flags) 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds #define LEAD "(scsi%d:%d:%d) " 2751da177e4SLinus Torvalds #define INFO_LEAD KERN_INFO LEAD 2761da177e4SLinus Torvalds #define CMDINFO(cmd) \ 2771da177e4SLinus Torvalds (cmd) ? ((cmd)->device->host->host_no) : -1, \ 2781da177e4SLinus Torvalds (cmd) ? ((cmd)->device->id & 0x0f) : -1, \ 2799cb78c16SHannes Reinecke (cmd) ? ((u8)(cmd)->device->lun & 0x07) : -1 2801da177e4SLinus Torvalds 2812338545aSBoaz Harrosh static inline void 2822338545aSBoaz Harrosh CMD_INC_RESID(struct scsi_cmnd *cmd, int inc) 2832338545aSBoaz Harrosh { 2842338545aSBoaz Harrosh scsi_set_resid(cmd, scsi_get_resid(cmd) + inc); 2852338545aSBoaz Harrosh } 2862338545aSBoaz Harrosh 2871da177e4SLinus Torvalds #define DELAY_DEFAULT 1000 2881da177e4SLinus Torvalds 2893eb2ebcbSChristoph Hellwig #if defined(AHA152X_PCMCIA) 2901da177e4SLinus Torvalds #define IRQ_MIN 0 2911da177e4SLinus Torvalds #define IRQ_MAX 16 2921da177e4SLinus Torvalds #else 2931da177e4SLinus Torvalds #define IRQ_MIN 9 2941da177e4SLinus Torvalds #if defined(__PPC) 295171ac6aeSYinghai Lu #define IRQ_MAX (nr_irqs-1) 2961da177e4SLinus Torvalds #else 2971da177e4SLinus Torvalds #define IRQ_MAX 12 2981da177e4SLinus Torvalds #endif 2991da177e4SLinus Torvalds #endif 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds enum { 3021da177e4SLinus Torvalds not_issued = 0x0001, /* command not yet issued */ 303f75ae8edSHannes Reinecke selecting = 0x0002, /* target is being selected */ 3041da177e4SLinus Torvalds identified = 0x0004, /* IDENTIFY was sent */ 3051da177e4SLinus Torvalds disconnected = 0x0008, /* target disconnected */ 3061da177e4SLinus Torvalds completed = 0x0010, /* target sent COMMAND COMPLETE */ 3071da177e4SLinus Torvalds aborted = 0x0020, /* ABORT was sent */ 3081da177e4SLinus Torvalds resetted = 0x0040, /* BUS DEVICE RESET was sent */ 3091da177e4SLinus Torvalds spiordy = 0x0080, /* waiting for SPIORDY to raise */ 3101da177e4SLinus Torvalds syncneg = 0x0100, /* synchronous negotiation in progress */ 3111da177e4SLinus Torvalds aborting = 0x0200, /* ABORT is pending */ 3121da177e4SLinus Torvalds resetting = 0x0400, /* BUS DEVICE RESET is pending */ 3131da177e4SLinus Torvalds check_condition = 0x0800, /* requesting sense after CHECK CONDITION */ 3141da177e4SLinus Torvalds }; 3151da177e4SLinus Torvalds 31696de0e25SJan Engelhardt MODULE_AUTHOR("Jürgen Fischer"); 3171da177e4SLinus Torvalds MODULE_DESCRIPTION(AHA152X_REVID); 3181da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 3191da177e4SLinus Torvalds 3203eb2ebcbSChristoph Hellwig #if !defined(AHA152X_PCMCIA) 3211da177e4SLinus Torvalds #if defined(MODULE) 3221da177e4SLinus Torvalds static int io[] = {0, 0}; 32388f06b76SDavid Howells module_param_hw_array(io, int, ioport, NULL, 0); 3241da177e4SLinus Torvalds MODULE_PARM_DESC(io,"base io address of controller"); 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds static int irq[] = {0, 0}; 32788f06b76SDavid Howells module_param_hw_array(irq, int, irq, NULL, 0); 3281da177e4SLinus Torvalds MODULE_PARM_DESC(irq,"interrupt for controller"); 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds static int scsiid[] = {7, 7}; 3311da177e4SLinus Torvalds module_param_array(scsiid, int, NULL, 0); 3321da177e4SLinus Torvalds MODULE_PARM_DESC(scsiid,"scsi id of controller"); 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds static int reconnect[] = {1, 1}; 3351da177e4SLinus Torvalds module_param_array(reconnect, int, NULL, 0); 3361da177e4SLinus Torvalds MODULE_PARM_DESC(reconnect,"allow targets to disconnect"); 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds static int parity[] = {1, 1}; 3391da177e4SLinus Torvalds module_param_array(parity, int, NULL, 0); 3401da177e4SLinus Torvalds MODULE_PARM_DESC(parity,"use scsi parity"); 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds static int sync[] = {1, 1}; 3431da177e4SLinus Torvalds module_param_array(sync, int, NULL, 0); 3441da177e4SLinus Torvalds MODULE_PARM_DESC(sync,"use synchronous transfers"); 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds static int delay[] = {DELAY_DEFAULT, DELAY_DEFAULT}; 3471da177e4SLinus Torvalds module_param_array(delay, int, NULL, 0); 3481da177e4SLinus Torvalds MODULE_PARM_DESC(delay,"scsi reset delay"); 3491da177e4SLinus Torvalds 3501da177e4SLinus Torvalds static int exttrans[] = {0, 0}; 3511da177e4SLinus Torvalds module_param_array(exttrans, int, NULL, 0); 3521da177e4SLinus Torvalds MODULE_PARM_DESC(exttrans,"use extended translation"); 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds static int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; 3551da177e4SLinus Torvalds module_param_array(aha152x, int, NULL, 0); 3561da177e4SLinus Torvalds MODULE_PARM_DESC(aha152x, "parameters for first controller"); 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds static int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; 3591da177e4SLinus Torvalds module_param_array(aha152x1, int, NULL, 0); 3601da177e4SLinus Torvalds MODULE_PARM_DESC(aha152x1, "parameters for second controller"); 3611da177e4SLinus Torvalds #endif /* MODULE */ 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds #ifdef __ISAPNP__ 3646f039790SGreg Kroah-Hartman static struct isapnp_device_id id_table[] = { 36550f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1502), 0 }, 36650f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1505), 0 }, 36750f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1510), 0 }, 36850f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1515), 0 }, 36950f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1520), 0 }, 37050f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2015), 0 }, 37150f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1522), 0 }, 37250f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2215), 0 }, 37350f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1530), 0 }, 37450f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3015), 0 }, 37550f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1532), 0 }, 37650f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3215), 0 }, 37750f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x6360), 0 }, 3781da177e4SLinus Torvalds { ISAPNP_DEVICE_SINGLE_END, } 3791da177e4SLinus Torvalds }; 3801da177e4SLinus Torvalds MODULE_DEVICE_TABLE(isapnp, id_table); 3811da177e4SLinus Torvalds #endif /* ISAPNP */ 3821da177e4SLinus Torvalds 3833eb2ebcbSChristoph Hellwig #endif /* !AHA152X_PCMCIA */ 3841da177e4SLinus Torvalds 385d0be4a7dSChristoph Hellwig static struct scsi_host_template aha152x_driver_template; 3861da177e4SLinus Torvalds 3871da177e4SLinus Torvalds /* 3881da177e4SLinus Torvalds * internal states of the host 3891da177e4SLinus Torvalds * 3901da177e4SLinus Torvalds */ 3911da177e4SLinus Torvalds enum aha152x_state { 3921da177e4SLinus Torvalds idle=0, 3931da177e4SLinus Torvalds unknown, 3941da177e4SLinus Torvalds seldo, 3951da177e4SLinus Torvalds seldi, 3961da177e4SLinus Torvalds selto, 3971da177e4SLinus Torvalds busfree, 3981da177e4SLinus Torvalds msgo, 3991da177e4SLinus Torvalds cmd, 4001da177e4SLinus Torvalds msgi, 4011da177e4SLinus Torvalds status, 4021da177e4SLinus Torvalds datai, 4031da177e4SLinus Torvalds datao, 4041da177e4SLinus Torvalds parerr, 4051da177e4SLinus Torvalds rsti, 4061da177e4SLinus Torvalds maxstate 4071da177e4SLinus Torvalds }; 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds /* 4101da177e4SLinus Torvalds * current state information of the host 4111da177e4SLinus Torvalds * 4121da177e4SLinus Torvalds */ 4131da177e4SLinus Torvalds struct aha152x_hostdata { 41491ebc1faSJohannes Thumshirn struct scsi_cmnd *issue_SC; 4151da177e4SLinus Torvalds /* pending commands to issue */ 4161da177e4SLinus Torvalds 41791ebc1faSJohannes Thumshirn struct scsi_cmnd *current_SC; 4181da177e4SLinus Torvalds /* current command on the bus */ 4191da177e4SLinus Torvalds 42091ebc1faSJohannes Thumshirn struct scsi_cmnd *disconnected_SC; 4211da177e4SLinus Torvalds /* commands that disconnected */ 4221da177e4SLinus Torvalds 42391ebc1faSJohannes Thumshirn struct scsi_cmnd *done_SC; 4241da177e4SLinus Torvalds /* command that was completed */ 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds spinlock_t lock; 4271da177e4SLinus Torvalds /* host lock */ 4281da177e4SLinus Torvalds 4291da177e4SLinus Torvalds #if defined(AHA152X_STAT) 4301da177e4SLinus Torvalds int total_commands; 4311da177e4SLinus Torvalds int disconnections; 4321da177e4SLinus Torvalds int busfree_without_any_action; 4331da177e4SLinus Torvalds int busfree_without_old_command; 4341da177e4SLinus Torvalds int busfree_without_new_command; 4351da177e4SLinus Torvalds int busfree_without_done_command; 4361da177e4SLinus Torvalds int busfree_with_check_condition; 4371da177e4SLinus Torvalds int count[maxstate]; 4381da177e4SLinus Torvalds int count_trans[maxstate]; 4391da177e4SLinus Torvalds unsigned long time[maxstate]; 4401da177e4SLinus Torvalds #endif 4411da177e4SLinus Torvalds 4421da177e4SLinus Torvalds int commands; /* current number of commands */ 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds int reconnect; /* disconnection allowed */ 4451da177e4SLinus Torvalds int parity; /* parity checking enabled */ 4461da177e4SLinus Torvalds int synchronous; /* synchronous transferes enabled */ 4471da177e4SLinus Torvalds int delay; /* reset out delay */ 4481da177e4SLinus Torvalds int ext_trans; /* extended translation enabled */ 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds int swint; /* software-interrupt was fired during detect() */ 4511da177e4SLinus Torvalds int service; /* bh needs to be run */ 4521da177e4SLinus Torvalds int in_intr; /* bh is running */ 4531da177e4SLinus Torvalds 4541da177e4SLinus Torvalds /* current state, 4551da177e4SLinus Torvalds previous state, 4561da177e4SLinus Torvalds last state different from current state */ 4571da177e4SLinus Torvalds enum aha152x_state state, prevstate, laststate; 4581da177e4SLinus Torvalds 4591da177e4SLinus Torvalds int target; 4601da177e4SLinus Torvalds /* reconnecting target */ 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds unsigned char syncrate[8]; 4631da177e4SLinus Torvalds /* current synchronous transfer agreements */ 4641da177e4SLinus Torvalds 4651da177e4SLinus Torvalds unsigned char syncneg[8]; 4661da177e4SLinus Torvalds /* 0: no negotiation; 4671da177e4SLinus Torvalds * 1: negotiation in progress; 4681da177e4SLinus Torvalds * 2: negotiation completed 4691da177e4SLinus Torvalds */ 4701da177e4SLinus Torvalds 4711da177e4SLinus Torvalds int cmd_i; 4721da177e4SLinus Torvalds /* number of sent bytes of current command */ 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds int msgi_len; 4751da177e4SLinus Torvalds /* number of received message bytes */ 4761da177e4SLinus Torvalds unsigned char msgi[256]; 4771da177e4SLinus Torvalds /* received message bytes */ 4781da177e4SLinus Torvalds 4791da177e4SLinus Torvalds int msgo_i, msgo_len; 4801da177e4SLinus Torvalds /* number of sent bytes and length of current messages */ 4811da177e4SLinus Torvalds unsigned char msgo[256]; 4821da177e4SLinus Torvalds /* pending messages */ 4831da177e4SLinus Torvalds 4841da177e4SLinus Torvalds int data_len; 4851da177e4SLinus Torvalds /* number of sent/received bytes in dataphase */ 4861da177e4SLinus Torvalds 4871da177e4SLinus Torvalds unsigned long io_port0; 4881da177e4SLinus Torvalds unsigned long io_port1; 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds #ifdef __ISAPNP__ 4911da177e4SLinus Torvalds struct pnp_dev *pnpdev; 4921da177e4SLinus Torvalds #endif 4935fcda422SJames Bottomley struct list_head host_list; 4941da177e4SLinus Torvalds }; 4951da177e4SLinus Torvalds 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds /* 4981da177e4SLinus Torvalds * host specific command extension 4991da177e4SLinus Torvalds * 5001da177e4SLinus Torvalds */ 5011da177e4SLinus Torvalds struct aha152x_scdata { 50291ebc1faSJohannes Thumshirn struct scsi_cmnd *next; /* next sc in queue */ 5030f06bb34SChristoph Hellwig struct completion *done;/* semaphore to block on */ 50473d2cb16SBoaz Harrosh struct scsi_eh_save ses; 5051da177e4SLinus Torvalds }; 5061da177e4SLinus Torvalds 5071da177e4SLinus Torvalds /* access macros for hostdata */ 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds #define HOSTDATA(shpnt) ((struct aha152x_hostdata *) &shpnt->hostdata) 5101da177e4SLinus Torvalds 5111da177e4SLinus Torvalds #define HOSTNO ((shpnt)->host_no) 5121da177e4SLinus Torvalds 5131da177e4SLinus Torvalds #define CURRENT_SC (HOSTDATA(shpnt)->current_SC) 5141da177e4SLinus Torvalds #define DONE_SC (HOSTDATA(shpnt)->done_SC) 5151da177e4SLinus Torvalds #define ISSUE_SC (HOSTDATA(shpnt)->issue_SC) 5161da177e4SLinus Torvalds #define DISCONNECTED_SC (HOSTDATA(shpnt)->disconnected_SC) 5171da177e4SLinus Torvalds #define QLOCK (HOSTDATA(shpnt)->lock) 5181da177e4SLinus Torvalds #define QLOCKER (HOSTDATA(shpnt)->locker) 5191da177e4SLinus Torvalds #define QLOCKERL (HOSTDATA(shpnt)->lockerl) 5201da177e4SLinus Torvalds 5211da177e4SLinus Torvalds #define STATE (HOSTDATA(shpnt)->state) 5221da177e4SLinus Torvalds #define PREVSTATE (HOSTDATA(shpnt)->prevstate) 5231da177e4SLinus Torvalds #define LASTSTATE (HOSTDATA(shpnt)->laststate) 5241da177e4SLinus Torvalds 5251da177e4SLinus Torvalds #define RECONN_TARGET (HOSTDATA(shpnt)->target) 5261da177e4SLinus Torvalds 5271da177e4SLinus Torvalds #define CMD_I (HOSTDATA(shpnt)->cmd_i) 5281da177e4SLinus Torvalds 5291da177e4SLinus Torvalds #define MSGO(i) (HOSTDATA(shpnt)->msgo[i]) 5301da177e4SLinus Torvalds #define MSGO_I (HOSTDATA(shpnt)->msgo_i) 5311da177e4SLinus Torvalds #define MSGOLEN (HOSTDATA(shpnt)->msgo_len) 5321da177e4SLinus Torvalds #define ADDMSGO(x) (MSGOLEN<256 ? (void)(MSGO(MSGOLEN++)=x) : aha152x_error(shpnt,"MSGO overflow")) 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds #define MSGI(i) (HOSTDATA(shpnt)->msgi[i]) 5351da177e4SLinus Torvalds #define MSGILEN (HOSTDATA(shpnt)->msgi_len) 5361da177e4SLinus Torvalds #define ADDMSGI(x) (MSGILEN<256 ? (void)(MSGI(MSGILEN++)=x) : aha152x_error(shpnt,"MSGI overflow")) 5371da177e4SLinus Torvalds 5381da177e4SLinus Torvalds #define DATA_LEN (HOSTDATA(shpnt)->data_len) 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds #define SYNCRATE (HOSTDATA(shpnt)->syncrate[CURRENT_SC->device->id]) 5411da177e4SLinus Torvalds #define SYNCNEG (HOSTDATA(shpnt)->syncneg[CURRENT_SC->device->id]) 5421da177e4SLinus Torvalds 5431da177e4SLinus Torvalds #define DELAY (HOSTDATA(shpnt)->delay) 5441da177e4SLinus Torvalds #define EXT_TRANS (HOSTDATA(shpnt)->ext_trans) 5451da177e4SLinus Torvalds #define TC1550 (HOSTDATA(shpnt)->tc1550) 5461da177e4SLinus Torvalds #define RECONNECT (HOSTDATA(shpnt)->reconnect) 5471da177e4SLinus Torvalds #define PARITY (HOSTDATA(shpnt)->parity) 5481da177e4SLinus Torvalds #define SYNCHRONOUS (HOSTDATA(shpnt)->synchronous) 5491da177e4SLinus Torvalds 5501da177e4SLinus Torvalds #define HOSTIOPORT0 (HOSTDATA(shpnt)->io_port0) 5511da177e4SLinus Torvalds #define HOSTIOPORT1 (HOSTDATA(shpnt)->io_port1) 5521da177e4SLinus Torvalds 5531da177e4SLinus Torvalds #define SCDATA(SCpnt) ((struct aha152x_scdata *) (SCpnt)->host_scribble) 5541da177e4SLinus Torvalds #define SCNEXT(SCpnt) SCDATA(SCpnt)->next 5550f06bb34SChristoph Hellwig #define SCSEM(SCpnt) SCDATA(SCpnt)->done 5561da177e4SLinus Torvalds 55745711f1aSJens Axboe #define SG_ADDRESS(buffer) ((char *) sg_virt((buffer))) 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds /* state handling */ 5601da177e4SLinus Torvalds static void seldi_run(struct Scsi_Host *shpnt); 5611da177e4SLinus Torvalds static void seldo_run(struct Scsi_Host *shpnt); 5621da177e4SLinus Torvalds static void selto_run(struct Scsi_Host *shpnt); 5631da177e4SLinus Torvalds static void busfree_run(struct Scsi_Host *shpnt); 5641da177e4SLinus Torvalds 5651da177e4SLinus Torvalds static void msgo_init(struct Scsi_Host *shpnt); 5661da177e4SLinus Torvalds static void msgo_run(struct Scsi_Host *shpnt); 5671da177e4SLinus Torvalds static void msgo_end(struct Scsi_Host *shpnt); 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds static void cmd_init(struct Scsi_Host *shpnt); 5701da177e4SLinus Torvalds static void cmd_run(struct Scsi_Host *shpnt); 5711da177e4SLinus Torvalds static void cmd_end(struct Scsi_Host *shpnt); 5721da177e4SLinus Torvalds 5731da177e4SLinus Torvalds static void datai_init(struct Scsi_Host *shpnt); 5741da177e4SLinus Torvalds static void datai_run(struct Scsi_Host *shpnt); 5751da177e4SLinus Torvalds static void datai_end(struct Scsi_Host *shpnt); 5761da177e4SLinus Torvalds 5771da177e4SLinus Torvalds static void datao_init(struct Scsi_Host *shpnt); 5781da177e4SLinus Torvalds static void datao_run(struct Scsi_Host *shpnt); 5791da177e4SLinus Torvalds static void datao_end(struct Scsi_Host *shpnt); 5801da177e4SLinus Torvalds 5811da177e4SLinus Torvalds static void status_run(struct Scsi_Host *shpnt); 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds static void msgi_run(struct Scsi_Host *shpnt); 5841da177e4SLinus Torvalds static void msgi_end(struct Scsi_Host *shpnt); 5851da177e4SLinus Torvalds 5861da177e4SLinus Torvalds static void parerr_run(struct Scsi_Host *shpnt); 5871da177e4SLinus Torvalds static void rsti_run(struct Scsi_Host *shpnt); 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds static void is_complete(struct Scsi_Host *shpnt); 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds /* 5921da177e4SLinus Torvalds * driver states 5931da177e4SLinus Torvalds * 5941da177e4SLinus Torvalds */ 5951da177e4SLinus Torvalds static struct { 5961da177e4SLinus Torvalds char *name; 5971da177e4SLinus Torvalds void (*init)(struct Scsi_Host *); 5981da177e4SLinus Torvalds void (*run)(struct Scsi_Host *); 5991da177e4SLinus Torvalds void (*end)(struct Scsi_Host *); 6001da177e4SLinus Torvalds int spio; 6011da177e4SLinus Torvalds } states[] = { 6021da177e4SLinus Torvalds { "idle", NULL, NULL, NULL, 0}, 6031da177e4SLinus Torvalds { "unknown", NULL, NULL, NULL, 0}, 6041da177e4SLinus Torvalds { "seldo", NULL, seldo_run, NULL, 0}, 6051da177e4SLinus Torvalds { "seldi", NULL, seldi_run, NULL, 0}, 6061da177e4SLinus Torvalds { "selto", NULL, selto_run, NULL, 0}, 6071da177e4SLinus Torvalds { "busfree", NULL, busfree_run, NULL, 0}, 6081da177e4SLinus Torvalds { "msgo", msgo_init, msgo_run, msgo_end, 1}, 6091da177e4SLinus Torvalds { "cmd", cmd_init, cmd_run, cmd_end, 1}, 6101da177e4SLinus Torvalds { "msgi", NULL, msgi_run, msgi_end, 1}, 6111da177e4SLinus Torvalds { "status", NULL, status_run, NULL, 1}, 6121da177e4SLinus Torvalds { "datai", datai_init, datai_run, datai_end, 0}, 6131da177e4SLinus Torvalds { "datao", datao_init, datao_run, datao_end, 0}, 6141da177e4SLinus Torvalds { "parerr", NULL, parerr_run, NULL, 0}, 6151da177e4SLinus Torvalds { "rsti", NULL, rsti_run, NULL, 0}, 6161da177e4SLinus Torvalds }; 6171da177e4SLinus Torvalds 6181da177e4SLinus Torvalds /* setup & interrupt */ 6197d12e780SDavid Howells static irqreturn_t intr(int irq, void *dev_id); 6201da177e4SLinus Torvalds static void reset_ports(struct Scsi_Host *shpnt); 6211da177e4SLinus Torvalds static void aha152x_error(struct Scsi_Host *shpnt, char *msg); 6221da177e4SLinus Torvalds static void done(struct Scsi_Host *shpnt, int error); 6231da177e4SLinus Torvalds 6241da177e4SLinus Torvalds /* diagnostics */ 62591ebc1faSJohannes Thumshirn static void show_command(struct scsi_cmnd * ptr); 6261da177e4SLinus Torvalds static void show_queues(struct Scsi_Host *shpnt); 6271da177e4SLinus Torvalds static void disp_enintr(struct Scsi_Host *shpnt); 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds 6301da177e4SLinus Torvalds /* 6311da177e4SLinus Torvalds * queue services: 6321da177e4SLinus Torvalds * 6331da177e4SLinus Torvalds */ 63491ebc1faSJohannes Thumshirn static inline void append_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC) 6351da177e4SLinus Torvalds { 63691ebc1faSJohannes Thumshirn struct scsi_cmnd *end; 6371da177e4SLinus Torvalds 6381da177e4SLinus Torvalds SCNEXT(new_SC) = NULL; 6391da177e4SLinus Torvalds if (!*SC) 6401da177e4SLinus Torvalds *SC = new_SC; 6411da177e4SLinus Torvalds else { 6421da177e4SLinus Torvalds for (end = *SC; SCNEXT(end); end = SCNEXT(end)) 6431da177e4SLinus Torvalds ; 6441da177e4SLinus Torvalds SCNEXT(end) = new_SC; 6451da177e4SLinus Torvalds } 6461da177e4SLinus Torvalds } 6471da177e4SLinus Torvalds 64891ebc1faSJohannes Thumshirn static inline struct scsi_cmnd *remove_first_SC(struct scsi_cmnd ** SC) 6491da177e4SLinus Torvalds { 65091ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr; 6511da177e4SLinus Torvalds 6521da177e4SLinus Torvalds ptr = *SC; 6531da177e4SLinus Torvalds if (ptr) { 6541da177e4SLinus Torvalds *SC = SCNEXT(*SC); 6551da177e4SLinus Torvalds SCNEXT(ptr)=NULL; 6561da177e4SLinus Torvalds } 6571da177e4SLinus Torvalds return ptr; 6581da177e4SLinus Torvalds } 6591da177e4SLinus Torvalds 66091ebc1faSJohannes Thumshirn static inline struct scsi_cmnd *remove_lun_SC(struct scsi_cmnd ** SC, 66191ebc1faSJohannes Thumshirn int target, int lun) 6621da177e4SLinus Torvalds { 66391ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr, *prev; 6641da177e4SLinus Torvalds 6651da177e4SLinus Torvalds for (ptr = *SC, prev = NULL; 6661da177e4SLinus Torvalds ptr && ((ptr->device->id != target) || (ptr->device->lun != lun)); 6671da177e4SLinus Torvalds prev = ptr, ptr = SCNEXT(ptr)) 6681da177e4SLinus Torvalds ; 6691da177e4SLinus Torvalds 6701da177e4SLinus Torvalds if (ptr) { 6711da177e4SLinus Torvalds if (prev) 6721da177e4SLinus Torvalds SCNEXT(prev) = SCNEXT(ptr); 6731da177e4SLinus Torvalds else 6741da177e4SLinus Torvalds *SC = SCNEXT(ptr); 6751da177e4SLinus Torvalds 6761da177e4SLinus Torvalds SCNEXT(ptr)=NULL; 6771da177e4SLinus Torvalds } 6781da177e4SLinus Torvalds 6791da177e4SLinus Torvalds return ptr; 6801da177e4SLinus Torvalds } 6811da177e4SLinus Torvalds 68291ebc1faSJohannes Thumshirn static inline struct scsi_cmnd *remove_SC(struct scsi_cmnd **SC, 68391ebc1faSJohannes Thumshirn struct scsi_cmnd *SCp) 6841da177e4SLinus Torvalds { 68591ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr, *prev; 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds for (ptr = *SC, prev = NULL; 6881da177e4SLinus Torvalds ptr && SCp!=ptr; 6891da177e4SLinus Torvalds prev = ptr, ptr = SCNEXT(ptr)) 6901da177e4SLinus Torvalds ; 6911da177e4SLinus Torvalds 6921da177e4SLinus Torvalds if (ptr) { 6931da177e4SLinus Torvalds if (prev) 6941da177e4SLinus Torvalds SCNEXT(prev) = SCNEXT(ptr); 6951da177e4SLinus Torvalds else 6961da177e4SLinus Torvalds *SC = SCNEXT(ptr); 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds SCNEXT(ptr)=NULL; 6991da177e4SLinus Torvalds } 7001da177e4SLinus Torvalds 7011da177e4SLinus Torvalds return ptr; 7021da177e4SLinus Torvalds } 7031da177e4SLinus Torvalds 7047d12e780SDavid Howells static irqreturn_t swintr(int irqno, void *dev_id) 7051da177e4SLinus Torvalds { 706c7bec5abSJeff Garzik struct Scsi_Host *shpnt = dev_id; 7071da177e4SLinus Torvalds 7081da177e4SLinus Torvalds HOSTDATA(shpnt)->swint++; 7091da177e4SLinus Torvalds 7101da177e4SLinus Torvalds SETPORT(DMACNTRL0, INTEN); 7111da177e4SLinus Torvalds return IRQ_HANDLED; 7121da177e4SLinus Torvalds } 7131da177e4SLinus Torvalds 7141da177e4SLinus Torvalds struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup) 7151da177e4SLinus Torvalds { 7161da177e4SLinus Torvalds struct Scsi_Host *shpnt; 7171da177e4SLinus Torvalds 7181da177e4SLinus Torvalds shpnt = scsi_host_alloc(&aha152x_driver_template, sizeof(struct aha152x_hostdata)); 7191da177e4SLinus Torvalds if (!shpnt) { 7201da177e4SLinus Torvalds printk(KERN_ERR "aha152x: scsi_host_alloc failed\n"); 7211da177e4SLinus Torvalds return NULL; 7221da177e4SLinus Torvalds } 7231da177e4SLinus Torvalds 7241da177e4SLinus Torvalds memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt)); 7255fcda422SJames Bottomley INIT_LIST_HEAD(&HOSTDATA(shpnt)->host_list); 7265fcda422SJames Bottomley 7275fcda422SJames Bottomley /* need to have host registered before triggering any interrupt */ 7285fcda422SJames Bottomley list_add_tail(&HOSTDATA(shpnt)->host_list, &aha152x_host_list); 7291da177e4SLinus Torvalds 7301da177e4SLinus Torvalds shpnt->io_port = setup->io_port; 7311da177e4SLinus Torvalds shpnt->n_io_port = IO_RANGE; 7321da177e4SLinus Torvalds shpnt->irq = setup->irq; 7331da177e4SLinus Torvalds 7341da177e4SLinus Torvalds if (!setup->tc1550) { 7351da177e4SLinus Torvalds HOSTIOPORT0 = setup->io_port; 7361da177e4SLinus Torvalds HOSTIOPORT1 = setup->io_port; 7371da177e4SLinus Torvalds } else { 7381da177e4SLinus Torvalds HOSTIOPORT0 = setup->io_port+0x10; 7391da177e4SLinus Torvalds HOSTIOPORT1 = setup->io_port-0x10; 7401da177e4SLinus Torvalds } 7411da177e4SLinus Torvalds 7421da177e4SLinus Torvalds spin_lock_init(&QLOCK); 7431da177e4SLinus Torvalds RECONNECT = setup->reconnect; 7441da177e4SLinus Torvalds SYNCHRONOUS = setup->synchronous; 7451da177e4SLinus Torvalds PARITY = setup->parity; 7461da177e4SLinus Torvalds DELAY = setup->delay; 7471da177e4SLinus Torvalds EXT_TRANS = setup->ext_trans; 7481da177e4SLinus Torvalds 7491da177e4SLinus Torvalds SETPORT(SCSIID, setup->scsiid << 4); 7501da177e4SLinus Torvalds shpnt->this_id = setup->scsiid; 7511da177e4SLinus Torvalds 7521da177e4SLinus Torvalds if (setup->reconnect) 7531da177e4SLinus Torvalds shpnt->can_queue = AHA152X_MAXQUEUE; 7541da177e4SLinus Torvalds 7551da177e4SLinus Torvalds /* RESET OUT */ 7561da177e4SLinus Torvalds printk("aha152x: resetting bus...\n"); 7571da177e4SLinus Torvalds SETPORT(SCSISEQ, SCSIRSTO); 7581da177e4SLinus Torvalds mdelay(256); 7591da177e4SLinus Torvalds SETPORT(SCSISEQ, 0); 7601da177e4SLinus Torvalds mdelay(DELAY); 7611da177e4SLinus Torvalds 7621da177e4SLinus Torvalds reset_ports(shpnt); 7631da177e4SLinus Torvalds 7641da177e4SLinus Torvalds printk(KERN_INFO 7651da177e4SLinus Torvalds "aha152x%d%s: " 7661da177e4SLinus Torvalds "vital data: rev=%x, " 7671da177e4SLinus Torvalds "io=0x%03lx (0x%03lx/0x%03lx), " 7681da177e4SLinus Torvalds "irq=%d, " 7691da177e4SLinus Torvalds "scsiid=%d, " 7701da177e4SLinus Torvalds "reconnect=%s, " 7711da177e4SLinus Torvalds "parity=%s, " 7721da177e4SLinus Torvalds "synchronous=%s, " 7731da177e4SLinus Torvalds "delay=%d, " 7741da177e4SLinus Torvalds "extended translation=%s\n", 7751da177e4SLinus Torvalds shpnt->host_no, setup->tc1550 ? " (tc1550 mode)" : "", 7761da177e4SLinus Torvalds GETPORT(REV) & 0x7, 7771da177e4SLinus Torvalds shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1, 7781da177e4SLinus Torvalds shpnt->irq, 7791da177e4SLinus Torvalds shpnt->this_id, 7801da177e4SLinus Torvalds RECONNECT ? "enabled" : "disabled", 7811da177e4SLinus Torvalds PARITY ? "enabled" : "disabled", 7821da177e4SLinus Torvalds SYNCHRONOUS ? "enabled" : "disabled", 7831da177e4SLinus Torvalds DELAY, 7841da177e4SLinus Torvalds EXT_TRANS ? "enabled" : "disabled"); 7851da177e4SLinus Torvalds 7861da177e4SLinus Torvalds /* not expecting any interrupts */ 7871da177e4SLinus Torvalds SETPORT(SIMODE0, 0); 7881da177e4SLinus Torvalds SETPORT(SIMODE1, 0); 7891da177e4SLinus Torvalds 7904909cc2bSMichael Opdenacker if (request_irq(shpnt->irq, swintr, IRQF_SHARED, "aha152x", shpnt)) { 7911da177e4SLinus Torvalds printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq); 7921da177e4SLinus Torvalds goto out_host_put; 7931da177e4SLinus Torvalds } 7941da177e4SLinus Torvalds 7951da177e4SLinus Torvalds HOSTDATA(shpnt)->swint = 0; 7961da177e4SLinus Torvalds 7971da177e4SLinus Torvalds printk(KERN_INFO "aha152x%d: trying software interrupt, ", shpnt->host_no); 7981da177e4SLinus Torvalds 7991da177e4SLinus Torvalds mb(); 8001da177e4SLinus Torvalds SETPORT(DMACNTRL0, SWINT|INTEN); 8011da177e4SLinus Torvalds mdelay(1000); 8021da177e4SLinus Torvalds free_irq(shpnt->irq, shpnt); 8031da177e4SLinus Torvalds 8041da177e4SLinus Torvalds if (!HOSTDATA(shpnt)->swint) { 8051da177e4SLinus Torvalds if (TESTHI(DMASTAT, INTSTAT)) { 8061da177e4SLinus Torvalds printk("lost.\n"); 8071da177e4SLinus Torvalds } else { 8081da177e4SLinus Torvalds printk("failed.\n"); 8091da177e4SLinus Torvalds } 8101da177e4SLinus Torvalds 8111da177e4SLinus Torvalds SETPORT(DMACNTRL0, INTEN); 8121da177e4SLinus Torvalds 8131da177e4SLinus Torvalds printk(KERN_ERR "aha152x%d: irq %d possibly wrong. " 8141da177e4SLinus Torvalds "Please verify.\n", shpnt->host_no, shpnt->irq); 8151da177e4SLinus Torvalds goto out_host_put; 8161da177e4SLinus Torvalds } 8171da177e4SLinus Torvalds printk("ok.\n"); 8181da177e4SLinus Torvalds 8191da177e4SLinus Torvalds 8201da177e4SLinus Torvalds /* clear interrupts */ 8211da177e4SLinus Torvalds SETPORT(SSTAT0, 0x7f); 8221da177e4SLinus Torvalds SETPORT(SSTAT1, 0xef); 8231da177e4SLinus Torvalds 8244909cc2bSMichael Opdenacker if (request_irq(shpnt->irq, intr, IRQF_SHARED, "aha152x", shpnt)) { 8251da177e4SLinus Torvalds printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq); 8261da177e4SLinus Torvalds goto out_host_put; 8271da177e4SLinus Torvalds } 8281da177e4SLinus Torvalds 8291da177e4SLinus Torvalds if( scsi_add_host(shpnt, NULL) ) { 8301da177e4SLinus Torvalds free_irq(shpnt->irq, shpnt); 8311da177e4SLinus Torvalds printk(KERN_ERR "aha152x%d: failed to add host.\n", shpnt->host_no); 8321da177e4SLinus Torvalds goto out_host_put; 8331da177e4SLinus Torvalds } 8341da177e4SLinus Torvalds 8351da177e4SLinus Torvalds scsi_scan_host(shpnt); 8361da177e4SLinus Torvalds 8371da177e4SLinus Torvalds return shpnt; 8381da177e4SLinus Torvalds 8391da177e4SLinus Torvalds out_host_put: 8405fcda422SJames Bottomley list_del(&HOSTDATA(shpnt)->host_list); 8411da177e4SLinus Torvalds scsi_host_put(shpnt); 8421da177e4SLinus Torvalds 8431da177e4SLinus Torvalds return NULL; 8441da177e4SLinus Torvalds } 8451da177e4SLinus Torvalds 8461da177e4SLinus Torvalds void aha152x_release(struct Scsi_Host *shpnt) 8471da177e4SLinus Torvalds { 8481da177e4SLinus Torvalds if (!shpnt) 8491da177e4SLinus Torvalds return; 8501da177e4SLinus Torvalds 8511bd40573SMatthew Wilcox scsi_remove_host(shpnt); 8521da177e4SLinus Torvalds if (shpnt->irq) 8531da177e4SLinus Torvalds free_irq(shpnt->irq, shpnt); 8541da177e4SLinus Torvalds 8553eb2ebcbSChristoph Hellwig #if !defined(AHA152X_PCMCIA) 8561da177e4SLinus Torvalds if (shpnt->io_port) 8571da177e4SLinus Torvalds release_region(shpnt->io_port, IO_RANGE); 8581da177e4SLinus Torvalds #endif 8591da177e4SLinus Torvalds 8601da177e4SLinus Torvalds #ifdef __ISAPNP__ 8611da177e4SLinus Torvalds if (HOSTDATA(shpnt)->pnpdev) 8621da177e4SLinus Torvalds pnp_device_detach(HOSTDATA(shpnt)->pnpdev); 8631da177e4SLinus Torvalds #endif 8641da177e4SLinus Torvalds 8655fcda422SJames Bottomley list_del(&HOSTDATA(shpnt)->host_list); 8661da177e4SLinus Torvalds scsi_host_put(shpnt); 8671da177e4SLinus Torvalds } 8681da177e4SLinus Torvalds 8691da177e4SLinus Torvalds 8701da177e4SLinus Torvalds /* 8711da177e4SLinus Torvalds * setup controller to generate interrupts depending 8721da177e4SLinus Torvalds * on current state (lock has to be acquired) 8731da177e4SLinus Torvalds * 8741da177e4SLinus Torvalds */ 8751da177e4SLinus Torvalds static int setup_expected_interrupts(struct Scsi_Host *shpnt) 8761da177e4SLinus Torvalds { 8771da177e4SLinus Torvalds if(CURRENT_SC) { 8781da177e4SLinus Torvalds CURRENT_SC->SCp.phase |= 1 << 16; 8791da177e4SLinus Torvalds 8801da177e4SLinus Torvalds if(CURRENT_SC->SCp.phase & selecting) { 8811da177e4SLinus Torvalds SETPORT(SSTAT1, SELTO); 8821da177e4SLinus Torvalds SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); 8831da177e4SLinus Torvalds SETPORT(SIMODE1, ENSELTIMO); 8841da177e4SLinus Torvalds } else { 8851da177e4SLinus Torvalds SETPORT(SIMODE0, (CURRENT_SC->SCp.phase & spiordy) ? ENSPIORDY : 0); 8861da177e4SLinus Torvalds SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); 8871da177e4SLinus Torvalds } 8881da177e4SLinus Torvalds } else if(STATE==seldi) { 8891da177e4SLinus Torvalds SETPORT(SIMODE0, 0); 8901da177e4SLinus Torvalds SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); 8911da177e4SLinus Torvalds } else { 8921da177e4SLinus Torvalds SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); 8931da177e4SLinus Torvalds SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0)); 8941da177e4SLinus Torvalds } 8951da177e4SLinus Torvalds 8961da177e4SLinus Torvalds if(!HOSTDATA(shpnt)->in_intr) 8971da177e4SLinus Torvalds SETBITS(DMACNTRL0, INTEN); 8981da177e4SLinus Torvalds 8991da177e4SLinus Torvalds return TESTHI(DMASTAT, INTSTAT); 9001da177e4SLinus Torvalds } 9011da177e4SLinus Torvalds 9021da177e4SLinus Torvalds 9031da177e4SLinus Torvalds /* 9041da177e4SLinus Torvalds * Queue a command and setup interrupts for a free bus. 9051da177e4SLinus Torvalds */ 90691ebc1faSJohannes Thumshirn static int aha152x_internal_queue(struct scsi_cmnd *SCpnt, 90791ebc1faSJohannes Thumshirn struct completion *complete, 90891ebc1faSJohannes Thumshirn int phase, void (*done)(struct scsi_cmnd *)) 9091da177e4SLinus Torvalds { 9101da177e4SLinus Torvalds struct Scsi_Host *shpnt = SCpnt->device->host; 9111da177e4SLinus Torvalds unsigned long flags; 9121da177e4SLinus Torvalds 9131da177e4SLinus Torvalds SCpnt->scsi_done = done; 9141da177e4SLinus Torvalds SCpnt->SCp.phase = not_issued | phase; 9150ceb4798SBoaz Harrosh SCpnt->SCp.Status = 0x1; /* Ilegal status by SCSI standard */ 9161da177e4SLinus Torvalds SCpnt->SCp.Message = 0; 9171da177e4SLinus Torvalds SCpnt->SCp.have_data_in = 0; 9181da177e4SLinus Torvalds SCpnt->SCp.sent_command = 0; 9191da177e4SLinus Torvalds 9201da177e4SLinus Torvalds if(SCpnt->SCp.phase & (resetting|check_condition)) { 921172c122dSHarvey Harrison if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) { 922f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, SCpnt, "cannot reuse command\n"); 9231da177e4SLinus Torvalds return FAILED; 9241da177e4SLinus Torvalds } 9251da177e4SLinus Torvalds } else { 9261da177e4SLinus Torvalds SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC); 927172c122dSHarvey Harrison if(!SCpnt->host_scribble) { 928f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, SCpnt, "allocation failed\n"); 9291da177e4SLinus Torvalds return FAILED; 9301da177e4SLinus Torvalds } 9311da177e4SLinus Torvalds } 9321da177e4SLinus Torvalds 9331da177e4SLinus Torvalds SCNEXT(SCpnt) = NULL; 9340f06bb34SChristoph Hellwig SCSEM(SCpnt) = complete; 9351da177e4SLinus Torvalds 9361da177e4SLinus Torvalds /* setup scratch area 9371da177e4SLinus Torvalds SCp.ptr : buffer pointer 9381da177e4SLinus Torvalds SCp.this_residual : buffer length 9391da177e4SLinus Torvalds SCp.buffer : next buffer 9401da177e4SLinus Torvalds SCp.phase : current state of the command */ 94166acdb03SBoaz Harrosh 94273d2cb16SBoaz Harrosh if ((phase & resetting) || !scsi_sglist(SCpnt)) { 94366acdb03SBoaz Harrosh SCpnt->SCp.ptr = NULL; 94466acdb03SBoaz Harrosh SCpnt->SCp.this_residual = 0; 9452338545aSBoaz Harrosh scsi_set_resid(SCpnt, 0); 94666acdb03SBoaz Harrosh SCpnt->SCp.buffer = NULL; 94766acdb03SBoaz Harrosh } else { 9482338545aSBoaz Harrosh scsi_set_resid(SCpnt, scsi_bufflen(SCpnt)); 9492338545aSBoaz Harrosh SCpnt->SCp.buffer = scsi_sglist(SCpnt); 9501da177e4SLinus Torvalds SCpnt->SCp.ptr = SG_ADDRESS(SCpnt->SCp.buffer); 9511da177e4SLinus Torvalds SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; 95266acdb03SBoaz Harrosh } 9531da177e4SLinus Torvalds 9541da177e4SLinus Torvalds DO_LOCK(flags); 9551da177e4SLinus Torvalds 9561da177e4SLinus Torvalds #if defined(AHA152X_STAT) 9571da177e4SLinus Torvalds HOSTDATA(shpnt)->total_commands++; 9581da177e4SLinus Torvalds #endif 9591da177e4SLinus Torvalds 9601da177e4SLinus Torvalds /* Turn led on, when this is the first command. */ 9611da177e4SLinus Torvalds HOSTDATA(shpnt)->commands++; 9621da177e4SLinus Torvalds if (HOSTDATA(shpnt)->commands==1) 9631da177e4SLinus Torvalds SETPORT(PORTA, 1); 9641da177e4SLinus Torvalds 9651da177e4SLinus Torvalds append_SC(&ISSUE_SC, SCpnt); 9661da177e4SLinus Torvalds 9671da177e4SLinus Torvalds if(!HOSTDATA(shpnt)->in_intr) 9681da177e4SLinus Torvalds setup_expected_interrupts(shpnt); 9691da177e4SLinus Torvalds 9701da177e4SLinus Torvalds DO_UNLOCK(flags); 9711da177e4SLinus Torvalds 9721da177e4SLinus Torvalds return 0; 9731da177e4SLinus Torvalds } 9741da177e4SLinus Torvalds 9751da177e4SLinus Torvalds /* 9761da177e4SLinus Torvalds * queue a command 9771da177e4SLinus Torvalds * 9781da177e4SLinus Torvalds */ 97991ebc1faSJohannes Thumshirn static int aha152x_queue_lck(struct scsi_cmnd *SCpnt, 98091ebc1faSJohannes Thumshirn void (*done)(struct scsi_cmnd *)) 9811da177e4SLinus Torvalds { 9821da177e4SLinus Torvalds return aha152x_internal_queue(SCpnt, NULL, 0, done); 9831da177e4SLinus Torvalds } 9841da177e4SLinus Torvalds 985f281233dSJeff Garzik static DEF_SCSI_QCMD(aha152x_queue) 986f281233dSJeff Garzik 9871da177e4SLinus Torvalds 9881da177e4SLinus Torvalds /* 9891da177e4SLinus Torvalds * 9901da177e4SLinus Torvalds */ 99191ebc1faSJohannes Thumshirn static void reset_done(struct scsi_cmnd *SCpnt) 9921da177e4SLinus Torvalds { 9931da177e4SLinus Torvalds if(SCSEM(SCpnt)) { 9940f06bb34SChristoph Hellwig complete(SCSEM(SCpnt)); 9951da177e4SLinus Torvalds } else { 9960f06bb34SChristoph Hellwig printk(KERN_ERR "aha152x: reset_done w/o completion\n"); 9971da177e4SLinus Torvalds } 9981da177e4SLinus Torvalds } 9991da177e4SLinus Torvalds 10001da177e4SLinus Torvalds /* 10011da177e4SLinus Torvalds * Abort a command 10021da177e4SLinus Torvalds * 10031da177e4SLinus Torvalds */ 100491ebc1faSJohannes Thumshirn static int aha152x_abort(struct scsi_cmnd *SCpnt) 10051da177e4SLinus Torvalds { 10061da177e4SLinus Torvalds struct Scsi_Host *shpnt = SCpnt->device->host; 100791ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr; 10081da177e4SLinus Torvalds unsigned long flags; 10091da177e4SLinus Torvalds 10101da177e4SLinus Torvalds DO_LOCK(flags); 10111da177e4SLinus Torvalds 10121da177e4SLinus Torvalds ptr=remove_SC(&ISSUE_SC, SCpnt); 10131da177e4SLinus Torvalds 10141da177e4SLinus Torvalds if(ptr) { 10151da177e4SLinus Torvalds HOSTDATA(shpnt)->commands--; 10161da177e4SLinus Torvalds if (!HOSTDATA(shpnt)->commands) 10171da177e4SLinus Torvalds SETPORT(PORTA, 0); 10181da177e4SLinus Torvalds DO_UNLOCK(flags); 10191da177e4SLinus Torvalds 10201da177e4SLinus Torvalds kfree(SCpnt->host_scribble); 10211da177e4SLinus Torvalds SCpnt->host_scribble=NULL; 10221da177e4SLinus Torvalds 10231da177e4SLinus Torvalds return SUCCESS; 10241da177e4SLinus Torvalds } 10251da177e4SLinus Torvalds 10261da177e4SLinus Torvalds DO_UNLOCK(flags); 10271da177e4SLinus Torvalds 10281da177e4SLinus Torvalds /* 10291da177e4SLinus Torvalds * FIXME: 10301da177e4SLinus Torvalds * for current command: queue ABORT for message out and raise ATN 10311da177e4SLinus Torvalds * for disconnected command: pseudo SC with ABORT message or ABORT on reselection? 10321da177e4SLinus Torvalds * 10331da177e4SLinus Torvalds */ 10341da177e4SLinus Torvalds 1035f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, SCpnt, 1036f75ae8edSHannes Reinecke "cannot abort running or disconnected command\n"); 10371da177e4SLinus Torvalds 10381da177e4SLinus Torvalds return FAILED; 10391da177e4SLinus Torvalds } 10401da177e4SLinus Torvalds 10411da177e4SLinus Torvalds /* 10421da177e4SLinus Torvalds * Reset a device 10431da177e4SLinus Torvalds * 10441da177e4SLinus Torvalds */ 104591ebc1faSJohannes Thumshirn static int aha152x_device_reset(struct scsi_cmnd * SCpnt) 10461da177e4SLinus Torvalds { 10471da177e4SLinus Torvalds struct Scsi_Host *shpnt = SCpnt->device->host; 10480f06bb34SChristoph Hellwig DECLARE_COMPLETION(done); 10491da177e4SLinus Torvalds int ret, issued, disconnected; 1050631c228cSChristoph Hellwig unsigned char old_cmd_len = SCpnt->cmd_len; 10511da177e4SLinus Torvalds unsigned long flags; 10520f06bb34SChristoph Hellwig unsigned long timeleft; 10531da177e4SLinus Torvalds 10541da177e4SLinus Torvalds if(CURRENT_SC==SCpnt) { 1055f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, SCpnt, "cannot reset current device\n"); 10561da177e4SLinus Torvalds return FAILED; 10571da177e4SLinus Torvalds } 10581da177e4SLinus Torvalds 10591da177e4SLinus Torvalds DO_LOCK(flags); 1060172c122dSHarvey Harrison issued = remove_SC(&ISSUE_SC, SCpnt) == NULL; 10611da177e4SLinus Torvalds disconnected = issued && remove_SC(&DISCONNECTED_SC, SCpnt); 10621da177e4SLinus Torvalds DO_UNLOCK(flags); 10631da177e4SLinus Torvalds 10641da177e4SLinus Torvalds SCpnt->cmd_len = 0; 10651da177e4SLinus Torvalds 10660f06bb34SChristoph Hellwig aha152x_internal_queue(SCpnt, &done, resetting, reset_done); 10671da177e4SLinus Torvalds 10680f06bb34SChristoph Hellwig timeleft = wait_for_completion_timeout(&done, 100*HZ); 10690f06bb34SChristoph Hellwig if (!timeleft) { 10700f06bb34SChristoph Hellwig /* remove command from issue queue */ 10710f06bb34SChristoph Hellwig DO_LOCK(flags); 10720f06bb34SChristoph Hellwig remove_SC(&ISSUE_SC, SCpnt); 10730f06bb34SChristoph Hellwig DO_UNLOCK(flags); 10740f06bb34SChristoph Hellwig } 10751da177e4SLinus Torvalds 1076631c228cSChristoph Hellwig SCpnt->cmd_len = old_cmd_len; 10771da177e4SLinus Torvalds 10781da177e4SLinus Torvalds DO_LOCK(flags); 10791da177e4SLinus Torvalds 10801da177e4SLinus Torvalds if(SCpnt->SCp.phase & resetted) { 10811da177e4SLinus Torvalds HOSTDATA(shpnt)->commands--; 10821da177e4SLinus Torvalds if (!HOSTDATA(shpnt)->commands) 10831da177e4SLinus Torvalds SETPORT(PORTA, 0); 10841da177e4SLinus Torvalds kfree(SCpnt->host_scribble); 10851da177e4SLinus Torvalds SCpnt->host_scribble=NULL; 10861da177e4SLinus Torvalds 10871da177e4SLinus Torvalds ret = SUCCESS; 10881da177e4SLinus Torvalds } else { 10891da177e4SLinus Torvalds /* requeue */ 10901da177e4SLinus Torvalds if(!issued) { 10911da177e4SLinus Torvalds append_SC(&ISSUE_SC, SCpnt); 10921da177e4SLinus Torvalds } else if(disconnected) { 10931da177e4SLinus Torvalds append_SC(&DISCONNECTED_SC, SCpnt); 10941da177e4SLinus Torvalds } 10951da177e4SLinus Torvalds 10961da177e4SLinus Torvalds ret = FAILED; 10971da177e4SLinus Torvalds } 10981da177e4SLinus Torvalds 10991da177e4SLinus Torvalds DO_UNLOCK(flags); 11001da177e4SLinus Torvalds return ret; 11011da177e4SLinus Torvalds } 11021da177e4SLinus Torvalds 110391ebc1faSJohannes Thumshirn static void free_hard_reset_SCs(struct Scsi_Host *shpnt, 110491ebc1faSJohannes Thumshirn struct scsi_cmnd **SCs) 11051da177e4SLinus Torvalds { 110691ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr; 11071da177e4SLinus Torvalds 11081da177e4SLinus Torvalds ptr=*SCs; 11091da177e4SLinus Torvalds while(ptr) { 111091ebc1faSJohannes Thumshirn struct scsi_cmnd *next; 11111da177e4SLinus Torvalds 11121da177e4SLinus Torvalds if(SCDATA(ptr)) { 11131da177e4SLinus Torvalds next = SCNEXT(ptr); 11141da177e4SLinus Torvalds } else { 1115f75ae8edSHannes Reinecke scmd_printk(KERN_DEBUG, ptr, 1116f75ae8edSHannes Reinecke "queue corrupted at %p\n", ptr); 11171da177e4SLinus Torvalds next = NULL; 11181da177e4SLinus Torvalds } 11191da177e4SLinus Torvalds 11201da177e4SLinus Torvalds if (!ptr->device->soft_reset) { 11211da177e4SLinus Torvalds remove_SC(SCs, ptr); 11221da177e4SLinus Torvalds HOSTDATA(shpnt)->commands--; 11231da177e4SLinus Torvalds kfree(ptr->host_scribble); 11241da177e4SLinus Torvalds ptr->host_scribble=NULL; 11251da177e4SLinus Torvalds } 11261da177e4SLinus Torvalds 11271da177e4SLinus Torvalds ptr = next; 11281da177e4SLinus Torvalds } 11291da177e4SLinus Torvalds } 11301da177e4SLinus Torvalds 11311da177e4SLinus Torvalds /* 11321da177e4SLinus Torvalds * Reset the bus 11331da177e4SLinus Torvalds * 1134819f80c9SHannes Reinecke * AIC-6260 has a hard reset (MRST signal), but apparently 1135819f80c9SHannes Reinecke * one cannot trigger it via software. So live with 1136819f80c9SHannes Reinecke * a soft reset; no-one seemed to have cared. 11371da177e4SLinus Torvalds */ 1138e2482fa1SJürgen E. Fischer static int aha152x_bus_reset_host(struct Scsi_Host *shpnt) 11391da177e4SLinus Torvalds { 11401da177e4SLinus Torvalds unsigned long flags; 11411da177e4SLinus Torvalds 11421da177e4SLinus Torvalds DO_LOCK(flags); 11431da177e4SLinus Torvalds 11441da177e4SLinus Torvalds free_hard_reset_SCs(shpnt, &ISSUE_SC); 11451da177e4SLinus Torvalds free_hard_reset_SCs(shpnt, &DISCONNECTED_SC); 11461da177e4SLinus Torvalds 11471da177e4SLinus Torvalds SETPORT(SCSISEQ, SCSIRSTO); 11481da177e4SLinus Torvalds mdelay(256); 11491da177e4SLinus Torvalds SETPORT(SCSISEQ, 0); 11501da177e4SLinus Torvalds mdelay(DELAY); 11511da177e4SLinus Torvalds 11521da177e4SLinus Torvalds setup_expected_interrupts(shpnt); 11531da177e4SLinus Torvalds if(HOSTDATA(shpnt)->commands==0) 11541da177e4SLinus Torvalds SETPORT(PORTA, 0); 11551da177e4SLinus Torvalds 11561da177e4SLinus Torvalds DO_UNLOCK(flags); 11571da177e4SLinus Torvalds 11581da177e4SLinus Torvalds return SUCCESS; 11591da177e4SLinus Torvalds } 11601da177e4SLinus Torvalds 1161e2482fa1SJürgen E. Fischer /* 1162e2482fa1SJürgen E. Fischer * Reset the bus 1163e2482fa1SJürgen E. Fischer * 1164e2482fa1SJürgen E. Fischer */ 116591ebc1faSJohannes Thumshirn static int aha152x_bus_reset(struct scsi_cmnd *SCpnt) 1166e2482fa1SJürgen E. Fischer { 1167e2482fa1SJürgen E. Fischer return aha152x_bus_reset_host(SCpnt->device->host); 1168e2482fa1SJürgen E. Fischer } 11691da177e4SLinus Torvalds 11701da177e4SLinus Torvalds /* 11711da177e4SLinus Torvalds * Restore default values to the AIC-6260 registers and reset the fifos 11721da177e4SLinus Torvalds * 11731da177e4SLinus Torvalds */ 11741da177e4SLinus Torvalds static void reset_ports(struct Scsi_Host *shpnt) 11751da177e4SLinus Torvalds { 11761da177e4SLinus Torvalds unsigned long flags; 11771da177e4SLinus Torvalds 11781da177e4SLinus Torvalds /* disable interrupts */ 11791da177e4SLinus Torvalds SETPORT(DMACNTRL0, RSTFIFO); 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds SETPORT(SCSISEQ, 0); 11821da177e4SLinus Torvalds 11831da177e4SLinus Torvalds SETPORT(SXFRCTL1, 0); 11841da177e4SLinus Torvalds SETPORT(SCSISIG, 0); 11851da177e4SLinus Torvalds SETRATE(0); 11861da177e4SLinus Torvalds 11871da177e4SLinus Torvalds /* clear all interrupt conditions */ 11881da177e4SLinus Torvalds SETPORT(SSTAT0, 0x7f); 11891da177e4SLinus Torvalds SETPORT(SSTAT1, 0xef); 11901da177e4SLinus Torvalds 11911da177e4SLinus Torvalds SETPORT(SSTAT4, SYNCERR | FWERR | FRERR); 11921da177e4SLinus Torvalds 11931da177e4SLinus Torvalds SETPORT(DMACNTRL0, 0); 11941da177e4SLinus Torvalds SETPORT(DMACNTRL1, 0); 11951da177e4SLinus Torvalds 11961da177e4SLinus Torvalds SETPORT(BRSTCNTRL, 0xf1); 11971da177e4SLinus Torvalds 11981da177e4SLinus Torvalds /* clear SCSI fifos and transfer count */ 11991da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); 12001da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1); 12011da177e4SLinus Torvalds 12021da177e4SLinus Torvalds DO_LOCK(flags); 12031da177e4SLinus Torvalds setup_expected_interrupts(shpnt); 12041da177e4SLinus Torvalds DO_UNLOCK(flags); 12051da177e4SLinus Torvalds } 12061da177e4SLinus Torvalds 12071da177e4SLinus Torvalds /* 12081da177e4SLinus Torvalds * Reset the host (bus and controller) 12091da177e4SLinus Torvalds * 12101da177e4SLinus Torvalds */ 1211e2482fa1SJürgen E. Fischer int aha152x_host_reset_host(struct Scsi_Host *shpnt) 12121da177e4SLinus Torvalds { 1213e2482fa1SJürgen E. Fischer aha152x_bus_reset_host(shpnt); 1214e2482fa1SJürgen E. Fischer reset_ports(shpnt); 12151da177e4SLinus Torvalds 12161da177e4SLinus Torvalds return SUCCESS; 12171da177e4SLinus Torvalds } 12181da177e4SLinus Torvalds 12191da177e4SLinus Torvalds /* 12201da177e4SLinus Torvalds * Return the "logical geometry" 12211da177e4SLinus Torvalds * 12221da177e4SLinus Torvalds */ 12231da177e4SLinus Torvalds static int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev, 12241da177e4SLinus Torvalds sector_t capacity, int *info_array) 12251da177e4SLinus Torvalds { 12261da177e4SLinus Torvalds struct Scsi_Host *shpnt = sdev->host; 12271da177e4SLinus Torvalds 12281da177e4SLinus Torvalds /* try default translation */ 12291da177e4SLinus Torvalds info_array[0] = 64; 12301da177e4SLinus Torvalds info_array[1] = 32; 12311da177e4SLinus Torvalds info_array[2] = (unsigned long)capacity / (64 * 32); 12321da177e4SLinus Torvalds 12331da177e4SLinus Torvalds /* for disks >1GB do some guessing */ 12341da177e4SLinus Torvalds if (info_array[2] >= 1024) { 12351da177e4SLinus Torvalds int info[3]; 12361da177e4SLinus Torvalds 12371da177e4SLinus Torvalds /* try to figure out the geometry from the partition table */ 12381da177e4SLinus Torvalds if (scsicam_bios_param(bdev, capacity, info) < 0 || 12391da177e4SLinus Torvalds !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) { 12401da177e4SLinus Torvalds if (EXT_TRANS) { 12411da177e4SLinus Torvalds printk(KERN_NOTICE 12421da177e4SLinus Torvalds "aha152x: unable to verify geometry for disk with >1GB.\n" 12431da177e4SLinus Torvalds " using extended translation.\n"); 12441da177e4SLinus Torvalds info_array[0] = 255; 12451da177e4SLinus Torvalds info_array[1] = 63; 12461da177e4SLinus Torvalds info_array[2] = (unsigned long)capacity / (255 * 63); 12471da177e4SLinus Torvalds } else { 12481da177e4SLinus Torvalds printk(KERN_NOTICE 12491da177e4SLinus Torvalds "aha152x: unable to verify geometry for disk with >1GB.\n" 12501da177e4SLinus Torvalds " Using default translation. Please verify yourself.\n" 12511da177e4SLinus Torvalds " Perhaps you need to enable extended translation in the driver.\n" 125294b5530fSMauro Carvalho Chehab " See Documentation/scsi/aha152x.rst for details.\n"); 12531da177e4SLinus Torvalds } 12541da177e4SLinus Torvalds } else { 12551da177e4SLinus Torvalds info_array[0] = info[0]; 12561da177e4SLinus Torvalds info_array[1] = info[1]; 12571da177e4SLinus Torvalds info_array[2] = info[2]; 12581da177e4SLinus Torvalds 12591da177e4SLinus Torvalds if (info[0] == 255 && !EXT_TRANS) { 12601da177e4SLinus Torvalds printk(KERN_NOTICE 12611da177e4SLinus Torvalds "aha152x: current partition table is using extended translation.\n" 12621da177e4SLinus Torvalds " using it also, although it's not explicitly enabled.\n"); 12631da177e4SLinus Torvalds } 12641da177e4SLinus Torvalds } 12651da177e4SLinus Torvalds } 12661da177e4SLinus Torvalds 12671da177e4SLinus Torvalds return 0; 12681da177e4SLinus Torvalds } 12691da177e4SLinus Torvalds 12701da177e4SLinus Torvalds /* 12711da177e4SLinus Torvalds * Internal done function 12721da177e4SLinus Torvalds * 12731da177e4SLinus Torvalds */ 12741da177e4SLinus Torvalds static void done(struct Scsi_Host *shpnt, int error) 12751da177e4SLinus Torvalds { 12761da177e4SLinus Torvalds if (CURRENT_SC) { 12771da177e4SLinus Torvalds if(DONE_SC) 1278f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, 1279f75ae8edSHannes Reinecke "there's already a completed command %p " 1280f75ae8edSHannes Reinecke "- will cause abort\n", DONE_SC); 12811da177e4SLinus Torvalds 12821da177e4SLinus Torvalds DONE_SC = CURRENT_SC; 12831da177e4SLinus Torvalds CURRENT_SC = NULL; 12841da177e4SLinus Torvalds DONE_SC->result = error; 12851da177e4SLinus Torvalds } else 12861da177e4SLinus Torvalds printk(KERN_ERR "aha152x: done() called outside of command\n"); 12871da177e4SLinus Torvalds } 12881da177e4SLinus Torvalds 12891da177e4SLinus Torvalds static struct work_struct aha152x_tq; 12901da177e4SLinus Torvalds 12911da177e4SLinus Torvalds /* 12921da177e4SLinus Torvalds * Run service completions on the card with interrupts enabled. 12931da177e4SLinus Torvalds * 12941da177e4SLinus Torvalds */ 1295c4028958SDavid Howells static void run(struct work_struct *work) 12961da177e4SLinus Torvalds { 12975fcda422SJames Bottomley struct aha152x_hostdata *hd; 12985fcda422SJames Bottomley 12995fcda422SJames Bottomley list_for_each_entry(hd, &aha152x_host_list, host_list) { 13005fcda422SJames Bottomley struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata); 13015fcda422SJames Bottomley 13025fcda422SJames Bottomley is_complete(shost); 13031da177e4SLinus Torvalds } 13041da177e4SLinus Torvalds } 13051da177e4SLinus Torvalds 13061da177e4SLinus Torvalds /* 1307e2482fa1SJürgen E. Fischer * Interrupt handler 13081da177e4SLinus Torvalds * 13091da177e4SLinus Torvalds */ 13107d12e780SDavid Howells static irqreturn_t intr(int irqno, void *dev_id) 13111da177e4SLinus Torvalds { 1312e19166d5SJeff Garzik struct Scsi_Host *shpnt = dev_id; 1313e2482fa1SJürgen E. Fischer unsigned long flags; 13141da177e4SLinus Torvalds unsigned char rev, dmacntrl0; 13151da177e4SLinus Torvalds 13161da177e4SLinus Torvalds /* 13171da177e4SLinus Torvalds * Read a couple of registers that are known to not be all 1's. If 13181da177e4SLinus Torvalds * we read all 1's (-1), that means that either: 13191da177e4SLinus Torvalds * 13201da177e4SLinus Torvalds * a. The host adapter chip has gone bad, and we cannot control it, 13211da177e4SLinus Torvalds * OR 13221da177e4SLinus Torvalds * b. The host adapter is a PCMCIA card that has been ejected 13231da177e4SLinus Torvalds * 13241da177e4SLinus Torvalds * In either case, we cannot do anything with the host adapter at 13251da177e4SLinus Torvalds * this point in time. So just ignore the interrupt and return. 13261da177e4SLinus Torvalds * In the latter case, the interrupt might actually be meant for 13271da177e4SLinus Torvalds * someone else sharing this IRQ, and that driver will handle it. 13281da177e4SLinus Torvalds */ 13291da177e4SLinus Torvalds rev = GETPORT(REV); 13301da177e4SLinus Torvalds dmacntrl0 = GETPORT(DMACNTRL0); 13311da177e4SLinus Torvalds if ((rev == 0xFF) && (dmacntrl0 == 0xFF)) 13321da177e4SLinus Torvalds return IRQ_NONE; 13331da177e4SLinus Torvalds 1334e2482fa1SJürgen E. Fischer if( TESTLO(DMASTAT, INTSTAT) ) 1335e2482fa1SJürgen E. Fischer return IRQ_NONE; 1336e2482fa1SJürgen E. Fischer 13371da177e4SLinus Torvalds /* no more interrupts from the controller, while we're busy. 13381da177e4SLinus Torvalds INTEN is restored by the BH handler */ 13391da177e4SLinus Torvalds CLRBITS(DMACNTRL0, INTEN); 13401da177e4SLinus Torvalds 1341e2482fa1SJürgen E. Fischer DO_LOCK(flags); 1342e2482fa1SJürgen E. Fischer if( HOSTDATA(shpnt)->service==0 ) { 1343e2482fa1SJürgen E. Fischer HOSTDATA(shpnt)->service=1; 13441da177e4SLinus Torvalds 13451da177e4SLinus Torvalds /* Poke the BH handler */ 1346c4028958SDavid Howells INIT_WORK(&aha152x_tq, run); 13471da177e4SLinus Torvalds schedule_work(&aha152x_tq); 1348e2482fa1SJürgen E. Fischer } 1349e2482fa1SJürgen E. Fischer DO_UNLOCK(flags); 1350e2482fa1SJürgen E. Fischer 13511da177e4SLinus Torvalds return IRQ_HANDLED; 13521da177e4SLinus Torvalds } 13531da177e4SLinus Torvalds 13541da177e4SLinus Torvalds /* 13551da177e4SLinus Torvalds * busfree phase 13561da177e4SLinus Torvalds * - handle completition/disconnection/error of current command 13571da177e4SLinus Torvalds * - start selection for next command (if any) 13581da177e4SLinus Torvalds */ 13591da177e4SLinus Torvalds static void busfree_run(struct Scsi_Host *shpnt) 13601da177e4SLinus Torvalds { 13611da177e4SLinus Torvalds unsigned long flags; 13621da177e4SLinus Torvalds #if defined(AHA152X_STAT) 13631da177e4SLinus Torvalds int action=0; 13641da177e4SLinus Torvalds #endif 13651da177e4SLinus Torvalds 13661da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); 13671da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1); 13681da177e4SLinus Torvalds 13691da177e4SLinus Torvalds SETPORT(SSTAT1, CLRBUSFREE); 13701da177e4SLinus Torvalds 13711da177e4SLinus Torvalds if(CURRENT_SC) { 13721da177e4SLinus Torvalds #if defined(AHA152X_STAT) 13731da177e4SLinus Torvalds action++; 13741da177e4SLinus Torvalds #endif 13751da177e4SLinus Torvalds CURRENT_SC->SCp.phase &= ~syncneg; 13761da177e4SLinus Torvalds 13771da177e4SLinus Torvalds if(CURRENT_SC->SCp.phase & completed) { 13781da177e4SLinus Torvalds /* target sent COMMAND COMPLETE */ 13791da177e4SLinus Torvalds done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16)); 13801da177e4SLinus Torvalds 13811da177e4SLinus Torvalds } else if(CURRENT_SC->SCp.phase & aborted) { 13821da177e4SLinus Torvalds done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_ABORT << 16)); 13831da177e4SLinus Torvalds 13841da177e4SLinus Torvalds } else if(CURRENT_SC->SCp.phase & resetted) { 13851da177e4SLinus Torvalds done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_RESET << 16)); 13861da177e4SLinus Torvalds 13871da177e4SLinus Torvalds } else if(CURRENT_SC->SCp.phase & disconnected) { 13881da177e4SLinus Torvalds /* target sent DISCONNECT */ 13891da177e4SLinus Torvalds #if defined(AHA152X_STAT) 13901da177e4SLinus Torvalds HOSTDATA(shpnt)->disconnections++; 13911da177e4SLinus Torvalds #endif 13921da177e4SLinus Torvalds append_SC(&DISCONNECTED_SC, CURRENT_SC); 13931da177e4SLinus Torvalds CURRENT_SC->SCp.phase |= 1 << 16; 13941da177e4SLinus Torvalds CURRENT_SC = NULL; 13951da177e4SLinus Torvalds 13961da177e4SLinus Torvalds } else { 13971da177e4SLinus Torvalds done(shpnt, DID_ERROR << 16); 13981da177e4SLinus Torvalds } 13991da177e4SLinus Torvalds #if defined(AHA152X_STAT) 14001da177e4SLinus Torvalds } else { 14011da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_old_command++; 14021da177e4SLinus Torvalds #endif 14031da177e4SLinus Torvalds } 14041da177e4SLinus Torvalds 14051da177e4SLinus Torvalds DO_LOCK(flags); 14061da177e4SLinus Torvalds 14071da177e4SLinus Torvalds if(DONE_SC) { 14081da177e4SLinus Torvalds #if defined(AHA152X_STAT) 14091da177e4SLinus Torvalds action++; 14101da177e4SLinus Torvalds #endif 14111da177e4SLinus Torvalds 14121da177e4SLinus Torvalds if(DONE_SC->SCp.phase & check_condition) { 14135e13cdfaSChristoph Hellwig struct scsi_cmnd *cmd = HOSTDATA(shpnt)->done_SC; 14145e13cdfaSChristoph Hellwig struct aha152x_scdata *sc = SCDATA(cmd); 14155e13cdfaSChristoph Hellwig 141673d2cb16SBoaz Harrosh scsi_eh_restore_cmnd(cmd, &sc->ses); 14171da177e4SLinus Torvalds 14180ceb4798SBoaz Harrosh cmd->SCp.Status = SAM_STAT_CHECK_CONDITION; 14191da177e4SLinus Torvalds 14201da177e4SLinus Torvalds HOSTDATA(shpnt)->commands--; 14211da177e4SLinus Torvalds if (!HOSTDATA(shpnt)->commands) 14221da177e4SLinus Torvalds SETPORT(PORTA, 0); /* turn led off */ 14230ceb4798SBoaz Harrosh } else if(DONE_SC->SCp.Status==SAM_STAT_CHECK_CONDITION) { 14241da177e4SLinus Torvalds #if defined(AHA152X_STAT) 14251da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_with_check_condition++; 14261da177e4SLinus Torvalds #endif 14271da177e4SLinus Torvalds 14280ceb4798SBoaz Harrosh if(!(DONE_SC->SCp.phase & not_issued)) { 142945333ffaSBoaz Harrosh struct aha152x_scdata *sc; 143091ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr = DONE_SC; 14311da177e4SLinus Torvalds DONE_SC=NULL; 14321da177e4SLinus Torvalds 143345333ffaSBoaz Harrosh sc = SCDATA(ptr); 143445333ffaSBoaz Harrosh /* It was allocated in aha152x_internal_queue? */ 143545333ffaSBoaz Harrosh BUG_ON(!sc); 143673d2cb16SBoaz Harrosh scsi_eh_prep_cmnd(ptr, &sc->ses, NULL, 0, ~0); 14371da177e4SLinus Torvalds 14381da177e4SLinus Torvalds DO_UNLOCK(flags); 14391da177e4SLinus Torvalds aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done); 14401da177e4SLinus Torvalds DO_LOCK(flags); 14411da177e4SLinus Torvalds } 14421da177e4SLinus Torvalds } 14431da177e4SLinus Torvalds 14441da177e4SLinus Torvalds if(DONE_SC && DONE_SC->scsi_done) { 144591ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr = DONE_SC; 14461da177e4SLinus Torvalds DONE_SC=NULL; 14471da177e4SLinus Torvalds 14481da177e4SLinus Torvalds /* turn led off, when no commands are in the driver */ 14491da177e4SLinus Torvalds HOSTDATA(shpnt)->commands--; 14501da177e4SLinus Torvalds if (!HOSTDATA(shpnt)->commands) 14511da177e4SLinus Torvalds SETPORT(PORTA, 0); /* turn led off */ 14521da177e4SLinus Torvalds 14531da177e4SLinus Torvalds if(ptr->scsi_done != reset_done) { 14541da177e4SLinus Torvalds kfree(ptr->host_scribble); 14551da177e4SLinus Torvalds ptr->host_scribble=NULL; 14561da177e4SLinus Torvalds } 14571da177e4SLinus Torvalds 14581da177e4SLinus Torvalds DO_UNLOCK(flags); 14591da177e4SLinus Torvalds ptr->scsi_done(ptr); 14601da177e4SLinus Torvalds DO_LOCK(flags); 14611da177e4SLinus Torvalds } 14621da177e4SLinus Torvalds 14631da177e4SLinus Torvalds DONE_SC=NULL; 14641da177e4SLinus Torvalds #if defined(AHA152X_STAT) 14651da177e4SLinus Torvalds } else { 14661da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_done_command++; 14671da177e4SLinus Torvalds #endif 14681da177e4SLinus Torvalds } 14691da177e4SLinus Torvalds 14701da177e4SLinus Torvalds if(ISSUE_SC) 14711da177e4SLinus Torvalds CURRENT_SC = remove_first_SC(&ISSUE_SC); 14721da177e4SLinus Torvalds 14731da177e4SLinus Torvalds DO_UNLOCK(flags); 14741da177e4SLinus Torvalds 14751da177e4SLinus Torvalds if(CURRENT_SC) { 14761da177e4SLinus Torvalds #if defined(AHA152X_STAT) 14771da177e4SLinus Torvalds action++; 14781da177e4SLinus Torvalds #endif 14791da177e4SLinus Torvalds CURRENT_SC->SCp.phase |= selecting; 14801da177e4SLinus Torvalds 14811da177e4SLinus Torvalds /* clear selection timeout */ 14821da177e4SLinus Torvalds SETPORT(SSTAT1, SELTO); 14831da177e4SLinus Torvalds 14841da177e4SLinus Torvalds SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->device->id); 14851da177e4SLinus Torvalds SETPORT(SXFRCTL1, (PARITY ? ENSPCHK : 0 ) | ENSTIMER); 14861da177e4SLinus Torvalds SETPORT(SCSISEQ, ENSELO | ENAUTOATNO | (DISCONNECTED_SC ? ENRESELI : 0)); 14871da177e4SLinus Torvalds } else { 14881da177e4SLinus Torvalds #if defined(AHA152X_STAT) 14891da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_new_command++; 14901da177e4SLinus Torvalds #endif 14911da177e4SLinus Torvalds SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0); 14921da177e4SLinus Torvalds } 14931da177e4SLinus Torvalds 14941da177e4SLinus Torvalds #if defined(AHA152X_STAT) 14951da177e4SLinus Torvalds if(!action) 14961da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_any_action++; 14971da177e4SLinus Torvalds #endif 14981da177e4SLinus Torvalds } 14991da177e4SLinus Torvalds 15001da177e4SLinus Torvalds /* 15011da177e4SLinus Torvalds * Selection done (OUT) 15021da177e4SLinus Torvalds * - queue IDENTIFY message and SDTR to selected target for message out 15031da177e4SLinus Torvalds * (ATN asserted automagically via ENAUTOATNO in busfree()) 15041da177e4SLinus Torvalds */ 15051da177e4SLinus Torvalds static void seldo_run(struct Scsi_Host *shpnt) 15061da177e4SLinus Torvalds { 15071da177e4SLinus Torvalds SETPORT(SCSISIG, 0); 15081da177e4SLinus Torvalds SETPORT(SSTAT1, CLRBUSFREE); 15091da177e4SLinus Torvalds SETPORT(SSTAT1, CLRPHASECHG); 15101da177e4SLinus Torvalds 15111da177e4SLinus Torvalds CURRENT_SC->SCp.phase &= ~(selecting|not_issued); 15121da177e4SLinus Torvalds 15131da177e4SLinus Torvalds SETPORT(SCSISEQ, 0); 15141da177e4SLinus Torvalds 15151da177e4SLinus Torvalds if (TESTLO(SSTAT0, SELDO)) { 1516f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, 1517f75ae8edSHannes Reinecke "aha152x: passing bus free condition\n"); 15181da177e4SLinus Torvalds done(shpnt, DID_NO_CONNECT << 16); 15191da177e4SLinus Torvalds return; 15201da177e4SLinus Torvalds } 15211da177e4SLinus Torvalds 15221da177e4SLinus Torvalds SETPORT(SSTAT0, CLRSELDO); 15231da177e4SLinus Torvalds 15241da177e4SLinus Torvalds ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun)); 15251da177e4SLinus Torvalds 15261da177e4SLinus Torvalds if (CURRENT_SC->SCp.phase & aborting) { 15271da177e4SLinus Torvalds ADDMSGO(ABORT); 15281da177e4SLinus Torvalds } else if (CURRENT_SC->SCp.phase & resetting) { 15291da177e4SLinus Torvalds ADDMSGO(BUS_DEVICE_RESET); 15301da177e4SLinus Torvalds } else if (SYNCNEG==0 && SYNCHRONOUS) { 15311da177e4SLinus Torvalds CURRENT_SC->SCp.phase |= syncneg; 15326ea3c0b2SMatthew Wilcox MSGOLEN += spi_populate_sync_msg(&MSGO(MSGOLEN), 50, 8); 15331da177e4SLinus Torvalds SYNCNEG=1; /* negotiation in progress */ 15341da177e4SLinus Torvalds } 15351da177e4SLinus Torvalds 15361da177e4SLinus Torvalds SETRATE(SYNCRATE); 15371da177e4SLinus Torvalds } 15381da177e4SLinus Torvalds 15391da177e4SLinus Torvalds /* 15401da177e4SLinus Torvalds * Selection timeout 15411da177e4SLinus Torvalds * - return command to mid-level with failure cause 15421da177e4SLinus Torvalds * 15431da177e4SLinus Torvalds */ 15441da177e4SLinus Torvalds static void selto_run(struct Scsi_Host *shpnt) 15451da177e4SLinus Torvalds { 15461da177e4SLinus Torvalds SETPORT(SCSISEQ, 0); 15471da177e4SLinus Torvalds SETPORT(SSTAT1, CLRSELTIMO); 15481da177e4SLinus Torvalds 1549f75ae8edSHannes Reinecke if (!CURRENT_SC) 15501da177e4SLinus Torvalds return; 15511da177e4SLinus Torvalds 15521da177e4SLinus Torvalds CURRENT_SC->SCp.phase &= ~selecting; 15531da177e4SLinus Torvalds 1554f75ae8edSHannes Reinecke if (CURRENT_SC->SCp.phase & aborted) 15551da177e4SLinus Torvalds done(shpnt, DID_ABORT << 16); 1556f75ae8edSHannes Reinecke else if (TESTLO(SSTAT0, SELINGO)) 15571da177e4SLinus Torvalds done(shpnt, DID_BUS_BUSY << 16); 1558f75ae8edSHannes Reinecke else 15591da177e4SLinus Torvalds /* ARBITRATION won, but SELECTION failed */ 15601da177e4SLinus Torvalds done(shpnt, DID_NO_CONNECT << 16); 15611da177e4SLinus Torvalds } 15621da177e4SLinus Torvalds 15631da177e4SLinus Torvalds /* 15641da177e4SLinus Torvalds * Selection in done 15651da177e4SLinus Torvalds * - put current command back to issue queue 15661da177e4SLinus Torvalds * (reconnection of a disconnected nexus instead 15671da177e4SLinus Torvalds * of successful selection out) 15681da177e4SLinus Torvalds * 15691da177e4SLinus Torvalds */ 15701da177e4SLinus Torvalds static void seldi_run(struct Scsi_Host *shpnt) 15711da177e4SLinus Torvalds { 15721da177e4SLinus Torvalds int selid; 15731da177e4SLinus Torvalds int target; 15741da177e4SLinus Torvalds unsigned long flags; 15751da177e4SLinus Torvalds 15761da177e4SLinus Torvalds SETPORT(SCSISIG, 0); 15771da177e4SLinus Torvalds SETPORT(SSTAT0, CLRSELDI); 15781da177e4SLinus Torvalds SETPORT(SSTAT1, CLRBUSFREE); 15791da177e4SLinus Torvalds SETPORT(SSTAT1, CLRPHASECHG); 15801da177e4SLinus Torvalds 15811da177e4SLinus Torvalds if(CURRENT_SC) { 15821da177e4SLinus Torvalds if(!(CURRENT_SC->SCp.phase & not_issued)) 1583f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, 1584f75ae8edSHannes Reinecke "command should not have been issued yet\n"); 15851da177e4SLinus Torvalds 15861da177e4SLinus Torvalds DO_LOCK(flags); 15871da177e4SLinus Torvalds append_SC(&ISSUE_SC, CURRENT_SC); 15881da177e4SLinus Torvalds DO_UNLOCK(flags); 15891da177e4SLinus Torvalds 15901da177e4SLinus Torvalds CURRENT_SC = NULL; 15911da177e4SLinus Torvalds } 15921da177e4SLinus Torvalds 1593f75ae8edSHannes Reinecke if (!DISCONNECTED_SC) 15941da177e4SLinus Torvalds return; 15951da177e4SLinus Torvalds 15961da177e4SLinus Torvalds RECONN_TARGET=-1; 15971da177e4SLinus Torvalds 15981da177e4SLinus Torvalds selid = GETPORT(SELID) & ~(1 << shpnt->this_id); 15991da177e4SLinus Torvalds 16001da177e4SLinus Torvalds if (selid==0) { 1601f75ae8edSHannes Reinecke shost_printk(KERN_INFO, shpnt, 1602f75ae8edSHannes Reinecke "target id unknown (%02x)\n", selid); 16031da177e4SLinus Torvalds return; 16041da177e4SLinus Torvalds } 16051da177e4SLinus Torvalds 16061da177e4SLinus Torvalds for(target=7; !(selid & (1 << target)); target--) 16071da177e4SLinus Torvalds ; 16081da177e4SLinus Torvalds 16091da177e4SLinus Torvalds if(selid & ~(1 << target)) { 1610f75ae8edSHannes Reinecke shost_printk(KERN_INFO, shpnt, 1611f75ae8edSHannes Reinecke "multiple targets reconnected (%02x)\n", selid); 16121da177e4SLinus Torvalds } 16131da177e4SLinus Torvalds 16141da177e4SLinus Torvalds 16151da177e4SLinus Torvalds SETPORT(SCSIID, (shpnt->this_id << OID_) | target); 16161da177e4SLinus Torvalds SETPORT(SCSISEQ, 0); 16171da177e4SLinus Torvalds 16181da177e4SLinus Torvalds SETRATE(HOSTDATA(shpnt)->syncrate[target]); 16191da177e4SLinus Torvalds 16201da177e4SLinus Torvalds RECONN_TARGET=target; 16211da177e4SLinus Torvalds } 16221da177e4SLinus Torvalds 16231da177e4SLinus Torvalds /* 16241da177e4SLinus Torvalds * message in phase 16251da177e4SLinus Torvalds * - handle initial message after reconnection to identify 16261da177e4SLinus Torvalds * reconnecting nexus 16271da177e4SLinus Torvalds * - queue command on DISCONNECTED_SC on DISCONNECT message 16281da177e4SLinus Torvalds * - set completed flag on COMMAND COMPLETE 16291da177e4SLinus Torvalds * (other completition code moved to busfree_run) 16301da177e4SLinus Torvalds * - handle response to SDTR 16311da177e4SLinus Torvalds * - clear synchronous transfer agreements on BUS RESET 16321da177e4SLinus Torvalds * 16331da177e4SLinus Torvalds * FIXME: what about SAVE POINTERS, RESTORE POINTERS? 16341da177e4SLinus Torvalds * 16351da177e4SLinus Torvalds */ 16361da177e4SLinus Torvalds static void msgi_run(struct Scsi_Host *shpnt) 16371da177e4SLinus Torvalds { 16381da177e4SLinus Torvalds for(;;) { 16391da177e4SLinus Torvalds int sstat1 = GETPORT(SSTAT1); 16401da177e4SLinus Torvalds 16411da177e4SLinus Torvalds if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT)) 16421da177e4SLinus Torvalds return; 16431da177e4SLinus Torvalds 1644f75ae8edSHannes Reinecke if (TESTLO(SSTAT0, SPIORDY)) 16451da177e4SLinus Torvalds return; 16461da177e4SLinus Torvalds 16471da177e4SLinus Torvalds ADDMSGI(GETPORT(SCSIDAT)); 16481da177e4SLinus Torvalds 16491da177e4SLinus Torvalds if(!CURRENT_SC) { 16501da177e4SLinus Torvalds if(LASTSTATE!=seldi) { 1651f75ae8edSHannes Reinecke shost_printk(KERN_ERR, shpnt, 1652f75ae8edSHannes Reinecke "message in w/o current command" 1653f75ae8edSHannes Reinecke " not after reselection\n"); 16541da177e4SLinus Torvalds } 16551da177e4SLinus Torvalds 16561da177e4SLinus Torvalds /* 16571da177e4SLinus Torvalds * Handle reselection 16581da177e4SLinus Torvalds */ 16591da177e4SLinus Torvalds if(!(MSGI(0) & IDENTIFY_BASE)) { 1660f75ae8edSHannes Reinecke shost_printk(KERN_ERR, shpnt, 1661f75ae8edSHannes Reinecke "target didn't identify after reselection\n"); 16621da177e4SLinus Torvalds continue; 16631da177e4SLinus Torvalds } 16641da177e4SLinus Torvalds 16651da177e4SLinus Torvalds CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f); 16661da177e4SLinus Torvalds 16671da177e4SLinus Torvalds if (!CURRENT_SC) { 16681da177e4SLinus Torvalds show_queues(shpnt); 1669f75ae8edSHannes Reinecke shost_printk(KERN_ERR, shpnt, 1670f75ae8edSHannes Reinecke "no disconnected command" 1671f75ae8edSHannes Reinecke " for target %d/%d\n", 1672f75ae8edSHannes Reinecke RECONN_TARGET, MSGI(0) & 0x3f); 16731da177e4SLinus Torvalds continue; 16741da177e4SLinus Torvalds } 16751da177e4SLinus Torvalds 16761da177e4SLinus Torvalds CURRENT_SC->SCp.Message = MSGI(0); 16771da177e4SLinus Torvalds CURRENT_SC->SCp.phase &= ~disconnected; 16781da177e4SLinus Torvalds 16791da177e4SLinus Torvalds MSGILEN=0; 16801da177e4SLinus Torvalds 16811da177e4SLinus Torvalds /* next message if any */ 16821da177e4SLinus Torvalds continue; 16831da177e4SLinus Torvalds } 16841da177e4SLinus Torvalds 16851da177e4SLinus Torvalds CURRENT_SC->SCp.Message = MSGI(0); 16861da177e4SLinus Torvalds 16871da177e4SLinus Torvalds switch (MSGI(0)) { 16881da177e4SLinus Torvalds case DISCONNECT: 16891da177e4SLinus Torvalds if (!RECONNECT) 1690f75ae8edSHannes Reinecke scmd_printk(KERN_WARNING, CURRENT_SC, 1691f75ae8edSHannes Reinecke "target was not allowed to disconnect\n"); 16921da177e4SLinus Torvalds 16931da177e4SLinus Torvalds CURRENT_SC->SCp.phase |= disconnected; 16941da177e4SLinus Torvalds break; 16951da177e4SLinus Torvalds 16961da177e4SLinus Torvalds case COMMAND_COMPLETE: 16971da177e4SLinus Torvalds CURRENT_SC->SCp.phase |= completed; 16981da177e4SLinus Torvalds break; 16991da177e4SLinus Torvalds 17001da177e4SLinus Torvalds case MESSAGE_REJECT: 17011da177e4SLinus Torvalds if (SYNCNEG==1) { 1702f75ae8edSHannes Reinecke scmd_printk(KERN_INFO, CURRENT_SC, 1703f75ae8edSHannes Reinecke "Synchronous Data Transfer Request" 1704f75ae8edSHannes Reinecke " was rejected\n"); 17051da177e4SLinus Torvalds SYNCNEG=2; /* negotiation completed */ 17061da177e4SLinus Torvalds } else 1707f75ae8edSHannes Reinecke scmd_printk(KERN_INFO, CURRENT_SC, 1708f75ae8edSHannes Reinecke "inbound message (MESSAGE REJECT)\n"); 17091da177e4SLinus Torvalds break; 17101da177e4SLinus Torvalds 17111da177e4SLinus Torvalds case SAVE_POINTERS: 17121da177e4SLinus Torvalds break; 17131da177e4SLinus Torvalds 17141da177e4SLinus Torvalds case RESTORE_POINTERS: 17151da177e4SLinus Torvalds break; 17161da177e4SLinus Torvalds 17171da177e4SLinus Torvalds case EXTENDED_MESSAGE: 17181da177e4SLinus Torvalds if(MSGILEN<2 || MSGILEN<MSGI(1)+2) { 17191da177e4SLinus Torvalds /* not yet completed */ 17201da177e4SLinus Torvalds continue; 17211da177e4SLinus Torvalds } 17221da177e4SLinus Torvalds 17231da177e4SLinus Torvalds switch (MSGI(2)) { 17241da177e4SLinus Torvalds case EXTENDED_SDTR: 17251da177e4SLinus Torvalds { 17261da177e4SLinus Torvalds long ticks; 17271da177e4SLinus Torvalds 17281da177e4SLinus Torvalds if (MSGI(1) != 3) { 1729f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, 1730f75ae8edSHannes Reinecke "SDTR message length!=3\n"); 17311da177e4SLinus Torvalds break; 17321da177e4SLinus Torvalds } 17331da177e4SLinus Torvalds 17341da177e4SLinus Torvalds if (!HOSTDATA(shpnt)->synchronous) 17351da177e4SLinus Torvalds break; 17361da177e4SLinus Torvalds 17371da177e4SLinus Torvalds printk(INFO_LEAD, CMDINFO(CURRENT_SC)); 17381abfd370SMatthew Wilcox spi_print_msg(&MSGI(0)); 17391da177e4SLinus Torvalds printk("\n"); 17401da177e4SLinus Torvalds 17411da177e4SLinus Torvalds ticks = (MSGI(3) * 4 + 49) / 50; 17421da177e4SLinus Torvalds 17431da177e4SLinus Torvalds if (syncneg) { 17441da177e4SLinus Torvalds /* negotiation in progress */ 17451da177e4SLinus Torvalds if (ticks > 9 || MSGI(4) < 1 || MSGI(4) > 8) { 17461da177e4SLinus Torvalds ADDMSGO(MESSAGE_REJECT); 1747f75ae8edSHannes Reinecke scmd_printk(KERN_INFO, 1748f75ae8edSHannes Reinecke CURRENT_SC, 1749f75ae8edSHannes Reinecke "received Synchronous Data Transfer Request invalid - rejected\n"); 17501da177e4SLinus Torvalds break; 17511da177e4SLinus Torvalds } 17521da177e4SLinus Torvalds 17531da177e4SLinus Torvalds SYNCRATE |= ((ticks - 2) << 4) + MSGI(4); 17541da177e4SLinus Torvalds } else if (ticks <= 9 && MSGI(4) >= 1) { 17551da177e4SLinus Torvalds ADDMSGO(EXTENDED_MESSAGE); 17561da177e4SLinus Torvalds ADDMSGO(3); 17571da177e4SLinus Torvalds ADDMSGO(EXTENDED_SDTR); 17581da177e4SLinus Torvalds if (ticks < 4) { 17591da177e4SLinus Torvalds ticks = 4; 17601da177e4SLinus Torvalds ADDMSGO(50); 17611da177e4SLinus Torvalds } else 17621da177e4SLinus Torvalds ADDMSGO(MSGI(3)); 17631da177e4SLinus Torvalds 17641da177e4SLinus Torvalds if (MSGI(4) > 8) 17651da177e4SLinus Torvalds MSGI(4) = 8; 17661da177e4SLinus Torvalds 17671da177e4SLinus Torvalds ADDMSGO(MSGI(4)); 17681da177e4SLinus Torvalds 17691da177e4SLinus Torvalds SYNCRATE |= ((ticks - 2) << 4) + MSGI(4); 17701da177e4SLinus Torvalds } else { 17711da177e4SLinus Torvalds /* requested SDTR is too slow, do it asynchronously */ 1772f75ae8edSHannes Reinecke scmd_printk(KERN_INFO, 1773f75ae8edSHannes Reinecke CURRENT_SC, 1774f75ae8edSHannes Reinecke "Synchronous Data Transfer Request too slow - Rejecting\n"); 17751da177e4SLinus Torvalds ADDMSGO(MESSAGE_REJECT); 17761da177e4SLinus Torvalds } 17771da177e4SLinus Torvalds 1778f75ae8edSHannes Reinecke /* negotiation completed */ 1779f75ae8edSHannes Reinecke SYNCNEG=2; 17801da177e4SLinus Torvalds SETRATE(SYNCRATE); 17811da177e4SLinus Torvalds } 17821da177e4SLinus Torvalds break; 17831da177e4SLinus Torvalds 17841da177e4SLinus Torvalds case BUS_DEVICE_RESET: 17851da177e4SLinus Torvalds { 17861da177e4SLinus Torvalds int i; 17871da177e4SLinus Torvalds 17881da177e4SLinus Torvalds for(i=0; i<8; i++) { 17891da177e4SLinus Torvalds HOSTDATA(shpnt)->syncrate[i]=0; 17901da177e4SLinus Torvalds HOSTDATA(shpnt)->syncneg[i]=0; 17911da177e4SLinus Torvalds } 17921da177e4SLinus Torvalds 17931da177e4SLinus Torvalds } 17941da177e4SLinus Torvalds break; 17951da177e4SLinus Torvalds 17961da177e4SLinus Torvalds case EXTENDED_MODIFY_DATA_POINTER: 17971da177e4SLinus Torvalds case EXTENDED_EXTENDED_IDENTIFY: 17981da177e4SLinus Torvalds case EXTENDED_WDTR: 17991da177e4SLinus Torvalds default: 18001da177e4SLinus Torvalds ADDMSGO(MESSAGE_REJECT); 18011da177e4SLinus Torvalds break; 18021da177e4SLinus Torvalds } 18031da177e4SLinus Torvalds break; 18041da177e4SLinus Torvalds } 18051da177e4SLinus Torvalds 18061da177e4SLinus Torvalds MSGILEN=0; 18071da177e4SLinus Torvalds } 18081da177e4SLinus Torvalds } 18091da177e4SLinus Torvalds 18101da177e4SLinus Torvalds static void msgi_end(struct Scsi_Host *shpnt) 18111da177e4SLinus Torvalds { 18121da177e4SLinus Torvalds if(MSGILEN>0) 1813f75ae8edSHannes Reinecke scmd_printk(KERN_WARNING, CURRENT_SC, 1814f75ae8edSHannes Reinecke "target left before message completed (%d)\n", 1815f75ae8edSHannes Reinecke MSGILEN); 18161da177e4SLinus Torvalds 1817f75ae8edSHannes Reinecke if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE)) 18181da177e4SLinus Torvalds SETPORT(SCSISIG, P_MSGI | SIG_ATNO); 18191da177e4SLinus Torvalds } 18201da177e4SLinus Torvalds 18211da177e4SLinus Torvalds /* 18221da177e4SLinus Torvalds * message out phase 18231da177e4SLinus Torvalds * 18241da177e4SLinus Torvalds */ 18251da177e4SLinus Torvalds static void msgo_init(struct Scsi_Host *shpnt) 18261da177e4SLinus Torvalds { 18271da177e4SLinus Torvalds if(MSGOLEN==0) { 18281da177e4SLinus Torvalds if((CURRENT_SC->SCp.phase & syncneg) && SYNCNEG==2 && SYNCRATE==0) { 18291da177e4SLinus Torvalds ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun)); 18301da177e4SLinus Torvalds } else { 1831f75ae8edSHannes Reinecke scmd_printk(KERN_INFO, CURRENT_SC, 1832f75ae8edSHannes Reinecke "unexpected MESSAGE OUT phase; rejecting\n"); 18331da177e4SLinus Torvalds ADDMSGO(MESSAGE_REJECT); 18341da177e4SLinus Torvalds } 18351da177e4SLinus Torvalds } 18361da177e4SLinus Torvalds 18371da177e4SLinus Torvalds } 18381da177e4SLinus Torvalds 18391da177e4SLinus Torvalds /* 18401da177e4SLinus Torvalds * message out phase 18411da177e4SLinus Torvalds * 18421da177e4SLinus Torvalds */ 18431da177e4SLinus Torvalds static void msgo_run(struct Scsi_Host *shpnt) 18441da177e4SLinus Torvalds { 18451da177e4SLinus Torvalds while(MSGO_I<MSGOLEN) { 1846f75ae8edSHannes Reinecke if (TESTLO(SSTAT0, SPIORDY)) 18471da177e4SLinus Torvalds return; 18481da177e4SLinus Torvalds 18491da177e4SLinus Torvalds if (MSGO_I==MSGOLEN-1) { 18501da177e4SLinus Torvalds /* Leave MESSAGE OUT after transfer */ 18511da177e4SLinus Torvalds SETPORT(SSTAT1, CLRATNO); 18521da177e4SLinus Torvalds } 18531da177e4SLinus Torvalds 18541da177e4SLinus Torvalds 18551da177e4SLinus Torvalds if (MSGO(MSGO_I) & IDENTIFY_BASE) 18561da177e4SLinus Torvalds CURRENT_SC->SCp.phase |= identified; 18571da177e4SLinus Torvalds 18581da177e4SLinus Torvalds if (MSGO(MSGO_I)==ABORT) 18591da177e4SLinus Torvalds CURRENT_SC->SCp.phase |= aborted; 18601da177e4SLinus Torvalds 18611da177e4SLinus Torvalds if (MSGO(MSGO_I)==BUS_DEVICE_RESET) 18621da177e4SLinus Torvalds CURRENT_SC->SCp.phase |= resetted; 18631da177e4SLinus Torvalds 18641da177e4SLinus Torvalds SETPORT(SCSIDAT, MSGO(MSGO_I++)); 18651da177e4SLinus Torvalds } 18661da177e4SLinus Torvalds } 18671da177e4SLinus Torvalds 18681da177e4SLinus Torvalds static void msgo_end(struct Scsi_Host *shpnt) 18691da177e4SLinus Torvalds { 18701da177e4SLinus Torvalds if(MSGO_I<MSGOLEN) { 1871f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, 1872f75ae8edSHannes Reinecke "message sent incompletely (%d/%d)\n", 1873f75ae8edSHannes Reinecke MSGO_I, MSGOLEN); 18741da177e4SLinus Torvalds if(SYNCNEG==1) { 1875f75ae8edSHannes Reinecke scmd_printk(KERN_INFO, CURRENT_SC, 1876f75ae8edSHannes Reinecke "Synchronous Data Transfer Request was rejected\n"); 18771da177e4SLinus Torvalds SYNCNEG=2; 18781da177e4SLinus Torvalds } 18791da177e4SLinus Torvalds } 18801da177e4SLinus Torvalds 18811da177e4SLinus Torvalds MSGO_I = 0; 18821da177e4SLinus Torvalds MSGOLEN = 0; 18831da177e4SLinus Torvalds } 18841da177e4SLinus Torvalds 18851da177e4SLinus Torvalds /* 18861da177e4SLinus Torvalds * command phase 18871da177e4SLinus Torvalds * 18881da177e4SLinus Torvalds */ 18891da177e4SLinus Torvalds static void cmd_init(struct Scsi_Host *shpnt) 18901da177e4SLinus Torvalds { 18911da177e4SLinus Torvalds if (CURRENT_SC->SCp.sent_command) { 1892f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, 1893f75ae8edSHannes Reinecke "command already sent\n"); 18941da177e4SLinus Torvalds done(shpnt, DID_ERROR << 16); 18951da177e4SLinus Torvalds return; 18961da177e4SLinus Torvalds } 18971da177e4SLinus Torvalds 18981da177e4SLinus Torvalds CMD_I=0; 18991da177e4SLinus Torvalds } 19001da177e4SLinus Torvalds 19011da177e4SLinus Torvalds /* 19021da177e4SLinus Torvalds * command phase 19031da177e4SLinus Torvalds * 19041da177e4SLinus Torvalds */ 19051da177e4SLinus Torvalds static void cmd_run(struct Scsi_Host *shpnt) 19061da177e4SLinus Torvalds { 19071da177e4SLinus Torvalds while(CMD_I<CURRENT_SC->cmd_len) { 1908f75ae8edSHannes Reinecke if (TESTLO(SSTAT0, SPIORDY)) 19091da177e4SLinus Torvalds return; 19101da177e4SLinus Torvalds 19111da177e4SLinus Torvalds SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]); 19121da177e4SLinus Torvalds } 19131da177e4SLinus Torvalds } 19141da177e4SLinus Torvalds 19151da177e4SLinus Torvalds static void cmd_end(struct Scsi_Host *shpnt) 19161da177e4SLinus Torvalds { 19171da177e4SLinus Torvalds if(CMD_I<CURRENT_SC->cmd_len) 1918f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, 1919f75ae8edSHannes Reinecke "command sent incompletely (%d/%d)\n", 1920f75ae8edSHannes Reinecke CMD_I, CURRENT_SC->cmd_len); 19211da177e4SLinus Torvalds else 19221da177e4SLinus Torvalds CURRENT_SC->SCp.sent_command++; 19231da177e4SLinus Torvalds } 19241da177e4SLinus Torvalds 19251da177e4SLinus Torvalds /* 19261da177e4SLinus Torvalds * status phase 19271da177e4SLinus Torvalds * 19281da177e4SLinus Torvalds */ 19291da177e4SLinus Torvalds static void status_run(struct Scsi_Host *shpnt) 19301da177e4SLinus Torvalds { 1931f75ae8edSHannes Reinecke if (TESTLO(SSTAT0, SPIORDY)) 19321da177e4SLinus Torvalds return; 19331da177e4SLinus Torvalds 19341da177e4SLinus Torvalds CURRENT_SC->SCp.Status = GETPORT(SCSIDAT); 19351da177e4SLinus Torvalds 19361da177e4SLinus Torvalds } 19371da177e4SLinus Torvalds 19381da177e4SLinus Torvalds /* 19391da177e4SLinus Torvalds * data in phase 19401da177e4SLinus Torvalds * 19411da177e4SLinus Torvalds */ 19421da177e4SLinus Torvalds static void datai_init(struct Scsi_Host *shpnt) 19431da177e4SLinus Torvalds { 19441da177e4SLinus Torvalds SETPORT(DMACNTRL0, RSTFIFO); 19451da177e4SLinus Torvalds SETPORT(DMACNTRL0, RSTFIFO|ENDMA); 19461da177e4SLinus Torvalds 19471da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|CLRSTCNT); 19481da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); 19491da177e4SLinus Torvalds 19501da177e4SLinus Torvalds SETPORT(SIMODE0, 0); 19511da177e4SLinus Torvalds SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE); 19521da177e4SLinus Torvalds 19531da177e4SLinus Torvalds DATA_LEN=0; 19541da177e4SLinus Torvalds } 19551da177e4SLinus Torvalds 19561da177e4SLinus Torvalds static void datai_run(struct Scsi_Host *shpnt) 19571da177e4SLinus Torvalds { 19581da177e4SLinus Torvalds unsigned long the_time; 19591da177e4SLinus Torvalds int fifodata, data_count; 19601da177e4SLinus Torvalds 19611da177e4SLinus Torvalds /* 19621da177e4SLinus Torvalds * loop while the phase persists or the fifos are not empty 19631da177e4SLinus Torvalds * 19641da177e4SLinus Torvalds */ 19651da177e4SLinus Torvalds while(TESTLO(DMASTAT, INTSTAT) || TESTLO(DMASTAT, DFIFOEMP) || TESTLO(SSTAT2, SEMPTY)) { 19661da177e4SLinus Torvalds /* FIXME: maybe this should be done by setting up 19671da177e4SLinus Torvalds * STCNT to trigger ENSWRAP interrupt, instead of 19681da177e4SLinus Torvalds * polling for DFIFOFULL 19691da177e4SLinus Torvalds */ 19701da177e4SLinus Torvalds the_time=jiffies + 100*HZ; 19711da177e4SLinus Torvalds while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time)) 19721da177e4SLinus Torvalds barrier(); 19731da177e4SLinus Torvalds 19741da177e4SLinus Torvalds if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) { 1975f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, "datai timeout\n"); 19761da177e4SLinus Torvalds break; 19771da177e4SLinus Torvalds } 19781da177e4SLinus Torvalds 19791da177e4SLinus Torvalds if(TESTHI(DMASTAT, DFIFOFULL)) { 19801da177e4SLinus Torvalds fifodata = 128; 19811da177e4SLinus Torvalds } else { 19821da177e4SLinus Torvalds the_time=jiffies + 100*HZ; 19831da177e4SLinus Torvalds while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time)) 19841da177e4SLinus Torvalds barrier(); 19851da177e4SLinus Torvalds 19861da177e4SLinus Torvalds if(TESTLO(SSTAT2, SEMPTY)) { 1987f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, 1988f75ae8edSHannes Reinecke "datai sempty timeout"); 19891da177e4SLinus Torvalds break; 19901da177e4SLinus Torvalds } 19911da177e4SLinus Torvalds 19921da177e4SLinus Torvalds fifodata = GETPORT(FIFOSTAT); 19931da177e4SLinus Torvalds } 19941da177e4SLinus Torvalds 19951da177e4SLinus Torvalds if(CURRENT_SC->SCp.this_residual>0) { 19961da177e4SLinus Torvalds while(fifodata>0 && CURRENT_SC->SCp.this_residual>0) { 19971da177e4SLinus Torvalds data_count = fifodata > CURRENT_SC->SCp.this_residual ? 19981da177e4SLinus Torvalds CURRENT_SC->SCp.this_residual : 19991da177e4SLinus Torvalds fifodata; 20001da177e4SLinus Torvalds fifodata -= data_count; 20011da177e4SLinus Torvalds 20021da177e4SLinus Torvalds if (data_count & 1) { 20031da177e4SLinus Torvalds SETPORT(DMACNTRL0, ENDMA|_8BIT); 20041da177e4SLinus Torvalds *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT); 20051da177e4SLinus Torvalds CURRENT_SC->SCp.this_residual--; 20061da177e4SLinus Torvalds DATA_LEN++; 20071da177e4SLinus Torvalds SETPORT(DMACNTRL0, ENDMA); 20081da177e4SLinus Torvalds } 20091da177e4SLinus Torvalds 20101da177e4SLinus Torvalds if (data_count > 1) { 20111da177e4SLinus Torvalds data_count >>= 1; 20121da177e4SLinus Torvalds insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); 20131da177e4SLinus Torvalds CURRENT_SC->SCp.ptr += 2 * data_count; 20141da177e4SLinus Torvalds CURRENT_SC->SCp.this_residual -= 2 * data_count; 20151da177e4SLinus Torvalds DATA_LEN += 2 * data_count; 20161da177e4SLinus Torvalds } 20171da177e4SLinus Torvalds 2018f75ae8edSHannes Reinecke if (CURRENT_SC->SCp.this_residual == 0 && 2019a7a253baSFinn Thain !sg_is_last(CURRENT_SC->SCp.buffer)) { 20201da177e4SLinus Torvalds /* advance to next buffer */ 2021a7a253baSFinn Thain CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer); 20221da177e4SLinus Torvalds CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer); 20231da177e4SLinus Torvalds CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; 20241da177e4SLinus Torvalds } 20251da177e4SLinus Torvalds } 20261da177e4SLinus Torvalds } else if (fifodata > 0) { 2027f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, 2028f75ae8edSHannes Reinecke "no buffers left for %d(%d) bytes" 2029f75ae8edSHannes Reinecke " (data overrun!?)\n", 2030f75ae8edSHannes Reinecke fifodata, GETPORT(FIFOSTAT)); 20311da177e4SLinus Torvalds SETPORT(DMACNTRL0, ENDMA|_8BIT); 20321da177e4SLinus Torvalds while(fifodata>0) { 2033*3c011793SLee Jones GETPORT(DATAPORT); 20341da177e4SLinus Torvalds fifodata--; 20351da177e4SLinus Torvalds DATA_LEN++; 20361da177e4SLinus Torvalds } 20371da177e4SLinus Torvalds SETPORT(DMACNTRL0, ENDMA|_8BIT); 20381da177e4SLinus Torvalds } 20391da177e4SLinus Torvalds } 20401da177e4SLinus Torvalds 20411da177e4SLinus Torvalds if(TESTLO(DMASTAT, INTSTAT) || 20421da177e4SLinus Torvalds TESTLO(DMASTAT, DFIFOEMP) || 20431da177e4SLinus Torvalds TESTLO(SSTAT2, SEMPTY) || 20441da177e4SLinus Torvalds GETPORT(FIFOSTAT)>0) { 20451da177e4SLinus Torvalds /* 20461da177e4SLinus Torvalds * something went wrong, if there's something left in the fifos 20471da177e4SLinus Torvalds * or the phase didn't change 20481da177e4SLinus Torvalds */ 2049f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, 2050f75ae8edSHannes Reinecke "fifos should be empty and phase should have changed\n"); 20511da177e4SLinus Torvalds } 20521da177e4SLinus Torvalds 20531da177e4SLinus Torvalds if(DATA_LEN!=GETSTCNT()) { 2054f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, 2055f75ae8edSHannes Reinecke "manual transfer count differs from automatic " 2056f75ae8edSHannes Reinecke "(count=%d;stcnt=%d;diff=%d;fifostat=%d)", 2057f75ae8edSHannes Reinecke DATA_LEN, GETSTCNT(), GETSTCNT()-DATA_LEN, 2058f75ae8edSHannes Reinecke GETPORT(FIFOSTAT)); 20591da177e4SLinus Torvalds mdelay(10000); 20601da177e4SLinus Torvalds } 20611da177e4SLinus Torvalds } 20621da177e4SLinus Torvalds 20631da177e4SLinus Torvalds static void datai_end(struct Scsi_Host *shpnt) 20641da177e4SLinus Torvalds { 20652338545aSBoaz Harrosh CMD_INC_RESID(CURRENT_SC, -GETSTCNT()); 20661da177e4SLinus Torvalds 20671da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|CLRSTCNT); 20681da177e4SLinus Torvalds SETPORT(DMACNTRL0, 0); 20691da177e4SLinus Torvalds } 20701da177e4SLinus Torvalds 20711da177e4SLinus Torvalds /* 20721da177e4SLinus Torvalds * data out phase 20731da177e4SLinus Torvalds * 20741da177e4SLinus Torvalds */ 20751da177e4SLinus Torvalds static void datao_init(struct Scsi_Host *shpnt) 20761da177e4SLinus Torvalds { 20771da177e4SLinus Torvalds SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO); 20781da177e4SLinus Torvalds SETPORT(DMACNTRL0, WRITE_READ | ENDMA); 20791da177e4SLinus Torvalds 20801da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|CLRSTCNT); 20811da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); 20821da177e4SLinus Torvalds 20831da177e4SLinus Torvalds SETPORT(SIMODE0, 0); 20841da177e4SLinus Torvalds SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE ); 20851da177e4SLinus Torvalds 20862338545aSBoaz Harrosh DATA_LEN = scsi_get_resid(CURRENT_SC); 20871da177e4SLinus Torvalds } 20881da177e4SLinus Torvalds 20891da177e4SLinus Torvalds static void datao_run(struct Scsi_Host *shpnt) 20901da177e4SLinus Torvalds { 20911da177e4SLinus Torvalds unsigned long the_time; 20921da177e4SLinus Torvalds int data_count; 20931da177e4SLinus Torvalds 20941da177e4SLinus Torvalds /* until phase changes or all data sent */ 20951da177e4SLinus Torvalds while(TESTLO(DMASTAT, INTSTAT) && CURRENT_SC->SCp.this_residual>0) { 20961da177e4SLinus Torvalds data_count = 128; 20971da177e4SLinus Torvalds if(data_count > CURRENT_SC->SCp.this_residual) 20981da177e4SLinus Torvalds data_count=CURRENT_SC->SCp.this_residual; 20991da177e4SLinus Torvalds 21001da177e4SLinus Torvalds if(TESTLO(DMASTAT, DFIFOEMP)) { 2101f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, 2102f75ae8edSHannes Reinecke "datao fifo not empty (%d)", 2103f75ae8edSHannes Reinecke GETPORT(FIFOSTAT)); 21041da177e4SLinus Torvalds break; 21051da177e4SLinus Torvalds } 21061da177e4SLinus Torvalds 21071da177e4SLinus Torvalds if(data_count & 1) { 21081da177e4SLinus Torvalds SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT); 21091da177e4SLinus Torvalds SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++); 21101da177e4SLinus Torvalds CURRENT_SC->SCp.this_residual--; 21112338545aSBoaz Harrosh CMD_INC_RESID(CURRENT_SC, -1); 21121da177e4SLinus Torvalds SETPORT(DMACNTRL0,WRITE_READ|ENDMA); 21131da177e4SLinus Torvalds } 21141da177e4SLinus Torvalds 21151da177e4SLinus Torvalds if(data_count > 1) { 21161da177e4SLinus Torvalds data_count >>= 1; 21171da177e4SLinus Torvalds outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); 21181da177e4SLinus Torvalds CURRENT_SC->SCp.ptr += 2 * data_count; 21191da177e4SLinus Torvalds CURRENT_SC->SCp.this_residual -= 2 * data_count; 21202338545aSBoaz Harrosh CMD_INC_RESID(CURRENT_SC, -2 * data_count); 21211da177e4SLinus Torvalds } 21221da177e4SLinus Torvalds 2123a7a253baSFinn Thain if (CURRENT_SC->SCp.this_residual == 0 && 2124a7a253baSFinn Thain !sg_is_last(CURRENT_SC->SCp.buffer)) { 21251da177e4SLinus Torvalds /* advance to next buffer */ 2126a7a253baSFinn Thain CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer); 21271da177e4SLinus Torvalds CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer); 21281da177e4SLinus Torvalds CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; 21291da177e4SLinus Torvalds } 21301da177e4SLinus Torvalds 21311da177e4SLinus Torvalds the_time=jiffies + 100*HZ; 21321da177e4SLinus Torvalds while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time)) 21331da177e4SLinus Torvalds barrier(); 21341da177e4SLinus Torvalds 21351da177e4SLinus Torvalds if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) { 2136f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, "dataout timeout\n"); 21371da177e4SLinus Torvalds break; 21381da177e4SLinus Torvalds } 21391da177e4SLinus Torvalds } 21401da177e4SLinus Torvalds } 21411da177e4SLinus Torvalds 21421da177e4SLinus Torvalds static void datao_end(struct Scsi_Host *shpnt) 21431da177e4SLinus Torvalds { 21441da177e4SLinus Torvalds if(TESTLO(DMASTAT, DFIFOEMP)) { 2145a7a253baSFinn Thain u32 datao_cnt = GETSTCNT(); 2146a7a253baSFinn Thain int datao_out = DATA_LEN - scsi_get_resid(CURRENT_SC); 2147a7a253baSFinn Thain int done; 2148a7a253baSFinn Thain struct scatterlist *sg = scsi_sglist(CURRENT_SC); 21491da177e4SLinus Torvalds 2150a7a253baSFinn Thain CMD_INC_RESID(CURRENT_SC, datao_out - datao_cnt); 21511da177e4SLinus Torvalds 2152a7a253baSFinn Thain done = scsi_bufflen(CURRENT_SC) - scsi_get_resid(CURRENT_SC); 2153a7a253baSFinn Thain /* Locate the first SG entry not yet sent */ 2154a7a253baSFinn Thain while (done > 0 && !sg_is_last(sg)) { 2155a7a253baSFinn Thain if (done < sg->length) 2156a7a253baSFinn Thain break; 2157a7a253baSFinn Thain done -= sg->length; 2158a7a253baSFinn Thain sg = sg_next(sg); 21591da177e4SLinus Torvalds } 2160a7a253baSFinn Thain 2161a7a253baSFinn Thain CURRENT_SC->SCp.buffer = sg; 2162a7a253baSFinn Thain CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) + done; 2163a7a253baSFinn Thain CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length - 2164a7a253baSFinn Thain done; 21651da177e4SLinus Torvalds } 21661da177e4SLinus Torvalds 21671da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); 21681da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1); 21691da177e4SLinus Torvalds 21701da177e4SLinus Torvalds SETPORT(DMACNTRL0, 0); 21711da177e4SLinus Torvalds } 21721da177e4SLinus Torvalds 21731da177e4SLinus Torvalds /* 21741da177e4SLinus Torvalds * figure out what state we're in 21751da177e4SLinus Torvalds * 21761da177e4SLinus Torvalds */ 21771da177e4SLinus Torvalds static int update_state(struct Scsi_Host *shpnt) 21781da177e4SLinus Torvalds { 21791da177e4SLinus Torvalds int dataphase=0; 21801da177e4SLinus Torvalds unsigned int stat0 = GETPORT(SSTAT0); 21811da177e4SLinus Torvalds unsigned int stat1 = GETPORT(SSTAT1); 21821da177e4SLinus Torvalds 21831da177e4SLinus Torvalds PREVSTATE = STATE; 21841da177e4SLinus Torvalds STATE=unknown; 21851da177e4SLinus Torvalds 21861da177e4SLinus Torvalds if(stat1 & SCSIRSTI) { 21871da177e4SLinus Torvalds STATE=rsti; 21881da177e4SLinus Torvalds SETPORT(SCSISEQ,0); 21891da177e4SLinus Torvalds SETPORT(SSTAT1,SCSIRSTI); 21901da177e4SLinus Torvalds } else if (stat0 & SELDI && PREVSTATE == busfree) { 21911da177e4SLinus Torvalds STATE=seldi; 21921da177e4SLinus Torvalds } else if(stat0 & SELDO && CURRENT_SC && (CURRENT_SC->SCp.phase & selecting)) { 21931da177e4SLinus Torvalds STATE=seldo; 21941da177e4SLinus Torvalds } else if(stat1 & SELTO) { 21951da177e4SLinus Torvalds STATE=selto; 21961da177e4SLinus Torvalds } else if(stat1 & BUSFREE) { 21971da177e4SLinus Torvalds STATE=busfree; 21981da177e4SLinus Torvalds SETPORT(SSTAT1,BUSFREE); 21991da177e4SLinus Torvalds } else if(stat1 & SCSIPERR) { 22001da177e4SLinus Torvalds STATE=parerr; 22011da177e4SLinus Torvalds SETPORT(SSTAT1,SCSIPERR); 22021da177e4SLinus Torvalds } else if(stat1 & REQINIT) { 22031da177e4SLinus Torvalds switch(GETPORT(SCSISIG) & P_MASK) { 22041da177e4SLinus Torvalds case P_MSGI: STATE=msgi; break; 22051da177e4SLinus Torvalds case P_MSGO: STATE=msgo; break; 22061da177e4SLinus Torvalds case P_DATAO: STATE=datao; break; 22071da177e4SLinus Torvalds case P_DATAI: STATE=datai; break; 22081da177e4SLinus Torvalds case P_STATUS: STATE=status; break; 22091da177e4SLinus Torvalds case P_CMD: STATE=cmd; break; 22101da177e4SLinus Torvalds } 22111da177e4SLinus Torvalds dataphase=1; 22121da177e4SLinus Torvalds } 22131da177e4SLinus Torvalds 22141da177e4SLinus Torvalds if((stat0 & SELDI) && STATE!=seldi && !dataphase) { 2215f75ae8edSHannes Reinecke scmd_printk(KERN_INFO, CURRENT_SC, "reselection missed?"); 22161da177e4SLinus Torvalds } 22171da177e4SLinus Torvalds 22181da177e4SLinus Torvalds if(STATE!=PREVSTATE) { 22191da177e4SLinus Torvalds LASTSTATE=PREVSTATE; 22201da177e4SLinus Torvalds } 22211da177e4SLinus Torvalds 22221da177e4SLinus Torvalds return dataphase; 22231da177e4SLinus Torvalds } 22241da177e4SLinus Torvalds 22251da177e4SLinus Torvalds /* 22261da177e4SLinus Torvalds * handle parity error 22271da177e4SLinus Torvalds * 22281da177e4SLinus Torvalds * FIXME: in which phase? 22291da177e4SLinus Torvalds * 22301da177e4SLinus Torvalds */ 22311da177e4SLinus Torvalds static void parerr_run(struct Scsi_Host *shpnt) 22321da177e4SLinus Torvalds { 2233f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, "parity error\n"); 22341da177e4SLinus Torvalds done(shpnt, DID_PARITY << 16); 22351da177e4SLinus Torvalds } 22361da177e4SLinus Torvalds 22371da177e4SLinus Torvalds /* 22381da177e4SLinus Torvalds * handle reset in 22391da177e4SLinus Torvalds * 22401da177e4SLinus Torvalds */ 22411da177e4SLinus Torvalds static void rsti_run(struct Scsi_Host *shpnt) 22421da177e4SLinus Torvalds { 224391ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr; 22441da177e4SLinus Torvalds 2245f75ae8edSHannes Reinecke shost_printk(KERN_NOTICE, shpnt, "scsi reset in\n"); 22461da177e4SLinus Torvalds 22471da177e4SLinus Torvalds ptr=DISCONNECTED_SC; 22481da177e4SLinus Torvalds while(ptr) { 224991ebc1faSJohannes Thumshirn struct scsi_cmnd *next = SCNEXT(ptr); 22501da177e4SLinus Torvalds 22511da177e4SLinus Torvalds if (!ptr->device->soft_reset) { 22521da177e4SLinus Torvalds remove_SC(&DISCONNECTED_SC, ptr); 22531da177e4SLinus Torvalds 22541da177e4SLinus Torvalds kfree(ptr->host_scribble); 22551da177e4SLinus Torvalds ptr->host_scribble=NULL; 22561da177e4SLinus Torvalds 22571da177e4SLinus Torvalds ptr->result = DID_RESET << 16; 22581da177e4SLinus Torvalds ptr->scsi_done(ptr); 22591da177e4SLinus Torvalds } 22601da177e4SLinus Torvalds 22611da177e4SLinus Torvalds ptr = next; 22621da177e4SLinus Torvalds } 22631da177e4SLinus Torvalds 22641da177e4SLinus Torvalds if(CURRENT_SC && !CURRENT_SC->device->soft_reset) 22651da177e4SLinus Torvalds done(shpnt, DID_RESET << 16 ); 22661da177e4SLinus Torvalds } 22671da177e4SLinus Torvalds 22681da177e4SLinus Torvalds 22691da177e4SLinus Torvalds /* 22701da177e4SLinus Torvalds * bottom-half handler 22711da177e4SLinus Torvalds * 22721da177e4SLinus Torvalds */ 22731da177e4SLinus Torvalds static void is_complete(struct Scsi_Host *shpnt) 22741da177e4SLinus Torvalds { 22751da177e4SLinus Torvalds int dataphase; 22761da177e4SLinus Torvalds unsigned long flags; 22771da177e4SLinus Torvalds int pending; 22781da177e4SLinus Torvalds 2279e2482fa1SJürgen E. Fischer if(!shpnt) 2280e2482fa1SJürgen E. Fischer return; 2281e2482fa1SJürgen E. Fischer 22821da177e4SLinus Torvalds DO_LOCK(flags); 2283e2482fa1SJürgen E. Fischer 2284e2482fa1SJürgen E. Fischer if( HOSTDATA(shpnt)->service==0 ) { 2285e2482fa1SJürgen E. Fischer DO_UNLOCK(flags); 2286e2482fa1SJürgen E. Fischer return; 2287e2482fa1SJürgen E. Fischer } 2288e2482fa1SJürgen E. Fischer 2289e2482fa1SJürgen E. Fischer HOSTDATA(shpnt)->service = 0; 2290e2482fa1SJürgen E. Fischer 22911da177e4SLinus Torvalds if(HOSTDATA(shpnt)->in_intr) { 22921da177e4SLinus Torvalds DO_UNLOCK(flags); 22931da177e4SLinus Torvalds /* aha152x_error never returns.. */ 22941da177e4SLinus Torvalds aha152x_error(shpnt, "bottom-half already running!?"); 22951da177e4SLinus Torvalds } 22961da177e4SLinus Torvalds HOSTDATA(shpnt)->in_intr++; 22971da177e4SLinus Torvalds 22981da177e4SLinus Torvalds /* 22991da177e4SLinus Torvalds * loop while there are interrupt conditions pending 23001da177e4SLinus Torvalds * 23011da177e4SLinus Torvalds */ 23021da177e4SLinus Torvalds do { 23031da177e4SLinus Torvalds unsigned long start = jiffies; 23041da177e4SLinus Torvalds DO_UNLOCK(flags); 23051da177e4SLinus Torvalds 23061da177e4SLinus Torvalds dataphase=update_state(shpnt); 23071da177e4SLinus Torvalds 23081da177e4SLinus Torvalds /* 23091da177e4SLinus Torvalds * end previous state 23101da177e4SLinus Torvalds * 23111da177e4SLinus Torvalds */ 23121da177e4SLinus Torvalds if(PREVSTATE!=STATE && states[PREVSTATE].end) 23131da177e4SLinus Torvalds states[PREVSTATE].end(shpnt); 23141da177e4SLinus Torvalds 23151da177e4SLinus Torvalds /* 23161da177e4SLinus Torvalds * disable SPIO mode if previous phase used it 23171da177e4SLinus Torvalds * and this one doesn't 23181da177e4SLinus Torvalds * 23191da177e4SLinus Torvalds */ 23201da177e4SLinus Torvalds if(states[PREVSTATE].spio && !states[STATE].spio) { 23211da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1); 23221da177e4SLinus Torvalds SETPORT(DMACNTRL0, 0); 23231da177e4SLinus Torvalds if(CURRENT_SC) 23241da177e4SLinus Torvalds CURRENT_SC->SCp.phase &= ~spiordy; 23251da177e4SLinus Torvalds } 23261da177e4SLinus Torvalds 23271da177e4SLinus Torvalds /* 23281da177e4SLinus Torvalds * accept current dataphase phase 23291da177e4SLinus Torvalds * 23301da177e4SLinus Torvalds */ 23311da177e4SLinus Torvalds if(dataphase) { 23321da177e4SLinus Torvalds SETPORT(SSTAT0, REQINIT); 23331da177e4SLinus Torvalds SETPORT(SCSISIG, GETPORT(SCSISIG) & P_MASK); 23341da177e4SLinus Torvalds SETPORT(SSTAT1, PHASECHG); 23351da177e4SLinus Torvalds } 23361da177e4SLinus Torvalds 23371da177e4SLinus Torvalds /* 23381da177e4SLinus Torvalds * enable SPIO mode if previous didn't use it 23391da177e4SLinus Torvalds * and this one does 23401da177e4SLinus Torvalds * 23411da177e4SLinus Torvalds */ 23421da177e4SLinus Torvalds if(!states[PREVSTATE].spio && states[STATE].spio) { 23431da177e4SLinus Torvalds SETPORT(DMACNTRL0, 0); 23441da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|SPIOEN); 23451da177e4SLinus Torvalds if(CURRENT_SC) 23461da177e4SLinus Torvalds CURRENT_SC->SCp.phase |= spiordy; 23471da177e4SLinus Torvalds } 23481da177e4SLinus Torvalds 23491da177e4SLinus Torvalds /* 23501da177e4SLinus Torvalds * initialize for new state 23511da177e4SLinus Torvalds * 23521da177e4SLinus Torvalds */ 23531da177e4SLinus Torvalds if(PREVSTATE!=STATE && states[STATE].init) 23541da177e4SLinus Torvalds states[STATE].init(shpnt); 23551da177e4SLinus Torvalds 23561da177e4SLinus Torvalds /* 23571da177e4SLinus Torvalds * handle current state 23581da177e4SLinus Torvalds * 23591da177e4SLinus Torvalds */ 23601da177e4SLinus Torvalds if(states[STATE].run) 23611da177e4SLinus Torvalds states[STATE].run(shpnt); 23621da177e4SLinus Torvalds else 2363f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, 2364f75ae8edSHannes Reinecke "unexpected state (%x)\n", STATE); 23651da177e4SLinus Torvalds 23661da177e4SLinus Torvalds /* 23671da177e4SLinus Torvalds * setup controller to interrupt on 23681da177e4SLinus Torvalds * the next expected condition and 23691da177e4SLinus Torvalds * loop if it's already there 23701da177e4SLinus Torvalds * 23711da177e4SLinus Torvalds */ 23721da177e4SLinus Torvalds DO_LOCK(flags); 23731da177e4SLinus Torvalds pending=setup_expected_interrupts(shpnt); 23741da177e4SLinus Torvalds #if defined(AHA152X_STAT) 23751da177e4SLinus Torvalds HOSTDATA(shpnt)->count[STATE]++; 23761da177e4SLinus Torvalds if(PREVSTATE!=STATE) 23771da177e4SLinus Torvalds HOSTDATA(shpnt)->count_trans[STATE]++; 23781da177e4SLinus Torvalds HOSTDATA(shpnt)->time[STATE] += jiffies-start; 23791da177e4SLinus Torvalds #endif 23801da177e4SLinus Torvalds 23811da177e4SLinus Torvalds } while(pending); 23821da177e4SLinus Torvalds 23831da177e4SLinus Torvalds /* 23841da177e4SLinus Torvalds * enable interrupts and leave bottom-half 23851da177e4SLinus Torvalds * 23861da177e4SLinus Torvalds */ 23871da177e4SLinus Torvalds HOSTDATA(shpnt)->in_intr--; 23881da177e4SLinus Torvalds SETBITS(DMACNTRL0, INTEN); 23891da177e4SLinus Torvalds DO_UNLOCK(flags); 23901da177e4SLinus Torvalds } 23911da177e4SLinus Torvalds 23921da177e4SLinus Torvalds 23931da177e4SLinus Torvalds /* 23941da177e4SLinus Torvalds * Dump the current driver status and panic 23951da177e4SLinus Torvalds */ 23961da177e4SLinus Torvalds static void aha152x_error(struct Scsi_Host *shpnt, char *msg) 23971da177e4SLinus Torvalds { 2398f75ae8edSHannes Reinecke shost_printk(KERN_EMERG, shpnt, "%s\n", msg); 23991da177e4SLinus Torvalds show_queues(shpnt); 24001da177e4SLinus Torvalds panic("aha152x panic\n"); 24011da177e4SLinus Torvalds } 24021da177e4SLinus Torvalds 24031da177e4SLinus Torvalds /* 24041da177e4SLinus Torvalds * display enabled interrupts 24051da177e4SLinus Torvalds */ 24061da177e4SLinus Torvalds static void disp_enintr(struct Scsi_Host *shpnt) 24071da177e4SLinus Torvalds { 2408f75ae8edSHannes Reinecke int s0, s1; 24091da177e4SLinus Torvalds 2410f75ae8edSHannes Reinecke s0 = GETPORT(SIMODE0); 2411f75ae8edSHannes Reinecke s1 = GETPORT(SIMODE1); 24121da177e4SLinus Torvalds 2413f75ae8edSHannes Reinecke shost_printk(KERN_DEBUG, shpnt, 2414f75ae8edSHannes Reinecke "enabled interrupts (%s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n", 2415f75ae8edSHannes Reinecke (s0 & ENSELDO) ? "ENSELDO " : "", 2416f75ae8edSHannes Reinecke (s0 & ENSELDI) ? "ENSELDI " : "", 2417f75ae8edSHannes Reinecke (s0 & ENSELINGO) ? "ENSELINGO " : "", 2418f75ae8edSHannes Reinecke (s0 & ENSWRAP) ? "ENSWRAP " : "", 2419f75ae8edSHannes Reinecke (s0 & ENSDONE) ? "ENSDONE " : "", 2420f75ae8edSHannes Reinecke (s0 & ENSPIORDY) ? "ENSPIORDY " : "", 2421f75ae8edSHannes Reinecke (s0 & ENDMADONE) ? "ENDMADONE " : "", 2422f75ae8edSHannes Reinecke (s1 & ENSELTIMO) ? "ENSELTIMO " : "", 2423f75ae8edSHannes Reinecke (s1 & ENATNTARG) ? "ENATNTARG " : "", 2424f75ae8edSHannes Reinecke (s1 & ENPHASEMIS) ? "ENPHASEMIS " : "", 2425f75ae8edSHannes Reinecke (s1 & ENBUSFREE) ? "ENBUSFREE " : "", 2426f75ae8edSHannes Reinecke (s1 & ENSCSIPERR) ? "ENSCSIPERR " : "", 2427f75ae8edSHannes Reinecke (s1 & ENPHASECHG) ? "ENPHASECHG " : "", 2428f75ae8edSHannes Reinecke (s1 & ENREQINIT) ? "ENREQINIT " : ""); 24291da177e4SLinus Torvalds } 24301da177e4SLinus Torvalds 24311da177e4SLinus Torvalds /* 24321da177e4SLinus Torvalds * Show the command data of a command 24331da177e4SLinus Torvalds */ 243491ebc1faSJohannes Thumshirn static void show_command(struct scsi_cmnd *ptr) 24351da177e4SLinus Torvalds { 2436f75ae8edSHannes Reinecke scsi_print_command(ptr); 2437f75ae8edSHannes Reinecke scmd_printk(KERN_DEBUG, ptr, 2438f75ae8edSHannes Reinecke "request_bufflen=%d; resid=%d; " 2439f75ae8edSHannes Reinecke "phase |%s%s%s%s%s%s%s%s%s; next=0x%p", 2440f75ae8edSHannes Reinecke scsi_bufflen(ptr), scsi_get_resid(ptr), 2441f75ae8edSHannes Reinecke (ptr->SCp.phase & not_issued) ? "not issued|" : "", 2442f75ae8edSHannes Reinecke (ptr->SCp.phase & selecting) ? "selecting|" : "", 2443f75ae8edSHannes Reinecke (ptr->SCp.phase & identified) ? "identified|" : "", 2444f75ae8edSHannes Reinecke (ptr->SCp.phase & disconnected) ? "disconnected|" : "", 2445f75ae8edSHannes Reinecke (ptr->SCp.phase & completed) ? "completed|" : "", 2446f75ae8edSHannes Reinecke (ptr->SCp.phase & spiordy) ? "spiordy|" : "", 2447f75ae8edSHannes Reinecke (ptr->SCp.phase & syncneg) ? "syncneg|" : "", 2448f75ae8edSHannes Reinecke (ptr->SCp.phase & aborted) ? "aborted|" : "", 2449f75ae8edSHannes Reinecke (ptr->SCp.phase & resetted) ? "resetted|" : "", 2450f75ae8edSHannes Reinecke (SCDATA(ptr)) ? SCNEXT(ptr) : NULL); 24511da177e4SLinus Torvalds } 24521da177e4SLinus Torvalds 24531da177e4SLinus Torvalds /* 24541da177e4SLinus Torvalds * Dump the queued data 24551da177e4SLinus Torvalds */ 24561da177e4SLinus Torvalds static void show_queues(struct Scsi_Host *shpnt) 24571da177e4SLinus Torvalds { 245891ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr; 24591da177e4SLinus Torvalds unsigned long flags; 24601da177e4SLinus Torvalds 24611da177e4SLinus Torvalds DO_LOCK(flags); 24621da177e4SLinus Torvalds printk(KERN_DEBUG "\nqueue status:\nissue_SC:\n"); 24631da177e4SLinus Torvalds for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr)) 24641da177e4SLinus Torvalds show_command(ptr); 24651da177e4SLinus Torvalds DO_UNLOCK(flags); 24661da177e4SLinus Torvalds 24671da177e4SLinus Torvalds printk(KERN_DEBUG "current_SC:\n"); 24681da177e4SLinus Torvalds if (CURRENT_SC) 24691da177e4SLinus Torvalds show_command(CURRENT_SC); 24701da177e4SLinus Torvalds else 24711da177e4SLinus Torvalds printk(KERN_DEBUG "none\n"); 24721da177e4SLinus Torvalds 24731da177e4SLinus Torvalds printk(KERN_DEBUG "disconnected_SC:\n"); 24741da177e4SLinus Torvalds for (ptr = DISCONNECTED_SC; ptr; ptr = SCDATA(ptr) ? SCNEXT(ptr) : NULL) 24751da177e4SLinus Torvalds show_command(ptr); 24761da177e4SLinus Torvalds 24771da177e4SLinus Torvalds disp_enintr(shpnt); 24781da177e4SLinus Torvalds } 24791da177e4SLinus Torvalds 248091ebc1faSJohannes Thumshirn static void get_command(struct seq_file *m, struct scsi_cmnd * ptr) 24811da177e4SLinus Torvalds { 24821da177e4SLinus Torvalds int i; 24831da177e4SLinus Torvalds 24840c3de38fSRasmus Villemoes seq_printf(m, "%p: target=%d; lun=%d; cmnd=( ", 24859cb78c16SHannes Reinecke ptr, ptr->device->id, (u8)ptr->device->lun); 24861da177e4SLinus Torvalds 24871da177e4SLinus Torvalds for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++) 24880c3de38fSRasmus Villemoes seq_printf(m, "0x%02x ", ptr->cmnd[i]); 24891da177e4SLinus Torvalds 24900c3de38fSRasmus Villemoes seq_printf(m, "); resid=%d; residual=%d; buffers=%d; phase |", 24912338545aSBoaz Harrosh scsi_get_resid(ptr), ptr->SCp.this_residual, 2492a7a253baSFinn Thain sg_nents(ptr->SCp.buffer) - 1); 24931da177e4SLinus Torvalds 24941da177e4SLinus Torvalds if (ptr->SCp.phase & not_issued) 2495ee7c7277SRasmus Villemoes seq_puts(m, "not issued|"); 24961da177e4SLinus Torvalds if (ptr->SCp.phase & selecting) 2497ee7c7277SRasmus Villemoes seq_puts(m, "selecting|"); 24981da177e4SLinus Torvalds if (ptr->SCp.phase & disconnected) 2499ee7c7277SRasmus Villemoes seq_puts(m, "disconnected|"); 25001da177e4SLinus Torvalds if (ptr->SCp.phase & aborted) 2501ee7c7277SRasmus Villemoes seq_puts(m, "aborted|"); 25021da177e4SLinus Torvalds if (ptr->SCp.phase & identified) 2503ee7c7277SRasmus Villemoes seq_puts(m, "identified|"); 25041da177e4SLinus Torvalds if (ptr->SCp.phase & completed) 2505ee7c7277SRasmus Villemoes seq_puts(m, "completed|"); 25061da177e4SLinus Torvalds if (ptr->SCp.phase & spiordy) 2507ee7c7277SRasmus Villemoes seq_puts(m, "spiordy|"); 25081da177e4SLinus Torvalds if (ptr->SCp.phase & syncneg) 2509ee7c7277SRasmus Villemoes seq_puts(m, "syncneg|"); 25100c3de38fSRasmus Villemoes seq_printf(m, "; next=0x%p\n", SCNEXT(ptr)); 25111da177e4SLinus Torvalds } 25121da177e4SLinus Torvalds 2513275084cbSAl Viro static void get_ports(struct seq_file *m, struct Scsi_Host *shpnt) 25141da177e4SLinus Torvalds { 25151da177e4SLinus Torvalds int s; 25161da177e4SLinus Torvalds 25170c3de38fSRasmus Villemoes seq_printf(m, "\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name); 25181da177e4SLinus Torvalds 25191da177e4SLinus Torvalds s = GETPORT(SCSISEQ); 2520ee7c7277SRasmus Villemoes seq_puts(m, "SCSISEQ( "); 25211da177e4SLinus Torvalds if (s & TEMODEO) 2522ee7c7277SRasmus Villemoes seq_puts(m, "TARGET MODE "); 25231da177e4SLinus Torvalds if (s & ENSELO) 2524ee7c7277SRasmus Villemoes seq_puts(m, "SELO "); 25251da177e4SLinus Torvalds if (s & ENSELI) 2526ee7c7277SRasmus Villemoes seq_puts(m, "SELI "); 25271da177e4SLinus Torvalds if (s & ENRESELI) 2528ee7c7277SRasmus Villemoes seq_puts(m, "RESELI "); 25291da177e4SLinus Torvalds if (s & ENAUTOATNO) 2530ee7c7277SRasmus Villemoes seq_puts(m, "AUTOATNO "); 25311da177e4SLinus Torvalds if (s & ENAUTOATNI) 2532ee7c7277SRasmus Villemoes seq_puts(m, "AUTOATNI "); 25331da177e4SLinus Torvalds if (s & ENAUTOATNP) 2534ee7c7277SRasmus Villemoes seq_puts(m, "AUTOATNP "); 25351da177e4SLinus Torvalds if (s & SCSIRSTO) 2536ee7c7277SRasmus Villemoes seq_puts(m, "SCSIRSTO "); 2537ee7c7277SRasmus Villemoes seq_puts(m, ");"); 25381da177e4SLinus Torvalds 2539ee7c7277SRasmus Villemoes seq_puts(m, " SCSISIG("); 25401da177e4SLinus Torvalds s = GETPORT(SCSISIG); 25411da177e4SLinus Torvalds switch (s & P_MASK) { 25421da177e4SLinus Torvalds case P_DATAO: 2543ee7c7277SRasmus Villemoes seq_puts(m, "DATA OUT"); 25441da177e4SLinus Torvalds break; 25451da177e4SLinus Torvalds case P_DATAI: 2546ee7c7277SRasmus Villemoes seq_puts(m, "DATA IN"); 25471da177e4SLinus Torvalds break; 25481da177e4SLinus Torvalds case P_CMD: 2549ee7c7277SRasmus Villemoes seq_puts(m, "COMMAND"); 25501da177e4SLinus Torvalds break; 25511da177e4SLinus Torvalds case P_STATUS: 2552ee7c7277SRasmus Villemoes seq_puts(m, "STATUS"); 25531da177e4SLinus Torvalds break; 25541da177e4SLinus Torvalds case P_MSGO: 2555ee7c7277SRasmus Villemoes seq_puts(m, "MESSAGE OUT"); 25561da177e4SLinus Torvalds break; 25571da177e4SLinus Torvalds case P_MSGI: 2558ee7c7277SRasmus Villemoes seq_puts(m, "MESSAGE IN"); 25591da177e4SLinus Torvalds break; 25601da177e4SLinus Torvalds default: 2561ee7c7277SRasmus Villemoes seq_puts(m, "*invalid*"); 25621da177e4SLinus Torvalds break; 25631da177e4SLinus Torvalds } 25641da177e4SLinus Torvalds 2565ee7c7277SRasmus Villemoes seq_puts(m, "); "); 25661da177e4SLinus Torvalds 25670c3de38fSRasmus Villemoes seq_printf(m, "INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); 25681da177e4SLinus Torvalds 2569ee7c7277SRasmus Villemoes seq_puts(m, "SSTAT( "); 25701da177e4SLinus Torvalds s = GETPORT(SSTAT0); 25711da177e4SLinus Torvalds if (s & TARGET) 2572ee7c7277SRasmus Villemoes seq_puts(m, "TARGET "); 25731da177e4SLinus Torvalds if (s & SELDO) 2574ee7c7277SRasmus Villemoes seq_puts(m, "SELDO "); 25751da177e4SLinus Torvalds if (s & SELDI) 2576ee7c7277SRasmus Villemoes seq_puts(m, "SELDI "); 25771da177e4SLinus Torvalds if (s & SELINGO) 2578ee7c7277SRasmus Villemoes seq_puts(m, "SELINGO "); 25791da177e4SLinus Torvalds if (s & SWRAP) 2580ee7c7277SRasmus Villemoes seq_puts(m, "SWRAP "); 25811da177e4SLinus Torvalds if (s & SDONE) 2582ee7c7277SRasmus Villemoes seq_puts(m, "SDONE "); 25831da177e4SLinus Torvalds if (s & SPIORDY) 2584ee7c7277SRasmus Villemoes seq_puts(m, "SPIORDY "); 25851da177e4SLinus Torvalds if (s & DMADONE) 2586ee7c7277SRasmus Villemoes seq_puts(m, "DMADONE "); 25871da177e4SLinus Torvalds 25881da177e4SLinus Torvalds s = GETPORT(SSTAT1); 25891da177e4SLinus Torvalds if (s & SELTO) 2590ee7c7277SRasmus Villemoes seq_puts(m, "SELTO "); 25911da177e4SLinus Torvalds if (s & ATNTARG) 2592ee7c7277SRasmus Villemoes seq_puts(m, "ATNTARG "); 25931da177e4SLinus Torvalds if (s & SCSIRSTI) 2594ee7c7277SRasmus Villemoes seq_puts(m, "SCSIRSTI "); 25951da177e4SLinus Torvalds if (s & PHASEMIS) 2596ee7c7277SRasmus Villemoes seq_puts(m, "PHASEMIS "); 25971da177e4SLinus Torvalds if (s & BUSFREE) 2598ee7c7277SRasmus Villemoes seq_puts(m, "BUSFREE "); 25991da177e4SLinus Torvalds if (s & SCSIPERR) 2600ee7c7277SRasmus Villemoes seq_puts(m, "SCSIPERR "); 26011da177e4SLinus Torvalds if (s & PHASECHG) 2602ee7c7277SRasmus Villemoes seq_puts(m, "PHASECHG "); 26031da177e4SLinus Torvalds if (s & REQINIT) 2604ee7c7277SRasmus Villemoes seq_puts(m, "REQINIT "); 2605ee7c7277SRasmus Villemoes seq_puts(m, "); "); 26061da177e4SLinus Torvalds 26071da177e4SLinus Torvalds 2608ee7c7277SRasmus Villemoes seq_puts(m, "SSTAT( "); 26091da177e4SLinus Torvalds 26101da177e4SLinus Torvalds s = GETPORT(SSTAT0) & GETPORT(SIMODE0); 26111da177e4SLinus Torvalds 26121da177e4SLinus Torvalds if (s & TARGET) 2613ee7c7277SRasmus Villemoes seq_puts(m, "TARGET "); 26141da177e4SLinus Torvalds if (s & SELDO) 2615ee7c7277SRasmus Villemoes seq_puts(m, "SELDO "); 26161da177e4SLinus Torvalds if (s & SELDI) 2617ee7c7277SRasmus Villemoes seq_puts(m, "SELDI "); 26181da177e4SLinus Torvalds if (s & SELINGO) 2619ee7c7277SRasmus Villemoes seq_puts(m, "SELINGO "); 26201da177e4SLinus Torvalds if (s & SWRAP) 2621ee7c7277SRasmus Villemoes seq_puts(m, "SWRAP "); 26221da177e4SLinus Torvalds if (s & SDONE) 2623ee7c7277SRasmus Villemoes seq_puts(m, "SDONE "); 26241da177e4SLinus Torvalds if (s & SPIORDY) 2625ee7c7277SRasmus Villemoes seq_puts(m, "SPIORDY "); 26261da177e4SLinus Torvalds if (s & DMADONE) 2627ee7c7277SRasmus Villemoes seq_puts(m, "DMADONE "); 26281da177e4SLinus Torvalds 26291da177e4SLinus Torvalds s = GETPORT(SSTAT1) & GETPORT(SIMODE1); 26301da177e4SLinus Torvalds 26311da177e4SLinus Torvalds if (s & SELTO) 2632ee7c7277SRasmus Villemoes seq_puts(m, "SELTO "); 26331da177e4SLinus Torvalds if (s & ATNTARG) 2634ee7c7277SRasmus Villemoes seq_puts(m, "ATNTARG "); 26351da177e4SLinus Torvalds if (s & SCSIRSTI) 2636ee7c7277SRasmus Villemoes seq_puts(m, "SCSIRSTI "); 26371da177e4SLinus Torvalds if (s & PHASEMIS) 2638ee7c7277SRasmus Villemoes seq_puts(m, "PHASEMIS "); 26391da177e4SLinus Torvalds if (s & BUSFREE) 2640ee7c7277SRasmus Villemoes seq_puts(m, "BUSFREE "); 26411da177e4SLinus Torvalds if (s & SCSIPERR) 2642ee7c7277SRasmus Villemoes seq_puts(m, "SCSIPERR "); 26431da177e4SLinus Torvalds if (s & PHASECHG) 2644ee7c7277SRasmus Villemoes seq_puts(m, "PHASECHG "); 26451da177e4SLinus Torvalds if (s & REQINIT) 2646ee7c7277SRasmus Villemoes seq_puts(m, "REQINIT "); 2647ee7c7277SRasmus Villemoes seq_puts(m, "); "); 26481da177e4SLinus Torvalds 2649ee7c7277SRasmus Villemoes seq_puts(m, "SXFRCTL0( "); 26501da177e4SLinus Torvalds 26511da177e4SLinus Torvalds s = GETPORT(SXFRCTL0); 26521da177e4SLinus Torvalds if (s & SCSIEN) 2653ee7c7277SRasmus Villemoes seq_puts(m, "SCSIEN "); 26541da177e4SLinus Torvalds if (s & DMAEN) 2655ee7c7277SRasmus Villemoes seq_puts(m, "DMAEN "); 26561da177e4SLinus Torvalds if (s & CH1) 2657ee7c7277SRasmus Villemoes seq_puts(m, "CH1 "); 26581da177e4SLinus Torvalds if (s & CLRSTCNT) 2659ee7c7277SRasmus Villemoes seq_puts(m, "CLRSTCNT "); 26601da177e4SLinus Torvalds if (s & SPIOEN) 2661ee7c7277SRasmus Villemoes seq_puts(m, "SPIOEN "); 26621da177e4SLinus Torvalds if (s & CLRCH1) 2663ee7c7277SRasmus Villemoes seq_puts(m, "CLRCH1 "); 2664ee7c7277SRasmus Villemoes seq_puts(m, "); "); 26651da177e4SLinus Torvalds 2666ee7c7277SRasmus Villemoes seq_puts(m, "SIGNAL( "); 26671da177e4SLinus Torvalds 26681da177e4SLinus Torvalds s = GETPORT(SCSISIG); 26691da177e4SLinus Torvalds if (s & SIG_ATNI) 2670ee7c7277SRasmus Villemoes seq_puts(m, "ATNI "); 26711da177e4SLinus Torvalds if (s & SIG_SELI) 2672ee7c7277SRasmus Villemoes seq_puts(m, "SELI "); 26731da177e4SLinus Torvalds if (s & SIG_BSYI) 2674ee7c7277SRasmus Villemoes seq_puts(m, "BSYI "); 26751da177e4SLinus Torvalds if (s & SIG_REQI) 2676ee7c7277SRasmus Villemoes seq_puts(m, "REQI "); 26771da177e4SLinus Torvalds if (s & SIG_ACKI) 2678ee7c7277SRasmus Villemoes seq_puts(m, "ACKI "); 2679ee7c7277SRasmus Villemoes seq_puts(m, "); "); 26801da177e4SLinus Torvalds 26810c3de38fSRasmus Villemoes seq_printf(m, "SELID(%02x), ", GETPORT(SELID)); 26821da177e4SLinus Torvalds 26830c3de38fSRasmus Villemoes seq_printf(m, "STCNT(%d), ", GETSTCNT()); 26841da177e4SLinus Torvalds 2685ee7c7277SRasmus Villemoes seq_puts(m, "SSTAT2( "); 26861da177e4SLinus Torvalds 26871da177e4SLinus Torvalds s = GETPORT(SSTAT2); 26881da177e4SLinus Torvalds if (s & SOFFSET) 2689ee7c7277SRasmus Villemoes seq_puts(m, "SOFFSET "); 26901da177e4SLinus Torvalds if (s & SEMPTY) 2691ee7c7277SRasmus Villemoes seq_puts(m, "SEMPTY "); 26921da177e4SLinus Torvalds if (s & SFULL) 2693ee7c7277SRasmus Villemoes seq_puts(m, "SFULL "); 26940c3de38fSRasmus Villemoes seq_printf(m, "); SFCNT (%d); ", s & (SFULL | SFCNT)); 26951da177e4SLinus Torvalds 26961da177e4SLinus Torvalds s = GETPORT(SSTAT3); 26970c3de38fSRasmus Villemoes seq_printf(m, "SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f); 26981da177e4SLinus Torvalds 2699ee7c7277SRasmus Villemoes seq_puts(m, "SSTAT4( "); 27001da177e4SLinus Torvalds s = GETPORT(SSTAT4); 27011da177e4SLinus Torvalds if (s & SYNCERR) 2702ee7c7277SRasmus Villemoes seq_puts(m, "SYNCERR "); 27031da177e4SLinus Torvalds if (s & FWERR) 2704ee7c7277SRasmus Villemoes seq_puts(m, "FWERR "); 27051da177e4SLinus Torvalds if (s & FRERR) 2706ee7c7277SRasmus Villemoes seq_puts(m, "FRERR "); 2707ee7c7277SRasmus Villemoes seq_puts(m, "); "); 27081da177e4SLinus Torvalds 2709ee7c7277SRasmus Villemoes seq_puts(m, "DMACNTRL0( "); 27101da177e4SLinus Torvalds s = GETPORT(DMACNTRL0); 27110c3de38fSRasmus Villemoes seq_printf(m, "%s ", s & _8BIT ? "8BIT" : "16BIT"); 27120c3de38fSRasmus Villemoes seq_printf(m, "%s ", s & DMA ? "DMA" : "PIO"); 27130c3de38fSRasmus Villemoes seq_printf(m, "%s ", s & WRITE_READ ? "WRITE" : "READ"); 27141da177e4SLinus Torvalds if (s & ENDMA) 2715ee7c7277SRasmus Villemoes seq_puts(m, "ENDMA "); 27161da177e4SLinus Torvalds if (s & INTEN) 2717ee7c7277SRasmus Villemoes seq_puts(m, "INTEN "); 27181da177e4SLinus Torvalds if (s & RSTFIFO) 2719ee7c7277SRasmus Villemoes seq_puts(m, "RSTFIFO "); 27201da177e4SLinus Torvalds if (s & SWINT) 2721ee7c7277SRasmus Villemoes seq_puts(m, "SWINT "); 2722ee7c7277SRasmus Villemoes seq_puts(m, "); "); 27231da177e4SLinus Torvalds 2724ee7c7277SRasmus Villemoes seq_puts(m, "DMASTAT( "); 27251da177e4SLinus Torvalds s = GETPORT(DMASTAT); 27261da177e4SLinus Torvalds if (s & ATDONE) 2727ee7c7277SRasmus Villemoes seq_puts(m, "ATDONE "); 27281da177e4SLinus Torvalds if (s & WORDRDY) 2729ee7c7277SRasmus Villemoes seq_puts(m, "WORDRDY "); 27301da177e4SLinus Torvalds if (s & DFIFOFULL) 2731ee7c7277SRasmus Villemoes seq_puts(m, "DFIFOFULL "); 27321da177e4SLinus Torvalds if (s & DFIFOEMP) 2733ee7c7277SRasmus Villemoes seq_puts(m, "DFIFOEMP "); 2734ee7c7277SRasmus Villemoes seq_puts(m, ")\n"); 27351da177e4SLinus Torvalds 2736ee7c7277SRasmus Villemoes seq_puts(m, "enabled interrupts( "); 27371da177e4SLinus Torvalds 27381da177e4SLinus Torvalds s = GETPORT(SIMODE0); 27391da177e4SLinus Torvalds if (s & ENSELDO) 2740ee7c7277SRasmus Villemoes seq_puts(m, "ENSELDO "); 27411da177e4SLinus Torvalds if (s & ENSELDI) 2742ee7c7277SRasmus Villemoes seq_puts(m, "ENSELDI "); 27431da177e4SLinus Torvalds if (s & ENSELINGO) 2744ee7c7277SRasmus Villemoes seq_puts(m, "ENSELINGO "); 27451da177e4SLinus Torvalds if (s & ENSWRAP) 2746ee7c7277SRasmus Villemoes seq_puts(m, "ENSWRAP "); 27471da177e4SLinus Torvalds if (s & ENSDONE) 2748ee7c7277SRasmus Villemoes seq_puts(m, "ENSDONE "); 27491da177e4SLinus Torvalds if (s & ENSPIORDY) 2750ee7c7277SRasmus Villemoes seq_puts(m, "ENSPIORDY "); 27511da177e4SLinus Torvalds if (s & ENDMADONE) 2752ee7c7277SRasmus Villemoes seq_puts(m, "ENDMADONE "); 27531da177e4SLinus Torvalds 27541da177e4SLinus Torvalds s = GETPORT(SIMODE1); 27551da177e4SLinus Torvalds if (s & ENSELTIMO) 2756ee7c7277SRasmus Villemoes seq_puts(m, "ENSELTIMO "); 27571da177e4SLinus Torvalds if (s & ENATNTARG) 2758ee7c7277SRasmus Villemoes seq_puts(m, "ENATNTARG "); 27591da177e4SLinus Torvalds if (s & ENPHASEMIS) 2760ee7c7277SRasmus Villemoes seq_puts(m, "ENPHASEMIS "); 27611da177e4SLinus Torvalds if (s & ENBUSFREE) 2762ee7c7277SRasmus Villemoes seq_puts(m, "ENBUSFREE "); 27631da177e4SLinus Torvalds if (s & ENSCSIPERR) 2764ee7c7277SRasmus Villemoes seq_puts(m, "ENSCSIPERR "); 27651da177e4SLinus Torvalds if (s & ENPHASECHG) 2766ee7c7277SRasmus Villemoes seq_puts(m, "ENPHASECHG "); 27671da177e4SLinus Torvalds if (s & ENREQINIT) 2768ee7c7277SRasmus Villemoes seq_puts(m, "ENREQINIT "); 2769ee7c7277SRasmus Villemoes seq_puts(m, ")\n"); 27701da177e4SLinus Torvalds } 27711da177e4SLinus Torvalds 2772275084cbSAl Viro static int aha152x_set_info(struct Scsi_Host *shpnt, char *buffer, int length) 27731da177e4SLinus Torvalds { 27741da177e4SLinus Torvalds if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0) 27751da177e4SLinus Torvalds return -EINVAL; 27761da177e4SLinus Torvalds 27771da177e4SLinus Torvalds #if defined(AHA152X_STAT) 27781da177e4SLinus Torvalds if(length>13 && strncmp("reset", buffer+8, 5)==0) { 27791da177e4SLinus Torvalds int i; 27801da177e4SLinus Torvalds 27811da177e4SLinus Torvalds HOSTDATA(shpnt)->total_commands=0; 27821da177e4SLinus Torvalds HOSTDATA(shpnt)->disconnections=0; 27831da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_any_action=0; 27841da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_old_command=0; 27851da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_new_command=0; 27861da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_done_command=0; 27871da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_with_check_condition=0; 27881da177e4SLinus Torvalds for (i = idle; i<maxstate; i++) { 27891da177e4SLinus Torvalds HOSTDATA(shpnt)->count[i]=0; 27901da177e4SLinus Torvalds HOSTDATA(shpnt)->count_trans[i]=0; 27911da177e4SLinus Torvalds HOSTDATA(shpnt)->time[i]=0; 27921da177e4SLinus Torvalds } 27931da177e4SLinus Torvalds 2794f75ae8edSHannes Reinecke shost_printk(KERN_INFO, shpnt, "aha152x: stats reset.\n"); 27951da177e4SLinus Torvalds 27961da177e4SLinus Torvalds } else 27971da177e4SLinus Torvalds #endif 27981da177e4SLinus Torvalds { 27991da177e4SLinus Torvalds return -EINVAL; 28001da177e4SLinus Torvalds } 28011da177e4SLinus Torvalds 28021da177e4SLinus Torvalds 28031da177e4SLinus Torvalds return length; 28041da177e4SLinus Torvalds } 28051da177e4SLinus Torvalds 2806275084cbSAl Viro static int aha152x_show_info(struct seq_file *m, struct Scsi_Host *shpnt) 28071da177e4SLinus Torvalds { 28081da177e4SLinus Torvalds int i; 280991ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr; 28101da177e4SLinus Torvalds unsigned long flags; 28111da177e4SLinus Torvalds 2812ee7c7277SRasmus Villemoes seq_puts(m, AHA152X_REVID "\n"); 28131da177e4SLinus Torvalds 28140c3de38fSRasmus Villemoes seq_printf(m, "ioports 0x%04lx to 0x%04lx\n", 28151da177e4SLinus Torvalds shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1); 28160c3de38fSRasmus Villemoes seq_printf(m, "interrupt 0x%02x\n", shpnt->irq); 28170c3de38fSRasmus Villemoes seq_printf(m, "disconnection/reconnection %s\n", 28181da177e4SLinus Torvalds RECONNECT ? "enabled" : "disabled"); 28190c3de38fSRasmus Villemoes seq_printf(m, "parity checking %s\n", 28201da177e4SLinus Torvalds PARITY ? "enabled" : "disabled"); 28210c3de38fSRasmus Villemoes seq_printf(m, "synchronous transfers %s\n", 28221da177e4SLinus Torvalds SYNCHRONOUS ? "enabled" : "disabled"); 28230c3de38fSRasmus Villemoes seq_printf(m, "%d commands currently queued\n", HOSTDATA(shpnt)->commands); 28241da177e4SLinus Torvalds 28251da177e4SLinus Torvalds if(SYNCHRONOUS) { 2826ee7c7277SRasmus Villemoes seq_puts(m, "synchronously operating targets (tick=50 ns):\n"); 28271da177e4SLinus Torvalds for (i = 0; i < 8; i++) 28281da177e4SLinus Torvalds if (HOSTDATA(shpnt)->syncrate[i] & 0x7f) 28290c3de38fSRasmus Villemoes seq_printf(m, "target %d: period %dT/%dns; req/ack offset %d\n", 28301da177e4SLinus Torvalds i, 28311da177e4SLinus Torvalds (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2), 28321da177e4SLinus Torvalds (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50, 28331da177e4SLinus Torvalds HOSTDATA(shpnt)->syncrate[i] & 0x0f); 28341da177e4SLinus Torvalds } 2835ee7c7277SRasmus Villemoes seq_puts(m, "\nqueue status:\n"); 28361da177e4SLinus Torvalds DO_LOCK(flags); 28371da177e4SLinus Torvalds if (ISSUE_SC) { 2838ee7c7277SRasmus Villemoes seq_puts(m, "not yet issued commands:\n"); 28391da177e4SLinus Torvalds for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr)) 2840275084cbSAl Viro get_command(m, ptr); 28411da177e4SLinus Torvalds } else 2842ee7c7277SRasmus Villemoes seq_puts(m, "no not yet issued commands\n"); 28431da177e4SLinus Torvalds DO_UNLOCK(flags); 28441da177e4SLinus Torvalds 28451da177e4SLinus Torvalds if (CURRENT_SC) { 2846ee7c7277SRasmus Villemoes seq_puts(m, "current command:\n"); 2847275084cbSAl Viro get_command(m, CURRENT_SC); 28481da177e4SLinus Torvalds } else 2849ee7c7277SRasmus Villemoes seq_puts(m, "no current command\n"); 28501da177e4SLinus Torvalds 28511da177e4SLinus Torvalds if (DISCONNECTED_SC) { 2852ee7c7277SRasmus Villemoes seq_puts(m, "disconnected commands:\n"); 28531da177e4SLinus Torvalds for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr)) 2854275084cbSAl Viro get_command(m, ptr); 28551da177e4SLinus Torvalds } else 2856ee7c7277SRasmus Villemoes seq_puts(m, "no disconnected commands\n"); 28571da177e4SLinus Torvalds 2858275084cbSAl Viro get_ports(m, shpnt); 28591da177e4SLinus Torvalds 28601da177e4SLinus Torvalds #if defined(AHA152X_STAT) 28610c3de38fSRasmus Villemoes seq_printf(m, "statistics:\n" 28621da177e4SLinus Torvalds "total commands: %d\n" 28631da177e4SLinus Torvalds "disconnections: %d\n" 28641da177e4SLinus Torvalds "busfree with check condition: %d\n" 28651da177e4SLinus Torvalds "busfree without old command: %d\n" 28661da177e4SLinus Torvalds "busfree without new command: %d\n" 28671da177e4SLinus Torvalds "busfree without done command: %d\n" 28681da177e4SLinus Torvalds "busfree without any action: %d\n" 28691da177e4SLinus Torvalds "state " 28701da177e4SLinus Torvalds "transitions " 28711da177e4SLinus Torvalds "count " 28721da177e4SLinus Torvalds "time\n", 28731da177e4SLinus Torvalds HOSTDATA(shpnt)->total_commands, 28741da177e4SLinus Torvalds HOSTDATA(shpnt)->disconnections, 28751da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_with_check_condition, 28761da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_old_command, 28771da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_new_command, 28781da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_done_command, 28791da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_any_action); 28801da177e4SLinus Torvalds for(i=0; i<maxstate; i++) { 28810c3de38fSRasmus Villemoes seq_printf(m, "%-10s %-12d %-12d %-12ld\n", 28821da177e4SLinus Torvalds states[i].name, 28831da177e4SLinus Torvalds HOSTDATA(shpnt)->count_trans[i], 28841da177e4SLinus Torvalds HOSTDATA(shpnt)->count[i], 28851da177e4SLinus Torvalds HOSTDATA(shpnt)->time[i]); 28861da177e4SLinus Torvalds } 28871da177e4SLinus Torvalds #endif 28881da177e4SLinus Torvalds return 0; 28891da177e4SLinus Torvalds } 28901da177e4SLinus Torvalds 2891b1ee0795SBoaz Harrosh static int aha152x_adjust_queue(struct scsi_device *device) 2892b1ee0795SBoaz Harrosh { 2893b1ee0795SBoaz Harrosh blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH); 2894b1ee0795SBoaz Harrosh return 0; 2895b1ee0795SBoaz Harrosh } 2896b1ee0795SBoaz Harrosh 2897d0be4a7dSChristoph Hellwig static struct scsi_host_template aha152x_driver_template = { 28981da177e4SLinus Torvalds .module = THIS_MODULE, 28991da177e4SLinus Torvalds .name = AHA152X_REVID, 29001da177e4SLinus Torvalds .proc_name = "aha152x", 2901275084cbSAl Viro .show_info = aha152x_show_info, 2902275084cbSAl Viro .write_info = aha152x_set_info, 29031da177e4SLinus Torvalds .queuecommand = aha152x_queue, 29041da177e4SLinus Torvalds .eh_abort_handler = aha152x_abort, 29051da177e4SLinus Torvalds .eh_device_reset_handler = aha152x_device_reset, 29061da177e4SLinus Torvalds .eh_bus_reset_handler = aha152x_bus_reset, 29071da177e4SLinus Torvalds .bios_param = aha152x_biosparam, 29081da177e4SLinus Torvalds .can_queue = 1, 29091da177e4SLinus Torvalds .this_id = 7, 29101da177e4SLinus Torvalds .sg_tablesize = SG_ALL, 29114af14d11SChristoph Hellwig .dma_boundary = PAGE_SIZE - 1, 2912b1ee0795SBoaz Harrosh .slave_alloc = aha152x_adjust_queue, 29131da177e4SLinus Torvalds }; 29141da177e4SLinus Torvalds 29153eb2ebcbSChristoph Hellwig #if !defined(AHA152X_PCMCIA) 29161da177e4SLinus Torvalds static int setup_count; 29171da177e4SLinus Torvalds static struct aha152x_setup setup[2]; 29181da177e4SLinus Torvalds 29191da177e4SLinus Torvalds /* possible i/o addresses for the AIC-6260; default first */ 29201da177e4SLinus Torvalds static unsigned short ports[] = { 0x340, 0x140 }; 29211da177e4SLinus Torvalds 29221da177e4SLinus Torvalds #if !defined(SKIP_BIOSTEST) 29231da177e4SLinus Torvalds /* possible locations for the Adaptec BIOS; defaults first */ 29241da177e4SLinus Torvalds static unsigned int addresses[] = 29251da177e4SLinus Torvalds { 29261da177e4SLinus Torvalds 0xdc000, /* default first */ 29271da177e4SLinus Torvalds 0xc8000, 29281da177e4SLinus Torvalds 0xcc000, 29291da177e4SLinus Torvalds 0xd0000, 29301da177e4SLinus Torvalds 0xd4000, 29311da177e4SLinus Torvalds 0xd8000, 29321da177e4SLinus Torvalds 0xe0000, 29331da177e4SLinus Torvalds 0xeb800, /* VTech Platinum SMP */ 29341da177e4SLinus Torvalds 0xf0000, 29351da177e4SLinus Torvalds }; 29361da177e4SLinus Torvalds 29371da177e4SLinus Torvalds /* signatures for various AIC-6[23]60 based controllers. 29381da177e4SLinus Torvalds The point in detecting signatures is to avoid useless and maybe 29391da177e4SLinus Torvalds harmful probes on ports. I'm not sure that all listed boards pass 29401da177e4SLinus Torvalds auto-configuration. For those which fail the BIOS signature is 29411da177e4SLinus Torvalds obsolete, because user intervention to supply the configuration is 29421da177e4SLinus Torvalds needed anyway. May be an information whether or not the BIOS supports 29431da177e4SLinus Torvalds extended translation could be also useful here. */ 29441da177e4SLinus Torvalds static struct signature { 29451da177e4SLinus Torvalds unsigned char *signature; 29461da177e4SLinus Torvalds int sig_offset; 29471da177e4SLinus Torvalds int sig_length; 29481da177e4SLinus Torvalds } signatures[] = 29491da177e4SLinus Torvalds { 29501da177e4SLinus Torvalds { "Adaptec AHA-1520 BIOS", 0x102e, 21 }, 29511da177e4SLinus Torvalds /* Adaptec 152x */ 29521da177e4SLinus Torvalds { "Adaptec AHA-1520B", 0x000b, 17 }, 29531da177e4SLinus Torvalds /* Adaptec 152x rev B */ 29541da177e4SLinus Torvalds { "Adaptec AHA-1520B", 0x0026, 17 }, 29551da177e4SLinus Torvalds /* Iomega Jaz Jet ISA (AIC6370Q) */ 29561da177e4SLinus Torvalds { "Adaptec ASW-B626 BIOS", 0x1029, 21 }, 29571da177e4SLinus Torvalds /* on-board controller */ 29581da177e4SLinus Torvalds { "Adaptec BIOS: ASW-B626", 0x000f, 22 }, 29591da177e4SLinus Torvalds /* on-board controller */ 29601da177e4SLinus Torvalds { "Adaptec ASW-B626 S2", 0x2e6c, 19 }, 29611da177e4SLinus Torvalds /* on-board controller */ 29621da177e4SLinus Torvalds { "Adaptec BIOS:AIC-6360", 0x000c, 21 }, 29631da177e4SLinus Torvalds /* on-board controller */ 29641da177e4SLinus Torvalds { "ScsiPro SP-360 BIOS", 0x2873, 19 }, 29651da177e4SLinus Torvalds /* ScsiPro-Controller */ 29661da177e4SLinus Torvalds { "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 }, 29671da177e4SLinus Torvalds /* Gigabyte Local-Bus-SCSI */ 29681da177e4SLinus Torvalds { "Adaptec BIOS:AVA-282X", 0x000c, 21 }, 29691da177e4SLinus Torvalds /* Adaptec 282x */ 29701da177e4SLinus Torvalds { "Adaptec IBM Dock II SCSI", 0x2edd, 24 }, 29711da177e4SLinus Torvalds /* IBM Thinkpad Dock II */ 29721da177e4SLinus Torvalds { "Adaptec BIOS:AHA-1532P", 0x001c, 22 }, 29731da177e4SLinus Torvalds /* IBM Thinkpad Dock II SCSI */ 29741da177e4SLinus Torvalds { "DTC3520A Host Adapter BIOS", 0x318a, 26 }, 29751da177e4SLinus Torvalds /* DTC 3520A ISA SCSI */ 29761da177e4SLinus Torvalds }; 29771da177e4SLinus Torvalds #endif /* !SKIP_BIOSTEST */ 29781da177e4SLinus Torvalds 29791da177e4SLinus Torvalds /* 29801da177e4SLinus Torvalds * Test, if port_base is valid. 29811da177e4SLinus Torvalds * 29821da177e4SLinus Torvalds */ 29831da177e4SLinus Torvalds static int aha152x_porttest(int io_port) 29841da177e4SLinus Torvalds { 29851da177e4SLinus Torvalds int i; 29861da177e4SLinus Torvalds 29871da177e4SLinus Torvalds SETPORT(io_port + O_DMACNTRL1, 0); /* reset stack pointer */ 29881da177e4SLinus Torvalds for (i = 0; i < 16; i++) 29891da177e4SLinus Torvalds SETPORT(io_port + O_STACK, i); 29901da177e4SLinus Torvalds 29911da177e4SLinus Torvalds SETPORT(io_port + O_DMACNTRL1, 0); /* reset stack pointer */ 29921da177e4SLinus Torvalds for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++) 29931da177e4SLinus Torvalds ; 29941da177e4SLinus Torvalds 29951da177e4SLinus Torvalds return (i == 16); 29961da177e4SLinus Torvalds } 29971da177e4SLinus Torvalds 29981da177e4SLinus Torvalds static int tc1550_porttest(int io_port) 29991da177e4SLinus Torvalds { 30001da177e4SLinus Torvalds int i; 30011da177e4SLinus Torvalds 30021da177e4SLinus Torvalds SETPORT(io_port + O_TC_DMACNTRL1, 0); /* reset stack pointer */ 30031da177e4SLinus Torvalds for (i = 0; i < 16; i++) 30041da177e4SLinus Torvalds SETPORT(io_port + O_STACK, i); 30051da177e4SLinus Torvalds 30061da177e4SLinus Torvalds SETPORT(io_port + O_TC_DMACNTRL1, 0); /* reset stack pointer */ 30071da177e4SLinus Torvalds for (i = 0; i < 16 && GETPORT(io_port + O_TC_STACK) == i; i++) 30081da177e4SLinus Torvalds ; 30091da177e4SLinus Torvalds 30101da177e4SLinus Torvalds return (i == 16); 30111da177e4SLinus Torvalds } 30121da177e4SLinus Torvalds 30131da177e4SLinus Torvalds 30141da177e4SLinus Torvalds static int checksetup(struct aha152x_setup *setup) 30151da177e4SLinus Torvalds { 30161da177e4SLinus Torvalds int i; 30171da177e4SLinus Torvalds for (i = 0; i < ARRAY_SIZE(ports) && (setup->io_port != ports[i]); i++) 30181da177e4SLinus Torvalds ; 30191da177e4SLinus Torvalds 30201da177e4SLinus Torvalds if (i == ARRAY_SIZE(ports)) 30211da177e4SLinus Torvalds return 0; 30221da177e4SLinus Torvalds 30239bcf0910SHarvey Harrison if (!request_region(setup->io_port, IO_RANGE, "aha152x")) { 30241da177e4SLinus Torvalds printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup->io_port); 30251da177e4SLinus Torvalds return 0; 30261da177e4SLinus Torvalds } 30271da177e4SLinus Torvalds 30281da177e4SLinus Torvalds if( aha152x_porttest(setup->io_port) ) { 30291da177e4SLinus Torvalds setup->tc1550=0; 30301da177e4SLinus Torvalds } else if( tc1550_porttest(setup->io_port) ) { 30311da177e4SLinus Torvalds setup->tc1550=1; 30321da177e4SLinus Torvalds } else { 30331da177e4SLinus Torvalds release_region(setup->io_port, IO_RANGE); 30341da177e4SLinus Torvalds return 0; 30351da177e4SLinus Torvalds } 30361da177e4SLinus Torvalds 30371da177e4SLinus Torvalds release_region(setup->io_port, IO_RANGE); 30381da177e4SLinus Torvalds 30391da177e4SLinus Torvalds if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX)) 30401da177e4SLinus Torvalds return 0; 30411da177e4SLinus Torvalds 30421da177e4SLinus Torvalds if ((setup->scsiid < 0) || (setup->scsiid > 7)) 30431da177e4SLinus Torvalds return 0; 30441da177e4SLinus Torvalds 30451da177e4SLinus Torvalds if ((setup->reconnect < 0) || (setup->reconnect > 1)) 30461da177e4SLinus Torvalds return 0; 30471da177e4SLinus Torvalds 30481da177e4SLinus Torvalds if ((setup->parity < 0) || (setup->parity > 1)) 30491da177e4SLinus Torvalds return 0; 30501da177e4SLinus Torvalds 30511da177e4SLinus Torvalds if ((setup->synchronous < 0) || (setup->synchronous > 1)) 30521da177e4SLinus Torvalds return 0; 30531da177e4SLinus Torvalds 30541da177e4SLinus Torvalds if ((setup->ext_trans < 0) || (setup->ext_trans > 1)) 30551da177e4SLinus Torvalds return 0; 30561da177e4SLinus Torvalds 30571da177e4SLinus Torvalds 30581da177e4SLinus Torvalds return 1; 30591da177e4SLinus Torvalds } 30601da177e4SLinus Torvalds 30611da177e4SLinus Torvalds 30621da177e4SLinus Torvalds static int __init aha152x_init(void) 30631da177e4SLinus Torvalds { 30641da177e4SLinus Torvalds int i, j, ok; 30651da177e4SLinus Torvalds #if defined(AUTOCONF) 30661da177e4SLinus Torvalds aha152x_config conf; 30671da177e4SLinus Torvalds #endif 30681da177e4SLinus Torvalds #ifdef __ISAPNP__ 30691da177e4SLinus Torvalds struct pnp_dev *dev=NULL, *pnpdev[2] = {NULL, NULL}; 30701da177e4SLinus Torvalds #endif 30711da177e4SLinus Torvalds 30721da177e4SLinus Torvalds if ( setup_count ) { 30731da177e4SLinus Torvalds printk(KERN_INFO "aha152x: processing commandline: "); 30741da177e4SLinus Torvalds 30751da177e4SLinus Torvalds for (i = 0; i<setup_count; i++) { 30761da177e4SLinus Torvalds if (!checksetup(&setup[i])) { 30771da177e4SLinus Torvalds printk(KERN_ERR "\naha152x: %s\n", setup[i].conf); 30781da177e4SLinus Torvalds printk(KERN_ERR "aha152x: invalid line\n"); 30791da177e4SLinus Torvalds } 30801da177e4SLinus Torvalds } 30811da177e4SLinus Torvalds printk("ok\n"); 30821da177e4SLinus Torvalds } 30831da177e4SLinus Torvalds 30841da177e4SLinus Torvalds #if defined(SETUP0) 30851da177e4SLinus Torvalds if (setup_count < ARRAY_SIZE(setup)) { 30861da177e4SLinus Torvalds struct aha152x_setup override = SETUP0; 30871da177e4SLinus Torvalds 30881da177e4SLinus Torvalds if (setup_count == 0 || (override.io_port != setup[0].io_port)) { 30891da177e4SLinus Torvalds if (!checksetup(&override)) { 30901da177e4SLinus Torvalds printk(KERN_ERR "\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", 30911da177e4SLinus Torvalds override.io_port, 30921da177e4SLinus Torvalds override.irq, 30931da177e4SLinus Torvalds override.scsiid, 30941da177e4SLinus Torvalds override.reconnect, 30951da177e4SLinus Torvalds override.parity, 30961da177e4SLinus Torvalds override.synchronous, 30971da177e4SLinus Torvalds override.delay, 30981da177e4SLinus Torvalds override.ext_trans); 30991da177e4SLinus Torvalds } else 31001da177e4SLinus Torvalds setup[setup_count++] = override; 31011da177e4SLinus Torvalds } 31021da177e4SLinus Torvalds } 31031da177e4SLinus Torvalds #endif 31041da177e4SLinus Torvalds 31051da177e4SLinus Torvalds #if defined(SETUP1) 31061da177e4SLinus Torvalds if (setup_count < ARRAY_SIZE(setup)) { 31071da177e4SLinus Torvalds struct aha152x_setup override = SETUP1; 31081da177e4SLinus Torvalds 31091da177e4SLinus Torvalds if (setup_count == 0 || (override.io_port != setup[0].io_port)) { 31101da177e4SLinus Torvalds if (!checksetup(&override)) { 31111da177e4SLinus Torvalds printk(KERN_ERR "\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", 31121da177e4SLinus Torvalds override.io_port, 31131da177e4SLinus Torvalds override.irq, 31141da177e4SLinus Torvalds override.scsiid, 31151da177e4SLinus Torvalds override.reconnect, 31161da177e4SLinus Torvalds override.parity, 31171da177e4SLinus Torvalds override.synchronous, 31181da177e4SLinus Torvalds override.delay, 31191da177e4SLinus Torvalds override.ext_trans); 31201da177e4SLinus Torvalds } else 31211da177e4SLinus Torvalds setup[setup_count++] = override; 31221da177e4SLinus Torvalds } 31231da177e4SLinus Torvalds } 31241da177e4SLinus Torvalds #endif 31251da177e4SLinus Torvalds 31261da177e4SLinus Torvalds #if defined(MODULE) 31271da177e4SLinus Torvalds if (setup_count<ARRAY_SIZE(setup) && (aha152x[0]!=0 || io[0]!=0 || irq[0]!=0)) { 31281da177e4SLinus Torvalds if(aha152x[0]!=0) { 31291da177e4SLinus Torvalds setup[setup_count].conf = ""; 31301da177e4SLinus Torvalds setup[setup_count].io_port = aha152x[0]; 31311da177e4SLinus Torvalds setup[setup_count].irq = aha152x[1]; 31321da177e4SLinus Torvalds setup[setup_count].scsiid = aha152x[2]; 31331da177e4SLinus Torvalds setup[setup_count].reconnect = aha152x[3]; 31341da177e4SLinus Torvalds setup[setup_count].parity = aha152x[4]; 31351da177e4SLinus Torvalds setup[setup_count].synchronous = aha152x[5]; 31361da177e4SLinus Torvalds setup[setup_count].delay = aha152x[6]; 31371da177e4SLinus Torvalds setup[setup_count].ext_trans = aha152x[7]; 31381da177e4SLinus Torvalds } else if (io[0] != 0 || irq[0] != 0) { 31391da177e4SLinus Torvalds if(io[0]!=0) setup[setup_count].io_port = io[0]; 31401da177e4SLinus Torvalds if(irq[0]!=0) setup[setup_count].irq = irq[0]; 31411da177e4SLinus Torvalds 31421da177e4SLinus Torvalds setup[setup_count].scsiid = scsiid[0]; 31431da177e4SLinus Torvalds setup[setup_count].reconnect = reconnect[0]; 31441da177e4SLinus Torvalds setup[setup_count].parity = parity[0]; 31451da177e4SLinus Torvalds setup[setup_count].synchronous = sync[0]; 31461da177e4SLinus Torvalds setup[setup_count].delay = delay[0]; 31471da177e4SLinus Torvalds setup[setup_count].ext_trans = exttrans[0]; 31481da177e4SLinus Torvalds } 31491da177e4SLinus Torvalds 31501da177e4SLinus Torvalds if (checksetup(&setup[setup_count])) 31511da177e4SLinus Torvalds setup_count++; 31521da177e4SLinus Torvalds else 31531da177e4SLinus Torvalds printk(KERN_ERR "aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d\n", 31541da177e4SLinus Torvalds setup[setup_count].io_port, 31551da177e4SLinus Torvalds setup[setup_count].irq, 31561da177e4SLinus Torvalds setup[setup_count].scsiid, 31571da177e4SLinus Torvalds setup[setup_count].reconnect, 31581da177e4SLinus Torvalds setup[setup_count].parity, 31591da177e4SLinus Torvalds setup[setup_count].synchronous, 31601da177e4SLinus Torvalds setup[setup_count].delay, 31611da177e4SLinus Torvalds setup[setup_count].ext_trans); 31621da177e4SLinus Torvalds } 31631da177e4SLinus Torvalds 31641da177e4SLinus Torvalds if (setup_count<ARRAY_SIZE(setup) && (aha152x1[0]!=0 || io[1]!=0 || irq[1]!=0)) { 31651da177e4SLinus Torvalds if(aha152x1[0]!=0) { 31661da177e4SLinus Torvalds setup[setup_count].conf = ""; 31671da177e4SLinus Torvalds setup[setup_count].io_port = aha152x1[0]; 31681da177e4SLinus Torvalds setup[setup_count].irq = aha152x1[1]; 31691da177e4SLinus Torvalds setup[setup_count].scsiid = aha152x1[2]; 31701da177e4SLinus Torvalds setup[setup_count].reconnect = aha152x1[3]; 31711da177e4SLinus Torvalds setup[setup_count].parity = aha152x1[4]; 31721da177e4SLinus Torvalds setup[setup_count].synchronous = aha152x1[5]; 31731da177e4SLinus Torvalds setup[setup_count].delay = aha152x1[6]; 31741da177e4SLinus Torvalds setup[setup_count].ext_trans = aha152x1[7]; 31751da177e4SLinus Torvalds } else if (io[1] != 0 || irq[1] != 0) { 31761da177e4SLinus Torvalds if(io[1]!=0) setup[setup_count].io_port = io[1]; 31771da177e4SLinus Torvalds if(irq[1]!=0) setup[setup_count].irq = irq[1]; 31781da177e4SLinus Torvalds 31791da177e4SLinus Torvalds setup[setup_count].scsiid = scsiid[1]; 31801da177e4SLinus Torvalds setup[setup_count].reconnect = reconnect[1]; 31811da177e4SLinus Torvalds setup[setup_count].parity = parity[1]; 31821da177e4SLinus Torvalds setup[setup_count].synchronous = sync[1]; 31831da177e4SLinus Torvalds setup[setup_count].delay = delay[1]; 31841da177e4SLinus Torvalds setup[setup_count].ext_trans = exttrans[1]; 31851da177e4SLinus Torvalds } 31861da177e4SLinus Torvalds if (checksetup(&setup[setup_count])) 31871da177e4SLinus Torvalds setup_count++; 31881da177e4SLinus Torvalds else 31891da177e4SLinus Torvalds printk(KERN_ERR "aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d\n", 31901da177e4SLinus Torvalds setup[setup_count].io_port, 31911da177e4SLinus Torvalds setup[setup_count].irq, 31921da177e4SLinus Torvalds setup[setup_count].scsiid, 31931da177e4SLinus Torvalds setup[setup_count].reconnect, 31941da177e4SLinus Torvalds setup[setup_count].parity, 31951da177e4SLinus Torvalds setup[setup_count].synchronous, 31961da177e4SLinus Torvalds setup[setup_count].delay, 31971da177e4SLinus Torvalds setup[setup_count].ext_trans); 31981da177e4SLinus Torvalds } 31991da177e4SLinus Torvalds #endif 32001da177e4SLinus Torvalds 32011da177e4SLinus Torvalds #ifdef __ISAPNP__ 32021da177e4SLinus Torvalds for(i=0; setup_count<ARRAY_SIZE(setup) && id_table[i].vendor; i++) { 32031da177e4SLinus Torvalds while ( setup_count<ARRAY_SIZE(setup) && 32041da177e4SLinus Torvalds (dev=pnp_find_dev(NULL, id_table[i].vendor, id_table[i].function, dev)) ) { 32051da177e4SLinus Torvalds if (pnp_device_attach(dev) < 0) 32061da177e4SLinus Torvalds continue; 32071da177e4SLinus Torvalds 32081da177e4SLinus Torvalds if (pnp_activate_dev(dev) < 0) { 32091da177e4SLinus Torvalds pnp_device_detach(dev); 32101da177e4SLinus Torvalds continue; 32111da177e4SLinus Torvalds } 32121da177e4SLinus Torvalds 32131da177e4SLinus Torvalds if (!pnp_port_valid(dev, 0)) { 32141da177e4SLinus Torvalds pnp_device_detach(dev); 32151da177e4SLinus Torvalds continue; 32161da177e4SLinus Torvalds } 32171da177e4SLinus Torvalds 32181da177e4SLinus Torvalds if (setup_count==1 && pnp_port_start(dev, 0)==setup[0].io_port) { 32191da177e4SLinus Torvalds pnp_device_detach(dev); 32201da177e4SLinus Torvalds continue; 32211da177e4SLinus Torvalds } 32221da177e4SLinus Torvalds 32231da177e4SLinus Torvalds setup[setup_count].io_port = pnp_port_start(dev, 0); 32241da177e4SLinus Torvalds setup[setup_count].irq = pnp_irq(dev, 0); 32251da177e4SLinus Torvalds setup[setup_count].scsiid = 7; 32261da177e4SLinus Torvalds setup[setup_count].reconnect = 1; 32271da177e4SLinus Torvalds setup[setup_count].parity = 1; 32281da177e4SLinus Torvalds setup[setup_count].synchronous = 1; 32291da177e4SLinus Torvalds setup[setup_count].delay = DELAY_DEFAULT; 32301da177e4SLinus Torvalds setup[setup_count].ext_trans = 0; 32311da177e4SLinus Torvalds #if defined(__ISAPNP__) 32321da177e4SLinus Torvalds pnpdev[setup_count] = dev; 32331da177e4SLinus Torvalds #endif 32341da177e4SLinus Torvalds printk (KERN_INFO 32351da177e4SLinus Torvalds "aha152x: found ISAPnP adapter at io=0x%03x, irq=%d\n", 32361da177e4SLinus Torvalds setup[setup_count].io_port, setup[setup_count].irq); 32371da177e4SLinus Torvalds setup_count++; 32381da177e4SLinus Torvalds } 32391da177e4SLinus Torvalds } 32401da177e4SLinus Torvalds #endif 32411da177e4SLinus Torvalds 32421da177e4SLinus Torvalds #if defined(AUTOCONF) 32431da177e4SLinus Torvalds if (setup_count<ARRAY_SIZE(setup)) { 32441da177e4SLinus Torvalds #if !defined(SKIP_BIOSTEST) 32451da177e4SLinus Torvalds ok = 0; 32461da177e4SLinus Torvalds for (i = 0; i < ARRAY_SIZE(addresses) && !ok; i++) { 32471da177e4SLinus Torvalds void __iomem *p = ioremap(addresses[i], 0x4000); 32481da177e4SLinus Torvalds if (!p) 32491da177e4SLinus Torvalds continue; 32501da177e4SLinus Torvalds for (j = 0; j<ARRAY_SIZE(signatures) && !ok; j++) 32511da177e4SLinus Torvalds ok = check_signature(p + signatures[j].sig_offset, 32521da177e4SLinus Torvalds signatures[j].signature, signatures[j].sig_length); 32531da177e4SLinus Torvalds iounmap(p); 32541da177e4SLinus Torvalds } 32551da177e4SLinus Torvalds if (!ok && setup_count == 0) 3256ad2fa42dSJames Bottomley return -ENODEV; 32571da177e4SLinus Torvalds 32581da177e4SLinus Torvalds printk(KERN_INFO "aha152x: BIOS test: passed, "); 32591da177e4SLinus Torvalds #else 32601da177e4SLinus Torvalds printk(KERN_INFO "aha152x: "); 32611da177e4SLinus Torvalds #endif /* !SKIP_BIOSTEST */ 32621da177e4SLinus Torvalds 32631da177e4SLinus Torvalds ok = 0; 32641da177e4SLinus Torvalds for (i = 0; i < ARRAY_SIZE(ports) && setup_count < 2; i++) { 32651da177e4SLinus Torvalds if ((setup_count == 1) && (setup[0].io_port == ports[i])) 32661da177e4SLinus Torvalds continue; 32671da177e4SLinus Torvalds 32689bcf0910SHarvey Harrison if (!request_region(ports[i], IO_RANGE, "aha152x")) { 32691da177e4SLinus Torvalds printk(KERN_ERR "aha152x: io port 0x%x busy.\n", ports[i]); 32701da177e4SLinus Torvalds continue; 32711da177e4SLinus Torvalds } 32721da177e4SLinus Torvalds 32731da177e4SLinus Torvalds if (aha152x_porttest(ports[i])) { 32741da177e4SLinus Torvalds setup[setup_count].tc1550 = 0; 32751da177e4SLinus Torvalds 32761da177e4SLinus Torvalds conf.cf_port = 32771da177e4SLinus Torvalds (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB); 32781da177e4SLinus Torvalds } else if (tc1550_porttest(ports[i])) { 32791da177e4SLinus Torvalds setup[setup_count].tc1550 = 1; 32801da177e4SLinus Torvalds 32811da177e4SLinus Torvalds conf.cf_port = 32821da177e4SLinus Torvalds (GETPORT(ports[i] + O_TC_PORTA) << 8) + GETPORT(ports[i] + O_TC_PORTB); 32831da177e4SLinus Torvalds } else { 32841da177e4SLinus Torvalds release_region(ports[i], IO_RANGE); 32851da177e4SLinus Torvalds continue; 32861da177e4SLinus Torvalds } 32871da177e4SLinus Torvalds 32881da177e4SLinus Torvalds release_region(ports[i], IO_RANGE); 32891da177e4SLinus Torvalds 32901da177e4SLinus Torvalds ok++; 32911da177e4SLinus Torvalds setup[setup_count].io_port = ports[i]; 32921da177e4SLinus Torvalds setup[setup_count].irq = IRQ_MIN + conf.cf_irq; 32931da177e4SLinus Torvalds setup[setup_count].scsiid = conf.cf_id; 32941da177e4SLinus Torvalds setup[setup_count].reconnect = conf.cf_tardisc; 32951da177e4SLinus Torvalds setup[setup_count].parity = !conf.cf_parity; 32961da177e4SLinus Torvalds setup[setup_count].synchronous = conf.cf_syncneg; 32971da177e4SLinus Torvalds setup[setup_count].delay = DELAY_DEFAULT; 32981da177e4SLinus Torvalds setup[setup_count].ext_trans = 0; 32991da177e4SLinus Torvalds setup_count++; 33001da177e4SLinus Torvalds 33011da177e4SLinus Torvalds } 33021da177e4SLinus Torvalds 33031da177e4SLinus Torvalds if (ok) 33041da177e4SLinus Torvalds printk("auto configuration: ok, "); 33051da177e4SLinus Torvalds } 33061da177e4SLinus Torvalds #endif 33071da177e4SLinus Torvalds 33081da177e4SLinus Torvalds printk("%d controller(s) configured\n", setup_count); 33091da177e4SLinus Torvalds 33101da177e4SLinus Torvalds for (i=0; i<setup_count; i++) { 33111da177e4SLinus Torvalds if ( request_region(setup[i].io_port, IO_RANGE, "aha152x") ) { 33121da177e4SLinus Torvalds struct Scsi_Host *shpnt = aha152x_probe_one(&setup[i]); 33131da177e4SLinus Torvalds 33141da177e4SLinus Torvalds if( !shpnt ) { 33151da177e4SLinus Torvalds release_region(setup[i].io_port, IO_RANGE); 33161da177e4SLinus Torvalds #if defined(__ISAPNP__) 33171da177e4SLinus Torvalds } else if( pnpdev[i] ) { 33181da177e4SLinus Torvalds HOSTDATA(shpnt)->pnpdev=pnpdev[i]; 33191da177e4SLinus Torvalds pnpdev[i]=NULL; 33201da177e4SLinus Torvalds #endif 33211da177e4SLinus Torvalds } 33221da177e4SLinus Torvalds } else { 33231da177e4SLinus Torvalds printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup[i].io_port); 33241da177e4SLinus Torvalds } 33251da177e4SLinus Torvalds 33261da177e4SLinus Torvalds #if defined(__ISAPNP__) 33271da177e4SLinus Torvalds if( pnpdev[i] ) 33281da177e4SLinus Torvalds pnp_device_detach(pnpdev[i]); 33291da177e4SLinus Torvalds #endif 33301da177e4SLinus Torvalds } 33311da177e4SLinus Torvalds 3332ad2fa42dSJames Bottomley return 0; 33331da177e4SLinus Torvalds } 33341da177e4SLinus Torvalds 33351da177e4SLinus Torvalds static void __exit aha152x_exit(void) 33361da177e4SLinus Torvalds { 333764976a03SJames Bottomley struct aha152x_hostdata *hd, *tmp; 33381da177e4SLinus Torvalds 333964976a03SJames Bottomley list_for_each_entry_safe(hd, tmp, &aha152x_host_list, host_list) { 33405fcda422SJames Bottomley struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata); 33415fcda422SJames Bottomley 33425fcda422SJames Bottomley aha152x_release(shost); 33431da177e4SLinus Torvalds } 33441da177e4SLinus Torvalds } 33451da177e4SLinus Torvalds 33461da177e4SLinus Torvalds module_init(aha152x_init); 33471da177e4SLinus Torvalds module_exit(aha152x_exit); 33481da177e4SLinus Torvalds 33491da177e4SLinus Torvalds #if !defined(MODULE) 33501da177e4SLinus Torvalds static int __init aha152x_setup(char *str) 33511da177e4SLinus Torvalds { 33521da177e4SLinus Torvalds int ints[10]; 3353f75ae8edSHannes Reinecke 33541da177e4SLinus Torvalds get_options(str, ARRAY_SIZE(ints), ints); 33551da177e4SLinus Torvalds 33561da177e4SLinus Torvalds if(setup_count>=ARRAY_SIZE(setup)) { 33571da177e4SLinus Torvalds printk(KERN_ERR "aha152x: you can only configure up to two controllers\n"); 33581da177e4SLinus Torvalds return 1; 33591da177e4SLinus Torvalds } 33601da177e4SLinus Torvalds 33611da177e4SLinus Torvalds setup[setup_count].conf = str; 33621da177e4SLinus Torvalds setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340; 33631da177e4SLinus Torvalds setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11; 33641da177e4SLinus Torvalds setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7; 33651da177e4SLinus Torvalds setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1; 33661da177e4SLinus Torvalds setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1; 33671da177e4SLinus Torvalds setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 1; 33681da177e4SLinus Torvalds setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT; 33691da177e4SLinus Torvalds setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0; 33701da177e4SLinus Torvalds if (ints[0] > 8) { /*}*/ 33711da177e4SLinus Torvalds printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>" 33721da177e4SLinus Torvalds "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n"); 33731da177e4SLinus Torvalds } else { 33741da177e4SLinus Torvalds setup_count++; 33751da177e4SLinus Torvalds return 0; 33761da177e4SLinus Torvalds } 33771da177e4SLinus Torvalds 33781da177e4SLinus Torvalds return 1; 33791da177e4SLinus Torvalds } 33801da177e4SLinus Torvalds __setup("aha152x=", aha152x_setup); 33811da177e4SLinus Torvalds #endif 33821da177e4SLinus Torvalds 33833eb2ebcbSChristoph Hellwig #endif /* !AHA152X_PCMCIA */ 3384