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
24753555fb7SBart Van Assche #include <scsi/scsi.h>
24853555fb7SBart Van Assche #include <scsi/scsi_cmnd.h>
249db9dff36S #include <scsi/scsi_dbg.h>
25053555fb7SBart Van Assche #include <scsi/scsi_device.h>
25173d2cb16SBoaz Harrosh #include <scsi/scsi_eh.h>
25253555fb7SBart Van Assche #include <scsi/scsi_host.h>
25353555fb7SBart Van Assche #include <scsi/scsi_tcq.h>
25453555fb7SBart Van Assche #include <scsi/scsi_transport_spi.h>
25553555fb7SBart Van Assche #include <scsi/scsicam.h>
2561da177e4SLinus Torvalds #include "aha152x.h"
2571da177e4SLinus Torvalds
2585fcda422SJames Bottomley static LIST_HEAD(aha152x_host_list);
2595fcda422SJames Bottomley
2601da177e4SLinus Torvalds
2611da177e4SLinus Torvalds /* DEFINES */
2621da177e4SLinus Torvalds
2631da177e4SLinus Torvalds /* For PCMCIA cards, always use AUTOCONF */
2643eb2ebcbSChristoph Hellwig #if defined(AHA152X_PCMCIA) || defined(MODULE)
2651da177e4SLinus Torvalds #if !defined(AUTOCONF)
2661da177e4SLinus Torvalds #define AUTOCONF
2671da177e4SLinus Torvalds #endif
2681da177e4SLinus Torvalds #endif
2691da177e4SLinus Torvalds
2701da177e4SLinus Torvalds #if !defined(AUTOCONF) && !defined(SETUP0)
2711da177e4SLinus Torvalds #error define AUTOCONF or SETUP0
2721da177e4SLinus Torvalds #endif
2731da177e4SLinus Torvalds
2741da177e4SLinus Torvalds #define DO_LOCK(flags) spin_lock_irqsave(&QLOCK,flags)
2751da177e4SLinus Torvalds #define DO_UNLOCK(flags) spin_unlock_irqrestore(&QLOCK,flags)
2761da177e4SLinus Torvalds
2771da177e4SLinus Torvalds #define LEAD "(scsi%d:%d:%d) "
2781da177e4SLinus Torvalds #define INFO_LEAD KERN_INFO LEAD
2791da177e4SLinus Torvalds #define CMDINFO(cmd) \
2801da177e4SLinus Torvalds (cmd) ? ((cmd)->device->host->host_no) : -1, \
2811da177e4SLinus Torvalds (cmd) ? ((cmd)->device->id & 0x0f) : -1, \
2829cb78c16SHannes Reinecke (cmd) ? ((u8)(cmd)->device->lun & 0x07) : -1
2831da177e4SLinus Torvalds
2842338545aSBoaz Harrosh static inline void
CMD_INC_RESID(struct scsi_cmnd * cmd,int inc)2852338545aSBoaz Harrosh CMD_INC_RESID(struct scsi_cmnd *cmd, int inc)
2862338545aSBoaz Harrosh {
2872338545aSBoaz Harrosh scsi_set_resid(cmd, scsi_get_resid(cmd) + inc);
2882338545aSBoaz Harrosh }
2892338545aSBoaz Harrosh
2901da177e4SLinus Torvalds #define DELAY_DEFAULT 1000
2911da177e4SLinus Torvalds
2923eb2ebcbSChristoph Hellwig #if defined(AHA152X_PCMCIA)
2931da177e4SLinus Torvalds #define IRQ_MIN 0
2941da177e4SLinus Torvalds #define IRQ_MAX 16
2951da177e4SLinus Torvalds #else
2961da177e4SLinus Torvalds #define IRQ_MIN 9
2971da177e4SLinus Torvalds #if defined(__PPC)
298171ac6aeSYinghai Lu #define IRQ_MAX (nr_irqs-1)
2991da177e4SLinus Torvalds #else
3001da177e4SLinus Torvalds #define IRQ_MAX 12
3011da177e4SLinus Torvalds #endif
3021da177e4SLinus Torvalds #endif
3031da177e4SLinus Torvalds
3041da177e4SLinus Torvalds enum {
3051da177e4SLinus Torvalds not_issued = 0x0001, /* command not yet issued */
306f75ae8edSHannes Reinecke selecting = 0x0002, /* target is being selected */
3071da177e4SLinus Torvalds identified = 0x0004, /* IDENTIFY was sent */
3081da177e4SLinus Torvalds disconnected = 0x0008, /* target disconnected */
3091da177e4SLinus Torvalds completed = 0x0010, /* target sent COMMAND COMPLETE */
3101da177e4SLinus Torvalds aborted = 0x0020, /* ABORT was sent */
3111da177e4SLinus Torvalds resetted = 0x0040, /* BUS DEVICE RESET was sent */
3121da177e4SLinus Torvalds spiordy = 0x0080, /* waiting for SPIORDY to raise */
3131da177e4SLinus Torvalds syncneg = 0x0100, /* synchronous negotiation in progress */
3141da177e4SLinus Torvalds aborting = 0x0200, /* ABORT is pending */
3151da177e4SLinus Torvalds resetting = 0x0400, /* BUS DEVICE RESET is pending */
3161da177e4SLinus Torvalds check_condition = 0x0800, /* requesting sense after CHECK CONDITION */
3171da177e4SLinus Torvalds };
3181da177e4SLinus Torvalds
3193ac6aba3SBart Van Assche struct aha152x_cmd_priv {
32063221571SFinn Thain char *ptr;
32163221571SFinn Thain int this_residual;
32263221571SFinn Thain struct scatterlist *buffer;
32363221571SFinn Thain int status;
32463221571SFinn Thain int message;
32563221571SFinn Thain int sent_command;
32663221571SFinn Thain int phase;
3273ac6aba3SBart Van Assche };
3283ac6aba3SBart Van Assche
aha152x_priv(struct scsi_cmnd * cmd)32963221571SFinn Thain static struct aha152x_cmd_priv *aha152x_priv(struct scsi_cmnd *cmd)
3303ac6aba3SBart Van Assche {
33163221571SFinn Thain return scsi_cmd_priv(cmd);
3323ac6aba3SBart Van Assche }
3333ac6aba3SBart Van Assche
33496de0e25SJan Engelhardt MODULE_AUTHOR("Jürgen Fischer");
3351da177e4SLinus Torvalds MODULE_DESCRIPTION(AHA152X_REVID);
3361da177e4SLinus Torvalds MODULE_LICENSE("GPL");
3371da177e4SLinus Torvalds
3383eb2ebcbSChristoph Hellwig #if !defined(AHA152X_PCMCIA)
3391da177e4SLinus Torvalds #if defined(MODULE)
3401da177e4SLinus Torvalds static int io[] = {0, 0};
34188f06b76SDavid Howells module_param_hw_array(io, int, ioport, NULL, 0);
3421da177e4SLinus Torvalds MODULE_PARM_DESC(io,"base io address of controller");
3431da177e4SLinus Torvalds
3441da177e4SLinus Torvalds static int irq[] = {0, 0};
34588f06b76SDavid Howells module_param_hw_array(irq, int, irq, NULL, 0);
3461da177e4SLinus Torvalds MODULE_PARM_DESC(irq,"interrupt for controller");
3471da177e4SLinus Torvalds
3481da177e4SLinus Torvalds static int scsiid[] = {7, 7};
3491da177e4SLinus Torvalds module_param_array(scsiid, int, NULL, 0);
3501da177e4SLinus Torvalds MODULE_PARM_DESC(scsiid,"scsi id of controller");
3511da177e4SLinus Torvalds
3521da177e4SLinus Torvalds static int reconnect[] = {1, 1};
3531da177e4SLinus Torvalds module_param_array(reconnect, int, NULL, 0);
3541da177e4SLinus Torvalds MODULE_PARM_DESC(reconnect,"allow targets to disconnect");
3551da177e4SLinus Torvalds
3561da177e4SLinus Torvalds static int parity[] = {1, 1};
3571da177e4SLinus Torvalds module_param_array(parity, int, NULL, 0);
3581da177e4SLinus Torvalds MODULE_PARM_DESC(parity,"use scsi parity");
3591da177e4SLinus Torvalds
3601da177e4SLinus Torvalds static int sync[] = {1, 1};
3611da177e4SLinus Torvalds module_param_array(sync, int, NULL, 0);
3621da177e4SLinus Torvalds MODULE_PARM_DESC(sync,"use synchronous transfers");
3631da177e4SLinus Torvalds
3641da177e4SLinus Torvalds static int delay[] = {DELAY_DEFAULT, DELAY_DEFAULT};
3651da177e4SLinus Torvalds module_param_array(delay, int, NULL, 0);
3661da177e4SLinus Torvalds MODULE_PARM_DESC(delay,"scsi reset delay");
3671da177e4SLinus Torvalds
3681da177e4SLinus Torvalds static int exttrans[] = {0, 0};
3691da177e4SLinus Torvalds module_param_array(exttrans, int, NULL, 0);
3701da177e4SLinus Torvalds MODULE_PARM_DESC(exttrans,"use extended translation");
3711da177e4SLinus Torvalds
3721da177e4SLinus Torvalds static int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
3731da177e4SLinus Torvalds module_param_array(aha152x, int, NULL, 0);
3741da177e4SLinus Torvalds MODULE_PARM_DESC(aha152x, "parameters for first controller");
3751da177e4SLinus Torvalds
3761da177e4SLinus Torvalds static int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
3771da177e4SLinus Torvalds module_param_array(aha152x1, int, NULL, 0);
3781da177e4SLinus Torvalds MODULE_PARM_DESC(aha152x1, "parameters for second controller");
3791da177e4SLinus Torvalds #endif /* MODULE */
3801da177e4SLinus Torvalds
3811da177e4SLinus Torvalds #ifdef __ISAPNP__
3826f039790SGreg Kroah-Hartman static struct isapnp_device_id id_table[] = {
38350f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1502), 0 },
38450f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1505), 0 },
38550f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1510), 0 },
38650f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1515), 0 },
38750f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1520), 0 },
38850f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2015), 0 },
38950f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1522), 0 },
39050f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2215), 0 },
39150f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1530), 0 },
39250f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3015), 0 },
39350f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1532), 0 },
39450f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3215), 0 },
39550f87f91SOndrej Zary { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x6360), 0 },
3961da177e4SLinus Torvalds { ISAPNP_DEVICE_SINGLE_END, }
3971da177e4SLinus Torvalds };
3981da177e4SLinus Torvalds MODULE_DEVICE_TABLE(isapnp, id_table);
3991da177e4SLinus Torvalds #endif /* ISAPNP */
4001da177e4SLinus Torvalds
4013eb2ebcbSChristoph Hellwig #endif /* !AHA152X_PCMCIA */
4021da177e4SLinus Torvalds
403*11e58ceaSBart Van Assche static const struct scsi_host_template aha152x_driver_template;
4041da177e4SLinus Torvalds
4051da177e4SLinus Torvalds /*
4061da177e4SLinus Torvalds * internal states of the host
4071da177e4SLinus Torvalds *
4081da177e4SLinus Torvalds */
4091da177e4SLinus Torvalds enum aha152x_state {
4101da177e4SLinus Torvalds idle=0,
4111da177e4SLinus Torvalds unknown,
4121da177e4SLinus Torvalds seldo,
4131da177e4SLinus Torvalds seldi,
4141da177e4SLinus Torvalds selto,
4151da177e4SLinus Torvalds busfree,
4161da177e4SLinus Torvalds msgo,
4171da177e4SLinus Torvalds cmd,
4181da177e4SLinus Torvalds msgi,
4191da177e4SLinus Torvalds status,
4201da177e4SLinus Torvalds datai,
4211da177e4SLinus Torvalds datao,
4221da177e4SLinus Torvalds parerr,
4231da177e4SLinus Torvalds rsti,
4241da177e4SLinus Torvalds maxstate
4251da177e4SLinus Torvalds };
4261da177e4SLinus Torvalds
4271da177e4SLinus Torvalds /*
4281da177e4SLinus Torvalds * current state information of the host
4291da177e4SLinus Torvalds *
4301da177e4SLinus Torvalds */
4311da177e4SLinus Torvalds struct aha152x_hostdata {
43291ebc1faSJohannes Thumshirn struct scsi_cmnd *issue_SC;
4331da177e4SLinus Torvalds /* pending commands to issue */
4341da177e4SLinus Torvalds
43591ebc1faSJohannes Thumshirn struct scsi_cmnd *current_SC;
4361da177e4SLinus Torvalds /* current command on the bus */
4371da177e4SLinus Torvalds
43891ebc1faSJohannes Thumshirn struct scsi_cmnd *disconnected_SC;
4391da177e4SLinus Torvalds /* commands that disconnected */
4401da177e4SLinus Torvalds
44191ebc1faSJohannes Thumshirn struct scsi_cmnd *done_SC;
4421da177e4SLinus Torvalds /* command that was completed */
4431da177e4SLinus Torvalds
4441da177e4SLinus Torvalds spinlock_t lock;
4451da177e4SLinus Torvalds /* host lock */
4461da177e4SLinus Torvalds
4471da177e4SLinus Torvalds #if defined(AHA152X_STAT)
4481da177e4SLinus Torvalds int total_commands;
4491da177e4SLinus Torvalds int disconnections;
4501da177e4SLinus Torvalds int busfree_without_any_action;
4511da177e4SLinus Torvalds int busfree_without_old_command;
4521da177e4SLinus Torvalds int busfree_without_new_command;
4531da177e4SLinus Torvalds int busfree_without_done_command;
4541da177e4SLinus Torvalds int busfree_with_check_condition;
4551da177e4SLinus Torvalds int count[maxstate];
4561da177e4SLinus Torvalds int count_trans[maxstate];
4571da177e4SLinus Torvalds unsigned long time[maxstate];
4581da177e4SLinus Torvalds #endif
4591da177e4SLinus Torvalds
4601da177e4SLinus Torvalds int commands; /* current number of commands */
4611da177e4SLinus Torvalds
4621da177e4SLinus Torvalds int reconnect; /* disconnection allowed */
4631da177e4SLinus Torvalds int parity; /* parity checking enabled */
4641da177e4SLinus Torvalds int synchronous; /* synchronous transferes enabled */
4651da177e4SLinus Torvalds int delay; /* reset out delay */
4661da177e4SLinus Torvalds int ext_trans; /* extended translation enabled */
4671da177e4SLinus Torvalds
4681da177e4SLinus Torvalds int swint; /* software-interrupt was fired during detect() */
4691da177e4SLinus Torvalds int service; /* bh needs to be run */
4701da177e4SLinus Torvalds int in_intr; /* bh is running */
4711da177e4SLinus Torvalds
4721da177e4SLinus Torvalds /* current state,
4731da177e4SLinus Torvalds previous state,
4741da177e4SLinus Torvalds last state different from current state */
4751da177e4SLinus Torvalds enum aha152x_state state, prevstate, laststate;
4761da177e4SLinus Torvalds
4771da177e4SLinus Torvalds int target;
4781da177e4SLinus Torvalds /* reconnecting target */
4791da177e4SLinus Torvalds
4801da177e4SLinus Torvalds unsigned char syncrate[8];
4811da177e4SLinus Torvalds /* current synchronous transfer agreements */
4821da177e4SLinus Torvalds
4831da177e4SLinus Torvalds unsigned char syncneg[8];
4841da177e4SLinus Torvalds /* 0: no negotiation;
4851da177e4SLinus Torvalds * 1: negotiation in progress;
4861da177e4SLinus Torvalds * 2: negotiation completed
4871da177e4SLinus Torvalds */
4881da177e4SLinus Torvalds
4891da177e4SLinus Torvalds int cmd_i;
4901da177e4SLinus Torvalds /* number of sent bytes of current command */
4911da177e4SLinus Torvalds
4921da177e4SLinus Torvalds int msgi_len;
4931da177e4SLinus Torvalds /* number of received message bytes */
4941da177e4SLinus Torvalds unsigned char msgi[256];
4951da177e4SLinus Torvalds /* received message bytes */
4961da177e4SLinus Torvalds
4971da177e4SLinus Torvalds int msgo_i, msgo_len;
4981da177e4SLinus Torvalds /* number of sent bytes and length of current messages */
4991da177e4SLinus Torvalds unsigned char msgo[256];
5001da177e4SLinus Torvalds /* pending messages */
5011da177e4SLinus Torvalds
5021da177e4SLinus Torvalds int data_len;
5031da177e4SLinus Torvalds /* number of sent/received bytes in dataphase */
5041da177e4SLinus Torvalds
5051da177e4SLinus Torvalds unsigned long io_port0;
5061da177e4SLinus Torvalds unsigned long io_port1;
5071da177e4SLinus Torvalds
5081da177e4SLinus Torvalds #ifdef __ISAPNP__
5091da177e4SLinus Torvalds struct pnp_dev *pnpdev;
5101da177e4SLinus Torvalds #endif
5115fcda422SJames Bottomley struct list_head host_list;
5121da177e4SLinus Torvalds };
5131da177e4SLinus Torvalds
5141da177e4SLinus Torvalds
5151da177e4SLinus Torvalds /*
5161da177e4SLinus Torvalds * host specific command extension
5171da177e4SLinus Torvalds *
5181da177e4SLinus Torvalds */
5191da177e4SLinus Torvalds struct aha152x_scdata {
52091ebc1faSJohannes Thumshirn struct scsi_cmnd *next; /* next sc in queue */
5210f06bb34SChristoph Hellwig struct completion *done;/* semaphore to block on */
52273d2cb16SBoaz Harrosh struct scsi_eh_save ses;
5231da177e4SLinus Torvalds };
5241da177e4SLinus Torvalds
5251da177e4SLinus Torvalds /* access macros for hostdata */
5261da177e4SLinus Torvalds
5271da177e4SLinus Torvalds #define HOSTDATA(shpnt) ((struct aha152x_hostdata *) &shpnt->hostdata)
5281da177e4SLinus Torvalds
5291da177e4SLinus Torvalds #define HOSTNO ((shpnt)->host_no)
5301da177e4SLinus Torvalds
5311da177e4SLinus Torvalds #define CURRENT_SC (HOSTDATA(shpnt)->current_SC)
5321da177e4SLinus Torvalds #define DONE_SC (HOSTDATA(shpnt)->done_SC)
5331da177e4SLinus Torvalds #define ISSUE_SC (HOSTDATA(shpnt)->issue_SC)
5341da177e4SLinus Torvalds #define DISCONNECTED_SC (HOSTDATA(shpnt)->disconnected_SC)
5351da177e4SLinus Torvalds #define QLOCK (HOSTDATA(shpnt)->lock)
5361da177e4SLinus Torvalds #define QLOCKER (HOSTDATA(shpnt)->locker)
5371da177e4SLinus Torvalds #define QLOCKERL (HOSTDATA(shpnt)->lockerl)
5381da177e4SLinus Torvalds
5391da177e4SLinus Torvalds #define STATE (HOSTDATA(shpnt)->state)
5401da177e4SLinus Torvalds #define PREVSTATE (HOSTDATA(shpnt)->prevstate)
5411da177e4SLinus Torvalds #define LASTSTATE (HOSTDATA(shpnt)->laststate)
5421da177e4SLinus Torvalds
5431da177e4SLinus Torvalds #define RECONN_TARGET (HOSTDATA(shpnt)->target)
5441da177e4SLinus Torvalds
5451da177e4SLinus Torvalds #define CMD_I (HOSTDATA(shpnt)->cmd_i)
5461da177e4SLinus Torvalds
5471da177e4SLinus Torvalds #define MSGO(i) (HOSTDATA(shpnt)->msgo[i])
5481da177e4SLinus Torvalds #define MSGO_I (HOSTDATA(shpnt)->msgo_i)
5491da177e4SLinus Torvalds #define MSGOLEN (HOSTDATA(shpnt)->msgo_len)
5501da177e4SLinus Torvalds #define ADDMSGO(x) (MSGOLEN<256 ? (void)(MSGO(MSGOLEN++)=x) : aha152x_error(shpnt,"MSGO overflow"))
5511da177e4SLinus Torvalds
5521da177e4SLinus Torvalds #define MSGI(i) (HOSTDATA(shpnt)->msgi[i])
5531da177e4SLinus Torvalds #define MSGILEN (HOSTDATA(shpnt)->msgi_len)
5541da177e4SLinus Torvalds #define ADDMSGI(x) (MSGILEN<256 ? (void)(MSGI(MSGILEN++)=x) : aha152x_error(shpnt,"MSGI overflow"))
5551da177e4SLinus Torvalds
5561da177e4SLinus Torvalds #define DATA_LEN (HOSTDATA(shpnt)->data_len)
5571da177e4SLinus Torvalds
5581da177e4SLinus Torvalds #define SYNCRATE (HOSTDATA(shpnt)->syncrate[CURRENT_SC->device->id])
5591da177e4SLinus Torvalds #define SYNCNEG (HOSTDATA(shpnt)->syncneg[CURRENT_SC->device->id])
5601da177e4SLinus Torvalds
5611da177e4SLinus Torvalds #define DELAY (HOSTDATA(shpnt)->delay)
5621da177e4SLinus Torvalds #define EXT_TRANS (HOSTDATA(shpnt)->ext_trans)
5631da177e4SLinus Torvalds #define TC1550 (HOSTDATA(shpnt)->tc1550)
5641da177e4SLinus Torvalds #define RECONNECT (HOSTDATA(shpnt)->reconnect)
5651da177e4SLinus Torvalds #define PARITY (HOSTDATA(shpnt)->parity)
5661da177e4SLinus Torvalds #define SYNCHRONOUS (HOSTDATA(shpnt)->synchronous)
5671da177e4SLinus Torvalds
5681da177e4SLinus Torvalds #define HOSTIOPORT0 (HOSTDATA(shpnt)->io_port0)
5691da177e4SLinus Torvalds #define HOSTIOPORT1 (HOSTDATA(shpnt)->io_port1)
5701da177e4SLinus Torvalds
5711da177e4SLinus Torvalds #define SCDATA(SCpnt) ((struct aha152x_scdata *) (SCpnt)->host_scribble)
5721da177e4SLinus Torvalds #define SCNEXT(SCpnt) SCDATA(SCpnt)->next
5730f06bb34SChristoph Hellwig #define SCSEM(SCpnt) SCDATA(SCpnt)->done
5741da177e4SLinus Torvalds
57545711f1aSJens Axboe #define SG_ADDRESS(buffer) ((char *) sg_virt((buffer)))
5761da177e4SLinus Torvalds
5771da177e4SLinus Torvalds /* state handling */
5781da177e4SLinus Torvalds static void seldi_run(struct Scsi_Host *shpnt);
5791da177e4SLinus Torvalds static void seldo_run(struct Scsi_Host *shpnt);
5801da177e4SLinus Torvalds static void selto_run(struct Scsi_Host *shpnt);
5811da177e4SLinus Torvalds static void busfree_run(struct Scsi_Host *shpnt);
5821da177e4SLinus Torvalds
5831da177e4SLinus Torvalds static void msgo_init(struct Scsi_Host *shpnt);
5841da177e4SLinus Torvalds static void msgo_run(struct Scsi_Host *shpnt);
5851da177e4SLinus Torvalds static void msgo_end(struct Scsi_Host *shpnt);
5861da177e4SLinus Torvalds
5871da177e4SLinus Torvalds static void cmd_init(struct Scsi_Host *shpnt);
5881da177e4SLinus Torvalds static void cmd_run(struct Scsi_Host *shpnt);
5891da177e4SLinus Torvalds static void cmd_end(struct Scsi_Host *shpnt);
5901da177e4SLinus Torvalds
5911da177e4SLinus Torvalds static void datai_init(struct Scsi_Host *shpnt);
5921da177e4SLinus Torvalds static void datai_run(struct Scsi_Host *shpnt);
5931da177e4SLinus Torvalds static void datai_end(struct Scsi_Host *shpnt);
5941da177e4SLinus Torvalds
5951da177e4SLinus Torvalds static void datao_init(struct Scsi_Host *shpnt);
5961da177e4SLinus Torvalds static void datao_run(struct Scsi_Host *shpnt);
5971da177e4SLinus Torvalds static void datao_end(struct Scsi_Host *shpnt);
5981da177e4SLinus Torvalds
5991da177e4SLinus Torvalds static void status_run(struct Scsi_Host *shpnt);
6001da177e4SLinus Torvalds
6011da177e4SLinus Torvalds static void msgi_run(struct Scsi_Host *shpnt);
6021da177e4SLinus Torvalds static void msgi_end(struct Scsi_Host *shpnt);
6031da177e4SLinus Torvalds
6041da177e4SLinus Torvalds static void parerr_run(struct Scsi_Host *shpnt);
6051da177e4SLinus Torvalds static void rsti_run(struct Scsi_Host *shpnt);
6061da177e4SLinus Torvalds
6071da177e4SLinus Torvalds static void is_complete(struct Scsi_Host *shpnt);
6081da177e4SLinus Torvalds
6091da177e4SLinus Torvalds /*
6101da177e4SLinus Torvalds * driver states
6111da177e4SLinus Torvalds *
6121da177e4SLinus Torvalds */
6131da177e4SLinus Torvalds static struct {
6141da177e4SLinus Torvalds char *name;
6151da177e4SLinus Torvalds void (*init)(struct Scsi_Host *);
6161da177e4SLinus Torvalds void (*run)(struct Scsi_Host *);
6171da177e4SLinus Torvalds void (*end)(struct Scsi_Host *);
6181da177e4SLinus Torvalds int spio;
6191da177e4SLinus Torvalds } states[] = {
6201da177e4SLinus Torvalds { "idle", NULL, NULL, NULL, 0},
6211da177e4SLinus Torvalds { "unknown", NULL, NULL, NULL, 0},
6221da177e4SLinus Torvalds { "seldo", NULL, seldo_run, NULL, 0},
6231da177e4SLinus Torvalds { "seldi", NULL, seldi_run, NULL, 0},
6241da177e4SLinus Torvalds { "selto", NULL, selto_run, NULL, 0},
6251da177e4SLinus Torvalds { "busfree", NULL, busfree_run, NULL, 0},
6261da177e4SLinus Torvalds { "msgo", msgo_init, msgo_run, msgo_end, 1},
6271da177e4SLinus Torvalds { "cmd", cmd_init, cmd_run, cmd_end, 1},
6281da177e4SLinus Torvalds { "msgi", NULL, msgi_run, msgi_end, 1},
6291da177e4SLinus Torvalds { "status", NULL, status_run, NULL, 1},
6301da177e4SLinus Torvalds { "datai", datai_init, datai_run, datai_end, 0},
6311da177e4SLinus Torvalds { "datao", datao_init, datao_run, datao_end, 0},
6321da177e4SLinus Torvalds { "parerr", NULL, parerr_run, NULL, 0},
6331da177e4SLinus Torvalds { "rsti", NULL, rsti_run, NULL, 0},
6341da177e4SLinus Torvalds };
6351da177e4SLinus Torvalds
6361da177e4SLinus Torvalds /* setup & interrupt */
6377d12e780SDavid Howells static irqreturn_t intr(int irq, void *dev_id);
6381da177e4SLinus Torvalds static void reset_ports(struct Scsi_Host *shpnt);
6391da177e4SLinus Torvalds static void aha152x_error(struct Scsi_Host *shpnt, char *msg);
640aec166fdSHannes Reinecke static void done(struct Scsi_Host *shpnt, unsigned char status_byte,
641fdabe57dSHannes Reinecke unsigned char host_byte);
6421da177e4SLinus Torvalds
6431da177e4SLinus Torvalds /* diagnostics */
64491ebc1faSJohannes Thumshirn static void show_command(struct scsi_cmnd * ptr);
6451da177e4SLinus Torvalds static void show_queues(struct Scsi_Host *shpnt);
6461da177e4SLinus Torvalds static void disp_enintr(struct Scsi_Host *shpnt);
6471da177e4SLinus Torvalds
6481da177e4SLinus Torvalds
6491da177e4SLinus Torvalds /*
6501da177e4SLinus Torvalds * queue services:
6511da177e4SLinus Torvalds *
6521da177e4SLinus Torvalds */
append_SC(struct scsi_cmnd ** SC,struct scsi_cmnd * new_SC)65391ebc1faSJohannes Thumshirn static inline void append_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC)
6541da177e4SLinus Torvalds {
65591ebc1faSJohannes Thumshirn struct scsi_cmnd *end;
6561da177e4SLinus Torvalds
6571da177e4SLinus Torvalds SCNEXT(new_SC) = NULL;
6581da177e4SLinus Torvalds if (!*SC)
6591da177e4SLinus Torvalds *SC = new_SC;
6601da177e4SLinus Torvalds else {
6611da177e4SLinus Torvalds for (end = *SC; SCNEXT(end); end = SCNEXT(end))
6621da177e4SLinus Torvalds ;
6631da177e4SLinus Torvalds SCNEXT(end) = new_SC;
6641da177e4SLinus Torvalds }
6651da177e4SLinus Torvalds }
6661da177e4SLinus Torvalds
remove_first_SC(struct scsi_cmnd ** SC)66791ebc1faSJohannes Thumshirn static inline struct scsi_cmnd *remove_first_SC(struct scsi_cmnd ** SC)
6681da177e4SLinus Torvalds {
66991ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr;
6701da177e4SLinus Torvalds
6711da177e4SLinus Torvalds ptr = *SC;
6721da177e4SLinus Torvalds if (ptr) {
6731da177e4SLinus Torvalds *SC = SCNEXT(*SC);
6741da177e4SLinus Torvalds SCNEXT(ptr)=NULL;
6751da177e4SLinus Torvalds }
6761da177e4SLinus Torvalds return ptr;
6771da177e4SLinus Torvalds }
6781da177e4SLinus Torvalds
remove_lun_SC(struct scsi_cmnd ** SC,int target,int lun)67991ebc1faSJohannes Thumshirn static inline struct scsi_cmnd *remove_lun_SC(struct scsi_cmnd ** SC,
68091ebc1faSJohannes Thumshirn int target, int lun)
6811da177e4SLinus Torvalds {
68291ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr, *prev;
6831da177e4SLinus Torvalds
6841da177e4SLinus Torvalds for (ptr = *SC, prev = NULL;
6851da177e4SLinus Torvalds ptr && ((ptr->device->id != target) || (ptr->device->lun != lun));
6861da177e4SLinus Torvalds prev = ptr, ptr = SCNEXT(ptr))
6871da177e4SLinus Torvalds ;
6881da177e4SLinus Torvalds
6891da177e4SLinus Torvalds if (ptr) {
6901da177e4SLinus Torvalds if (prev)
6911da177e4SLinus Torvalds SCNEXT(prev) = SCNEXT(ptr);
6921da177e4SLinus Torvalds else
6931da177e4SLinus Torvalds *SC = SCNEXT(ptr);
6941da177e4SLinus Torvalds
6951da177e4SLinus Torvalds SCNEXT(ptr)=NULL;
6961da177e4SLinus Torvalds }
6971da177e4SLinus Torvalds
6981da177e4SLinus Torvalds return ptr;
6991da177e4SLinus Torvalds }
7001da177e4SLinus Torvalds
remove_SC(struct scsi_cmnd ** SC,struct scsi_cmnd * SCp)70191ebc1faSJohannes Thumshirn static inline struct scsi_cmnd *remove_SC(struct scsi_cmnd **SC,
70291ebc1faSJohannes Thumshirn struct scsi_cmnd *SCp)
7031da177e4SLinus Torvalds {
70491ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr, *prev;
7051da177e4SLinus Torvalds
7061da177e4SLinus Torvalds for (ptr = *SC, prev = NULL;
7071da177e4SLinus Torvalds ptr && SCp!=ptr;
7081da177e4SLinus Torvalds prev = ptr, ptr = SCNEXT(ptr))
7091da177e4SLinus Torvalds ;
7101da177e4SLinus Torvalds
7111da177e4SLinus Torvalds if (ptr) {
7121da177e4SLinus Torvalds if (prev)
7131da177e4SLinus Torvalds SCNEXT(prev) = SCNEXT(ptr);
7141da177e4SLinus Torvalds else
7151da177e4SLinus Torvalds *SC = SCNEXT(ptr);
7161da177e4SLinus Torvalds
7171da177e4SLinus Torvalds SCNEXT(ptr)=NULL;
7181da177e4SLinus Torvalds }
7191da177e4SLinus Torvalds
7201da177e4SLinus Torvalds return ptr;
7211da177e4SLinus Torvalds }
7221da177e4SLinus Torvalds
swintr(int irqno,void * dev_id)7237d12e780SDavid Howells static irqreturn_t swintr(int irqno, void *dev_id)
7241da177e4SLinus Torvalds {
725c7bec5abSJeff Garzik struct Scsi_Host *shpnt = dev_id;
7261da177e4SLinus Torvalds
7271da177e4SLinus Torvalds HOSTDATA(shpnt)->swint++;
7281da177e4SLinus Torvalds
7291da177e4SLinus Torvalds SETPORT(DMACNTRL0, INTEN);
7301da177e4SLinus Torvalds return IRQ_HANDLED;
7311da177e4SLinus Torvalds }
7321da177e4SLinus Torvalds
aha152x_probe_one(struct aha152x_setup * setup)7331da177e4SLinus Torvalds struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
7341da177e4SLinus Torvalds {
7351da177e4SLinus Torvalds struct Scsi_Host *shpnt;
7361da177e4SLinus Torvalds
7371da177e4SLinus Torvalds shpnt = scsi_host_alloc(&aha152x_driver_template, sizeof(struct aha152x_hostdata));
7381da177e4SLinus Torvalds if (!shpnt) {
7391da177e4SLinus Torvalds printk(KERN_ERR "aha152x: scsi_host_alloc failed\n");
7401da177e4SLinus Torvalds return NULL;
7411da177e4SLinus Torvalds }
7421da177e4SLinus Torvalds
7431da177e4SLinus Torvalds memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt));
7445fcda422SJames Bottomley INIT_LIST_HEAD(&HOSTDATA(shpnt)->host_list);
7455fcda422SJames Bottomley
7465fcda422SJames Bottomley /* need to have host registered before triggering any interrupt */
7475fcda422SJames Bottomley list_add_tail(&HOSTDATA(shpnt)->host_list, &aha152x_host_list);
7481da177e4SLinus Torvalds
7491da177e4SLinus Torvalds shpnt->io_port = setup->io_port;
7501da177e4SLinus Torvalds shpnt->n_io_port = IO_RANGE;
7511da177e4SLinus Torvalds shpnt->irq = setup->irq;
7521da177e4SLinus Torvalds
7531da177e4SLinus Torvalds if (!setup->tc1550) {
7541da177e4SLinus Torvalds HOSTIOPORT0 = setup->io_port;
7551da177e4SLinus Torvalds HOSTIOPORT1 = setup->io_port;
7561da177e4SLinus Torvalds } else {
7571da177e4SLinus Torvalds HOSTIOPORT0 = setup->io_port+0x10;
7581da177e4SLinus Torvalds HOSTIOPORT1 = setup->io_port-0x10;
7591da177e4SLinus Torvalds }
7601da177e4SLinus Torvalds
7611da177e4SLinus Torvalds spin_lock_init(&QLOCK);
7621da177e4SLinus Torvalds RECONNECT = setup->reconnect;
7631da177e4SLinus Torvalds SYNCHRONOUS = setup->synchronous;
7641da177e4SLinus Torvalds PARITY = setup->parity;
7651da177e4SLinus Torvalds DELAY = setup->delay;
7661da177e4SLinus Torvalds EXT_TRANS = setup->ext_trans;
7671da177e4SLinus Torvalds
7681da177e4SLinus Torvalds SETPORT(SCSIID, setup->scsiid << 4);
7691da177e4SLinus Torvalds shpnt->this_id = setup->scsiid;
7701da177e4SLinus Torvalds
7711da177e4SLinus Torvalds if (setup->reconnect)
7721da177e4SLinus Torvalds shpnt->can_queue = AHA152X_MAXQUEUE;
7731da177e4SLinus Torvalds
7741da177e4SLinus Torvalds /* RESET OUT */
7751da177e4SLinus Torvalds printk("aha152x: resetting bus...\n");
7761da177e4SLinus Torvalds SETPORT(SCSISEQ, SCSIRSTO);
7771da177e4SLinus Torvalds mdelay(256);
7781da177e4SLinus Torvalds SETPORT(SCSISEQ, 0);
7791da177e4SLinus Torvalds mdelay(DELAY);
7801da177e4SLinus Torvalds
7811da177e4SLinus Torvalds reset_ports(shpnt);
7821da177e4SLinus Torvalds
7831da177e4SLinus Torvalds printk(KERN_INFO
7841da177e4SLinus Torvalds "aha152x%d%s: "
7851da177e4SLinus Torvalds "vital data: rev=%x, "
7861da177e4SLinus Torvalds "io=0x%03lx (0x%03lx/0x%03lx), "
7871da177e4SLinus Torvalds "irq=%d, "
7881da177e4SLinus Torvalds "scsiid=%d, "
7891da177e4SLinus Torvalds "reconnect=%s, "
7901da177e4SLinus Torvalds "parity=%s, "
7911da177e4SLinus Torvalds "synchronous=%s, "
7921da177e4SLinus Torvalds "delay=%d, "
7931da177e4SLinus Torvalds "extended translation=%s\n",
7941da177e4SLinus Torvalds shpnt->host_no, setup->tc1550 ? " (tc1550 mode)" : "",
7951da177e4SLinus Torvalds GETPORT(REV) & 0x7,
7961da177e4SLinus Torvalds shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1,
7971da177e4SLinus Torvalds shpnt->irq,
7981da177e4SLinus Torvalds shpnt->this_id,
7991da177e4SLinus Torvalds RECONNECT ? "enabled" : "disabled",
8001da177e4SLinus Torvalds PARITY ? "enabled" : "disabled",
8011da177e4SLinus Torvalds SYNCHRONOUS ? "enabled" : "disabled",
8021da177e4SLinus Torvalds DELAY,
8031da177e4SLinus Torvalds EXT_TRANS ? "enabled" : "disabled");
8041da177e4SLinus Torvalds
8051da177e4SLinus Torvalds /* not expecting any interrupts */
8061da177e4SLinus Torvalds SETPORT(SIMODE0, 0);
8071da177e4SLinus Torvalds SETPORT(SIMODE1, 0);
8081da177e4SLinus Torvalds
8094909cc2bSMichael Opdenacker if (request_irq(shpnt->irq, swintr, IRQF_SHARED, "aha152x", shpnt)) {
8101da177e4SLinus Torvalds printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq);
8111da177e4SLinus Torvalds goto out_host_put;
8121da177e4SLinus Torvalds }
8131da177e4SLinus Torvalds
8141da177e4SLinus Torvalds HOSTDATA(shpnt)->swint = 0;
8151da177e4SLinus Torvalds
8161da177e4SLinus Torvalds printk(KERN_INFO "aha152x%d: trying software interrupt, ", shpnt->host_no);
8171da177e4SLinus Torvalds
8181da177e4SLinus Torvalds mb();
8191da177e4SLinus Torvalds SETPORT(DMACNTRL0, SWINT|INTEN);
8201da177e4SLinus Torvalds mdelay(1000);
8211da177e4SLinus Torvalds free_irq(shpnt->irq, shpnt);
8221da177e4SLinus Torvalds
8231da177e4SLinus Torvalds if (!HOSTDATA(shpnt)->swint) {
8241da177e4SLinus Torvalds if (TESTHI(DMASTAT, INTSTAT)) {
8251da177e4SLinus Torvalds printk("lost.\n");
8261da177e4SLinus Torvalds } else {
8271da177e4SLinus Torvalds printk("failed.\n");
8281da177e4SLinus Torvalds }
8291da177e4SLinus Torvalds
8301da177e4SLinus Torvalds SETPORT(DMACNTRL0, INTEN);
8311da177e4SLinus Torvalds
8321da177e4SLinus Torvalds printk(KERN_ERR "aha152x%d: irq %d possibly wrong. "
8331da177e4SLinus Torvalds "Please verify.\n", shpnt->host_no, shpnt->irq);
8341da177e4SLinus Torvalds goto out_host_put;
8351da177e4SLinus Torvalds }
8361da177e4SLinus Torvalds printk("ok.\n");
8371da177e4SLinus Torvalds
8381da177e4SLinus Torvalds
8391da177e4SLinus Torvalds /* clear interrupts */
8401da177e4SLinus Torvalds SETPORT(SSTAT0, 0x7f);
8411da177e4SLinus Torvalds SETPORT(SSTAT1, 0xef);
8421da177e4SLinus Torvalds
8434909cc2bSMichael Opdenacker if (request_irq(shpnt->irq, intr, IRQF_SHARED, "aha152x", shpnt)) {
8441da177e4SLinus Torvalds printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq);
8451da177e4SLinus Torvalds goto out_host_put;
8461da177e4SLinus Torvalds }
8471da177e4SLinus Torvalds
8481da177e4SLinus Torvalds if( scsi_add_host(shpnt, NULL) ) {
8491da177e4SLinus Torvalds free_irq(shpnt->irq, shpnt);
8501da177e4SLinus Torvalds printk(KERN_ERR "aha152x%d: failed to add host.\n", shpnt->host_no);
8511da177e4SLinus Torvalds goto out_host_put;
8521da177e4SLinus Torvalds }
8531da177e4SLinus Torvalds
8541da177e4SLinus Torvalds scsi_scan_host(shpnt);
8551da177e4SLinus Torvalds
8561da177e4SLinus Torvalds return shpnt;
8571da177e4SLinus Torvalds
8581da177e4SLinus Torvalds out_host_put:
8595fcda422SJames Bottomley list_del(&HOSTDATA(shpnt)->host_list);
8601da177e4SLinus Torvalds scsi_host_put(shpnt);
8611da177e4SLinus Torvalds
8621da177e4SLinus Torvalds return NULL;
8631da177e4SLinus Torvalds }
8641da177e4SLinus Torvalds
aha152x_release(struct Scsi_Host * shpnt)8651da177e4SLinus Torvalds void aha152x_release(struct Scsi_Host *shpnt)
8661da177e4SLinus Torvalds {
8671da177e4SLinus Torvalds if (!shpnt)
8681da177e4SLinus Torvalds return;
8691da177e4SLinus Torvalds
8701bd40573SMatthew Wilcox scsi_remove_host(shpnt);
8711da177e4SLinus Torvalds if (shpnt->irq)
8721da177e4SLinus Torvalds free_irq(shpnt->irq, shpnt);
8731da177e4SLinus Torvalds
8743eb2ebcbSChristoph Hellwig #if !defined(AHA152X_PCMCIA)
8751da177e4SLinus Torvalds if (shpnt->io_port)
8761da177e4SLinus Torvalds release_region(shpnt->io_port, IO_RANGE);
8771da177e4SLinus Torvalds #endif
8781da177e4SLinus Torvalds
8791da177e4SLinus Torvalds #ifdef __ISAPNP__
8801da177e4SLinus Torvalds if (HOSTDATA(shpnt)->pnpdev)
8811da177e4SLinus Torvalds pnp_device_detach(HOSTDATA(shpnt)->pnpdev);
8821da177e4SLinus Torvalds #endif
8831da177e4SLinus Torvalds
8845fcda422SJames Bottomley list_del(&HOSTDATA(shpnt)->host_list);
8851da177e4SLinus Torvalds scsi_host_put(shpnt);
8861da177e4SLinus Torvalds }
8871da177e4SLinus Torvalds
8881da177e4SLinus Torvalds
8891da177e4SLinus Torvalds /*
8901da177e4SLinus Torvalds * setup controller to generate interrupts depending
8911da177e4SLinus Torvalds * on current state (lock has to be acquired)
8921da177e4SLinus Torvalds *
8931da177e4SLinus Torvalds */
setup_expected_interrupts(struct Scsi_Host * shpnt)8941da177e4SLinus Torvalds static int setup_expected_interrupts(struct Scsi_Host *shpnt)
8951da177e4SLinus Torvalds {
8961da177e4SLinus Torvalds if(CURRENT_SC) {
89763221571SFinn Thain struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
8981da177e4SLinus Torvalds
89963221571SFinn Thain acp->phase |= 1 << 16;
9003ac6aba3SBart Van Assche
90163221571SFinn Thain if (acp->phase & selecting) {
9021da177e4SLinus Torvalds SETPORT(SSTAT1, SELTO);
9031da177e4SLinus Torvalds SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
9041da177e4SLinus Torvalds SETPORT(SIMODE1, ENSELTIMO);
9051da177e4SLinus Torvalds } else {
90663221571SFinn Thain SETPORT(SIMODE0, (acp->phase & spiordy) ? ENSPIORDY : 0);
9071da177e4SLinus Torvalds SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE);
9081da177e4SLinus Torvalds }
9091da177e4SLinus Torvalds } else if(STATE==seldi) {
9101da177e4SLinus Torvalds SETPORT(SIMODE0, 0);
9111da177e4SLinus Torvalds SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE);
9121da177e4SLinus Torvalds } else {
9131da177e4SLinus Torvalds SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
9141da177e4SLinus Torvalds SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0));
9151da177e4SLinus Torvalds }
9161da177e4SLinus Torvalds
9171da177e4SLinus Torvalds if(!HOSTDATA(shpnt)->in_intr)
9181da177e4SLinus Torvalds SETBITS(DMACNTRL0, INTEN);
9191da177e4SLinus Torvalds
9201da177e4SLinus Torvalds return TESTHI(DMASTAT, INTSTAT);
9211da177e4SLinus Torvalds }
9221da177e4SLinus Torvalds
9231da177e4SLinus Torvalds
9241da177e4SLinus Torvalds /*
9251da177e4SLinus Torvalds * Queue a command and setup interrupts for a free bus.
9261da177e4SLinus Torvalds */
aha152x_internal_queue(struct scsi_cmnd * SCpnt,struct completion * complete,int phase)92791ebc1faSJohannes Thumshirn static int aha152x_internal_queue(struct scsi_cmnd *SCpnt,
9283ab3b151SBart Van Assche struct completion *complete, int phase)
9291da177e4SLinus Torvalds {
93063221571SFinn Thain struct aha152x_cmd_priv *acp = aha152x_priv(SCpnt);
9311da177e4SLinus Torvalds struct Scsi_Host *shpnt = SCpnt->device->host;
9321da177e4SLinus Torvalds unsigned long flags;
9331da177e4SLinus Torvalds
93463221571SFinn Thain acp->phase = not_issued | phase;
93563221571SFinn Thain acp->status = 0x1; /* Illegal status by SCSI standard */
93663221571SFinn Thain acp->message = 0;
93763221571SFinn Thain acp->sent_command = 0;
9381da177e4SLinus Torvalds
93963221571SFinn Thain if (acp->phase & (resetting | check_condition)) {
940172c122dSHarvey Harrison if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) {
941f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, SCpnt, "cannot reuse command\n");
9421da177e4SLinus Torvalds return FAILED;
9431da177e4SLinus Torvalds }
9441da177e4SLinus Torvalds } else {
9451da177e4SLinus Torvalds SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
946172c122dSHarvey Harrison if(!SCpnt->host_scribble) {
947f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, SCpnt, "allocation failed\n");
9481da177e4SLinus Torvalds return FAILED;
9491da177e4SLinus Torvalds }
9501da177e4SLinus Torvalds }
9511da177e4SLinus Torvalds
9521da177e4SLinus Torvalds SCNEXT(SCpnt) = NULL;
9530f06bb34SChristoph Hellwig SCSEM(SCpnt) = complete;
9541da177e4SLinus Torvalds
9551da177e4SLinus Torvalds /* setup scratch area
9561da177e4SLinus Torvalds SCp.ptr : buffer pointer
9571da177e4SLinus Torvalds SCp.this_residual : buffer length
9581da177e4SLinus Torvalds SCp.buffer : next buffer
9591da177e4SLinus Torvalds SCp.phase : current state of the command */
96066acdb03SBoaz Harrosh
96173d2cb16SBoaz Harrosh if ((phase & resetting) || !scsi_sglist(SCpnt)) {
96263221571SFinn Thain acp->ptr = NULL;
96363221571SFinn Thain acp->this_residual = 0;
9642338545aSBoaz Harrosh scsi_set_resid(SCpnt, 0);
96563221571SFinn Thain acp->buffer = NULL;
96666acdb03SBoaz Harrosh } else {
9672338545aSBoaz Harrosh scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
96863221571SFinn Thain acp->buffer = scsi_sglist(SCpnt);
96963221571SFinn Thain acp->ptr = SG_ADDRESS(acp->buffer);
97063221571SFinn Thain acp->this_residual = acp->buffer->length;
97166acdb03SBoaz Harrosh }
9721da177e4SLinus Torvalds
9731da177e4SLinus Torvalds DO_LOCK(flags);
9741da177e4SLinus Torvalds
9751da177e4SLinus Torvalds #if defined(AHA152X_STAT)
9761da177e4SLinus Torvalds HOSTDATA(shpnt)->total_commands++;
9771da177e4SLinus Torvalds #endif
9781da177e4SLinus Torvalds
9791da177e4SLinus Torvalds /* Turn led on, when this is the first command. */
9801da177e4SLinus Torvalds HOSTDATA(shpnt)->commands++;
9811da177e4SLinus Torvalds if (HOSTDATA(shpnt)->commands==1)
9821da177e4SLinus Torvalds SETPORT(PORTA, 1);
9831da177e4SLinus Torvalds
9841da177e4SLinus Torvalds append_SC(&ISSUE_SC, SCpnt);
9851da177e4SLinus Torvalds
9861da177e4SLinus Torvalds if(!HOSTDATA(shpnt)->in_intr)
9871da177e4SLinus Torvalds setup_expected_interrupts(shpnt);
9881da177e4SLinus Torvalds
9891da177e4SLinus Torvalds DO_UNLOCK(flags);
9901da177e4SLinus Torvalds
9911da177e4SLinus Torvalds return 0;
9921da177e4SLinus Torvalds }
9931da177e4SLinus Torvalds
9941da177e4SLinus Torvalds /*
9951da177e4SLinus Torvalds * queue a command
9961da177e4SLinus Torvalds *
9971da177e4SLinus Torvalds */
aha152x_queue_lck(struct scsi_cmnd * SCpnt)998af049dfdSBart Van Assche static int aha152x_queue_lck(struct scsi_cmnd *SCpnt)
9991da177e4SLinus Torvalds {
10003ab3b151SBart Van Assche return aha152x_internal_queue(SCpnt, NULL, 0);
10011da177e4SLinus Torvalds }
10021da177e4SLinus Torvalds
DEF_SCSI_QCMD(aha152x_queue)1003f281233dSJeff Garzik static DEF_SCSI_QCMD(aha152x_queue)
1004f281233dSJeff Garzik
10051da177e4SLinus Torvalds
10061da177e4SLinus Torvalds /*
10071da177e4SLinus Torvalds *
10081da177e4SLinus Torvalds */
100991ebc1faSJohannes Thumshirn static void reset_done(struct scsi_cmnd *SCpnt)
10101da177e4SLinus Torvalds {
10111da177e4SLinus Torvalds if(SCSEM(SCpnt)) {
10120f06bb34SChristoph Hellwig complete(SCSEM(SCpnt));
10131da177e4SLinus Torvalds } else {
10140f06bb34SChristoph Hellwig printk(KERN_ERR "aha152x: reset_done w/o completion\n");
10151da177e4SLinus Torvalds }
10161da177e4SLinus Torvalds }
10171da177e4SLinus Torvalds
aha152x_scsi_done(struct scsi_cmnd * SCpnt)10183ab3b151SBart Van Assche static void aha152x_scsi_done(struct scsi_cmnd *SCpnt)
10193ab3b151SBart Van Assche {
102063221571SFinn Thain if (aha152x_priv(SCpnt)->phase & resetting)
10213ab3b151SBart Van Assche reset_done(SCpnt);
10223ab3b151SBart Van Assche else
10233ab3b151SBart Van Assche scsi_done(SCpnt);
10243ab3b151SBart Van Assche }
10253ab3b151SBart Van Assche
10261da177e4SLinus Torvalds /*
10271da177e4SLinus Torvalds * Abort a command
10281da177e4SLinus Torvalds *
10291da177e4SLinus Torvalds */
aha152x_abort(struct scsi_cmnd * SCpnt)103091ebc1faSJohannes Thumshirn static int aha152x_abort(struct scsi_cmnd *SCpnt)
10311da177e4SLinus Torvalds {
10321da177e4SLinus Torvalds struct Scsi_Host *shpnt = SCpnt->device->host;
103391ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr;
10341da177e4SLinus Torvalds unsigned long flags;
10351da177e4SLinus Torvalds
10361da177e4SLinus Torvalds DO_LOCK(flags);
10371da177e4SLinus Torvalds
10381da177e4SLinus Torvalds ptr=remove_SC(&ISSUE_SC, SCpnt);
10391da177e4SLinus Torvalds
10401da177e4SLinus Torvalds if(ptr) {
10411da177e4SLinus Torvalds HOSTDATA(shpnt)->commands--;
10421da177e4SLinus Torvalds if (!HOSTDATA(shpnt)->commands)
10431da177e4SLinus Torvalds SETPORT(PORTA, 0);
10441da177e4SLinus Torvalds DO_UNLOCK(flags);
10451da177e4SLinus Torvalds
10461da177e4SLinus Torvalds kfree(SCpnt->host_scribble);
10471da177e4SLinus Torvalds SCpnt->host_scribble=NULL;
10481da177e4SLinus Torvalds
10491da177e4SLinus Torvalds return SUCCESS;
10501da177e4SLinus Torvalds }
10511da177e4SLinus Torvalds
10521da177e4SLinus Torvalds DO_UNLOCK(flags);
10531da177e4SLinus Torvalds
10541da177e4SLinus Torvalds /*
10551da177e4SLinus Torvalds * FIXME:
10561da177e4SLinus Torvalds * for current command: queue ABORT for message out and raise ATN
10571da177e4SLinus Torvalds * for disconnected command: pseudo SC with ABORT message or ABORT on reselection?
10581da177e4SLinus Torvalds *
10591da177e4SLinus Torvalds */
10601da177e4SLinus Torvalds
1061f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, SCpnt,
1062f75ae8edSHannes Reinecke "cannot abort running or disconnected command\n");
10631da177e4SLinus Torvalds
10641da177e4SLinus Torvalds return FAILED;
10651da177e4SLinus Torvalds }
10661da177e4SLinus Torvalds
10671da177e4SLinus Torvalds /*
10681da177e4SLinus Torvalds * Reset a device
10691da177e4SLinus Torvalds *
10701da177e4SLinus Torvalds */
aha152x_device_reset(struct scsi_cmnd * SCpnt)107191ebc1faSJohannes Thumshirn static int aha152x_device_reset(struct scsi_cmnd * SCpnt)
10721da177e4SLinus Torvalds {
10731da177e4SLinus Torvalds struct Scsi_Host *shpnt = SCpnt->device->host;
10740f06bb34SChristoph Hellwig DECLARE_COMPLETION(done);
10751da177e4SLinus Torvalds int ret, issued, disconnected;
1076631c228cSChristoph Hellwig unsigned char old_cmd_len = SCpnt->cmd_len;
10771da177e4SLinus Torvalds unsigned long flags;
10780f06bb34SChristoph Hellwig unsigned long timeleft;
10791da177e4SLinus Torvalds
10801da177e4SLinus Torvalds if(CURRENT_SC==SCpnt) {
1081f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, SCpnt, "cannot reset current device\n");
10821da177e4SLinus Torvalds return FAILED;
10831da177e4SLinus Torvalds }
10841da177e4SLinus Torvalds
10851da177e4SLinus Torvalds DO_LOCK(flags);
1086172c122dSHarvey Harrison issued = remove_SC(&ISSUE_SC, SCpnt) == NULL;
10871da177e4SLinus Torvalds disconnected = issued && remove_SC(&DISCONNECTED_SC, SCpnt);
10881da177e4SLinus Torvalds DO_UNLOCK(flags);
10891da177e4SLinus Torvalds
10901da177e4SLinus Torvalds SCpnt->cmd_len = 0;
10911da177e4SLinus Torvalds
10923ab3b151SBart Van Assche aha152x_internal_queue(SCpnt, &done, resetting);
10931da177e4SLinus Torvalds
10940f06bb34SChristoph Hellwig timeleft = wait_for_completion_timeout(&done, 100*HZ);
10950f06bb34SChristoph Hellwig if (!timeleft) {
10960f06bb34SChristoph Hellwig /* remove command from issue queue */
10970f06bb34SChristoph Hellwig DO_LOCK(flags);
10980f06bb34SChristoph Hellwig remove_SC(&ISSUE_SC, SCpnt);
10990f06bb34SChristoph Hellwig DO_UNLOCK(flags);
11000f06bb34SChristoph Hellwig }
11011da177e4SLinus Torvalds
1102631c228cSChristoph Hellwig SCpnt->cmd_len = old_cmd_len;
11031da177e4SLinus Torvalds
11041da177e4SLinus Torvalds DO_LOCK(flags);
11051da177e4SLinus Torvalds
110663221571SFinn Thain if (aha152x_priv(SCpnt)->phase & resetted) {
11071da177e4SLinus Torvalds HOSTDATA(shpnt)->commands--;
11081da177e4SLinus Torvalds if (!HOSTDATA(shpnt)->commands)
11091da177e4SLinus Torvalds SETPORT(PORTA, 0);
11101da177e4SLinus Torvalds kfree(SCpnt->host_scribble);
11111da177e4SLinus Torvalds SCpnt->host_scribble=NULL;
11121da177e4SLinus Torvalds
11131da177e4SLinus Torvalds ret = SUCCESS;
11141da177e4SLinus Torvalds } else {
11151da177e4SLinus Torvalds /* requeue */
11161da177e4SLinus Torvalds if(!issued) {
11171da177e4SLinus Torvalds append_SC(&ISSUE_SC, SCpnt);
11181da177e4SLinus Torvalds } else if(disconnected) {
11191da177e4SLinus Torvalds append_SC(&DISCONNECTED_SC, SCpnt);
11201da177e4SLinus Torvalds }
11211da177e4SLinus Torvalds
11221da177e4SLinus Torvalds ret = FAILED;
11231da177e4SLinus Torvalds }
11241da177e4SLinus Torvalds
11251da177e4SLinus Torvalds DO_UNLOCK(flags);
11261da177e4SLinus Torvalds return ret;
11271da177e4SLinus Torvalds }
11281da177e4SLinus Torvalds
free_hard_reset_SCs(struct Scsi_Host * shpnt,struct scsi_cmnd ** SCs)112991ebc1faSJohannes Thumshirn static void free_hard_reset_SCs(struct Scsi_Host *shpnt,
113091ebc1faSJohannes Thumshirn struct scsi_cmnd **SCs)
11311da177e4SLinus Torvalds {
113291ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr;
11331da177e4SLinus Torvalds
11341da177e4SLinus Torvalds ptr=*SCs;
11351da177e4SLinus Torvalds while(ptr) {
113691ebc1faSJohannes Thumshirn struct scsi_cmnd *next;
11371da177e4SLinus Torvalds
11381da177e4SLinus Torvalds if(SCDATA(ptr)) {
11391da177e4SLinus Torvalds next = SCNEXT(ptr);
11401da177e4SLinus Torvalds } else {
1141f75ae8edSHannes Reinecke scmd_printk(KERN_DEBUG, ptr,
1142f75ae8edSHannes Reinecke "queue corrupted at %p\n", ptr);
11431da177e4SLinus Torvalds next = NULL;
11441da177e4SLinus Torvalds }
11451da177e4SLinus Torvalds
11461da177e4SLinus Torvalds if (!ptr->device->soft_reset) {
11471da177e4SLinus Torvalds remove_SC(SCs, ptr);
11481da177e4SLinus Torvalds HOSTDATA(shpnt)->commands--;
11491da177e4SLinus Torvalds kfree(ptr->host_scribble);
11501da177e4SLinus Torvalds ptr->host_scribble=NULL;
11511da177e4SLinus Torvalds }
11521da177e4SLinus Torvalds
11531da177e4SLinus Torvalds ptr = next;
11541da177e4SLinus Torvalds }
11551da177e4SLinus Torvalds }
11561da177e4SLinus Torvalds
11571da177e4SLinus Torvalds /*
11581da177e4SLinus Torvalds * Reset the bus
11591da177e4SLinus Torvalds *
1160819f80c9SHannes Reinecke * AIC-6260 has a hard reset (MRST signal), but apparently
1161819f80c9SHannes Reinecke * one cannot trigger it via software. So live with
1162819f80c9SHannes Reinecke * a soft reset; no-one seemed to have cared.
11631da177e4SLinus Torvalds */
aha152x_bus_reset_host(struct Scsi_Host * shpnt)1164e2482fa1SJürgen E. Fischer static int aha152x_bus_reset_host(struct Scsi_Host *shpnt)
11651da177e4SLinus Torvalds {
11661da177e4SLinus Torvalds unsigned long flags;
11671da177e4SLinus Torvalds
11681da177e4SLinus Torvalds DO_LOCK(flags);
11691da177e4SLinus Torvalds
11701da177e4SLinus Torvalds free_hard_reset_SCs(shpnt, &ISSUE_SC);
11711da177e4SLinus Torvalds free_hard_reset_SCs(shpnt, &DISCONNECTED_SC);
11721da177e4SLinus Torvalds
11731da177e4SLinus Torvalds SETPORT(SCSISEQ, SCSIRSTO);
11741da177e4SLinus Torvalds mdelay(256);
11751da177e4SLinus Torvalds SETPORT(SCSISEQ, 0);
11761da177e4SLinus Torvalds mdelay(DELAY);
11771da177e4SLinus Torvalds
11781da177e4SLinus Torvalds setup_expected_interrupts(shpnt);
11791da177e4SLinus Torvalds if(HOSTDATA(shpnt)->commands==0)
11801da177e4SLinus Torvalds SETPORT(PORTA, 0);
11811da177e4SLinus Torvalds
11821da177e4SLinus Torvalds DO_UNLOCK(flags);
11831da177e4SLinus Torvalds
11841da177e4SLinus Torvalds return SUCCESS;
11851da177e4SLinus Torvalds }
11861da177e4SLinus Torvalds
1187e2482fa1SJürgen E. Fischer /*
1188e2482fa1SJürgen E. Fischer * Reset the bus
1189e2482fa1SJürgen E. Fischer *
1190e2482fa1SJürgen E. Fischer */
aha152x_bus_reset(struct scsi_cmnd * SCpnt)119191ebc1faSJohannes Thumshirn static int aha152x_bus_reset(struct scsi_cmnd *SCpnt)
1192e2482fa1SJürgen E. Fischer {
1193e2482fa1SJürgen E. Fischer return aha152x_bus_reset_host(SCpnt->device->host);
1194e2482fa1SJürgen E. Fischer }
11951da177e4SLinus Torvalds
11961da177e4SLinus Torvalds /*
11971da177e4SLinus Torvalds * Restore default values to the AIC-6260 registers and reset the fifos
11981da177e4SLinus Torvalds *
11991da177e4SLinus Torvalds */
reset_ports(struct Scsi_Host * shpnt)12001da177e4SLinus Torvalds static void reset_ports(struct Scsi_Host *shpnt)
12011da177e4SLinus Torvalds {
12021da177e4SLinus Torvalds unsigned long flags;
12031da177e4SLinus Torvalds
12041da177e4SLinus Torvalds /* disable interrupts */
12051da177e4SLinus Torvalds SETPORT(DMACNTRL0, RSTFIFO);
12061da177e4SLinus Torvalds
12071da177e4SLinus Torvalds SETPORT(SCSISEQ, 0);
12081da177e4SLinus Torvalds
12091da177e4SLinus Torvalds SETPORT(SXFRCTL1, 0);
12101da177e4SLinus Torvalds SETPORT(SCSISIG, 0);
12111da177e4SLinus Torvalds SETRATE(0);
12121da177e4SLinus Torvalds
12131da177e4SLinus Torvalds /* clear all interrupt conditions */
12141da177e4SLinus Torvalds SETPORT(SSTAT0, 0x7f);
12151da177e4SLinus Torvalds SETPORT(SSTAT1, 0xef);
12161da177e4SLinus Torvalds
12171da177e4SLinus Torvalds SETPORT(SSTAT4, SYNCERR | FWERR | FRERR);
12181da177e4SLinus Torvalds
12191da177e4SLinus Torvalds SETPORT(DMACNTRL0, 0);
12201da177e4SLinus Torvalds SETPORT(DMACNTRL1, 0);
12211da177e4SLinus Torvalds
12221da177e4SLinus Torvalds SETPORT(BRSTCNTRL, 0xf1);
12231da177e4SLinus Torvalds
12241da177e4SLinus Torvalds /* clear SCSI fifos and transfer count */
12251da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
12261da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1);
12271da177e4SLinus Torvalds
12281da177e4SLinus Torvalds DO_LOCK(flags);
12291da177e4SLinus Torvalds setup_expected_interrupts(shpnt);
12301da177e4SLinus Torvalds DO_UNLOCK(flags);
12311da177e4SLinus Torvalds }
12321da177e4SLinus Torvalds
12331da177e4SLinus Torvalds /*
12341da177e4SLinus Torvalds * Reset the host (bus and controller)
12351da177e4SLinus Torvalds *
12361da177e4SLinus Torvalds */
aha152x_host_reset_host(struct Scsi_Host * shpnt)1237e2482fa1SJürgen E. Fischer int aha152x_host_reset_host(struct Scsi_Host *shpnt)
12381da177e4SLinus Torvalds {
1239e2482fa1SJürgen E. Fischer aha152x_bus_reset_host(shpnt);
1240e2482fa1SJürgen E. Fischer reset_ports(shpnt);
12411da177e4SLinus Torvalds
12421da177e4SLinus Torvalds return SUCCESS;
12431da177e4SLinus Torvalds }
12441da177e4SLinus Torvalds
12451da177e4SLinus Torvalds /*
12461da177e4SLinus Torvalds * Return the "logical geometry"
12471da177e4SLinus Torvalds *
12481da177e4SLinus Torvalds */
aha152x_biosparam(struct scsi_device * sdev,struct block_device * bdev,sector_t capacity,int * info_array)12491da177e4SLinus Torvalds static int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev,
12501da177e4SLinus Torvalds sector_t capacity, int *info_array)
12511da177e4SLinus Torvalds {
12521da177e4SLinus Torvalds struct Scsi_Host *shpnt = sdev->host;
12531da177e4SLinus Torvalds
12541da177e4SLinus Torvalds /* try default translation */
12551da177e4SLinus Torvalds info_array[0] = 64;
12561da177e4SLinus Torvalds info_array[1] = 32;
12571da177e4SLinus Torvalds info_array[2] = (unsigned long)capacity / (64 * 32);
12581da177e4SLinus Torvalds
12591da177e4SLinus Torvalds /* for disks >1GB do some guessing */
12601da177e4SLinus Torvalds if (info_array[2] >= 1024) {
12611da177e4SLinus Torvalds int info[3];
12621da177e4SLinus Torvalds
12631da177e4SLinus Torvalds /* try to figure out the geometry from the partition table */
12641da177e4SLinus Torvalds if (scsicam_bios_param(bdev, capacity, info) < 0 ||
12651da177e4SLinus Torvalds !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) {
12661da177e4SLinus Torvalds if (EXT_TRANS) {
12671da177e4SLinus Torvalds printk(KERN_NOTICE
12681da177e4SLinus Torvalds "aha152x: unable to verify geometry for disk with >1GB.\n"
12691da177e4SLinus Torvalds " using extended translation.\n");
12701da177e4SLinus Torvalds info_array[0] = 255;
12711da177e4SLinus Torvalds info_array[1] = 63;
12721da177e4SLinus Torvalds info_array[2] = (unsigned long)capacity / (255 * 63);
12731da177e4SLinus Torvalds } else {
12741da177e4SLinus Torvalds printk(KERN_NOTICE
12751da177e4SLinus Torvalds "aha152x: unable to verify geometry for disk with >1GB.\n"
12761da177e4SLinus Torvalds " Using default translation. Please verify yourself.\n"
12771da177e4SLinus Torvalds " Perhaps you need to enable extended translation in the driver.\n"
127894b5530fSMauro Carvalho Chehab " See Documentation/scsi/aha152x.rst for details.\n");
12791da177e4SLinus Torvalds }
12801da177e4SLinus Torvalds } else {
12811da177e4SLinus Torvalds info_array[0] = info[0];
12821da177e4SLinus Torvalds info_array[1] = info[1];
12831da177e4SLinus Torvalds info_array[2] = info[2];
12841da177e4SLinus Torvalds
12851da177e4SLinus Torvalds if (info[0] == 255 && !EXT_TRANS) {
12861da177e4SLinus Torvalds printk(KERN_NOTICE
12871da177e4SLinus Torvalds "aha152x: current partition table is using extended translation.\n"
12881da177e4SLinus Torvalds " using it also, although it's not explicitly enabled.\n");
12891da177e4SLinus Torvalds }
12901da177e4SLinus Torvalds }
12911da177e4SLinus Torvalds }
12921da177e4SLinus Torvalds
12931da177e4SLinus Torvalds return 0;
12941da177e4SLinus Torvalds }
12951da177e4SLinus Torvalds
12961da177e4SLinus Torvalds /*
12971da177e4SLinus Torvalds * Internal done function
12981da177e4SLinus Torvalds *
12991da177e4SLinus Torvalds */
done(struct Scsi_Host * shpnt,unsigned char status_byte,unsigned char host_byte)1300aec166fdSHannes Reinecke static void done(struct Scsi_Host *shpnt, unsigned char status_byte,
1301fdabe57dSHannes Reinecke unsigned char host_byte)
13021da177e4SLinus Torvalds {
13031da177e4SLinus Torvalds if (CURRENT_SC) {
13041da177e4SLinus Torvalds if(DONE_SC)
1305f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC,
1306f75ae8edSHannes Reinecke "there's already a completed command %p "
1307f75ae8edSHannes Reinecke "- will cause abort\n", DONE_SC);
13081da177e4SLinus Torvalds
13091da177e4SLinus Torvalds DONE_SC = CURRENT_SC;
13101da177e4SLinus Torvalds CURRENT_SC = NULL;
1311fdabe57dSHannes Reinecke set_status_byte(DONE_SC, status_byte);
1312aec166fdSHannes Reinecke set_host_byte(DONE_SC, host_byte);
13131da177e4SLinus Torvalds } else
13141da177e4SLinus Torvalds printk(KERN_ERR "aha152x: done() called outside of command\n");
13151da177e4SLinus Torvalds }
13161da177e4SLinus Torvalds
13171da177e4SLinus Torvalds static struct work_struct aha152x_tq;
13181da177e4SLinus Torvalds
13191da177e4SLinus Torvalds /*
13201da177e4SLinus Torvalds * Run service completions on the card with interrupts enabled.
13211da177e4SLinus Torvalds *
13221da177e4SLinus Torvalds */
run(struct work_struct * work)1323c4028958SDavid Howells static void run(struct work_struct *work)
13241da177e4SLinus Torvalds {
13255fcda422SJames Bottomley struct aha152x_hostdata *hd;
13265fcda422SJames Bottomley
13275fcda422SJames Bottomley list_for_each_entry(hd, &aha152x_host_list, host_list) {
13285fcda422SJames Bottomley struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
13295fcda422SJames Bottomley
13305fcda422SJames Bottomley is_complete(shost);
13311da177e4SLinus Torvalds }
13321da177e4SLinus Torvalds }
13331da177e4SLinus Torvalds
13341da177e4SLinus Torvalds /*
1335e2482fa1SJürgen E. Fischer * Interrupt handler
13361da177e4SLinus Torvalds *
13371da177e4SLinus Torvalds */
intr(int irqno,void * dev_id)13387d12e780SDavid Howells static irqreturn_t intr(int irqno, void *dev_id)
13391da177e4SLinus Torvalds {
1340e19166d5SJeff Garzik struct Scsi_Host *shpnt = dev_id;
1341e2482fa1SJürgen E. Fischer unsigned long flags;
13421da177e4SLinus Torvalds unsigned char rev, dmacntrl0;
13431da177e4SLinus Torvalds
13441da177e4SLinus Torvalds /*
13451da177e4SLinus Torvalds * Read a couple of registers that are known to not be all 1's. If
13461da177e4SLinus Torvalds * we read all 1's (-1), that means that either:
13471da177e4SLinus Torvalds *
13481da177e4SLinus Torvalds * a. The host adapter chip has gone bad, and we cannot control it,
13491da177e4SLinus Torvalds * OR
13501da177e4SLinus Torvalds * b. The host adapter is a PCMCIA card that has been ejected
13511da177e4SLinus Torvalds *
13521da177e4SLinus Torvalds * In either case, we cannot do anything with the host adapter at
13531da177e4SLinus Torvalds * this point in time. So just ignore the interrupt and return.
13541da177e4SLinus Torvalds * In the latter case, the interrupt might actually be meant for
13551da177e4SLinus Torvalds * someone else sharing this IRQ, and that driver will handle it.
13561da177e4SLinus Torvalds */
13571da177e4SLinus Torvalds rev = GETPORT(REV);
13581da177e4SLinus Torvalds dmacntrl0 = GETPORT(DMACNTRL0);
13591da177e4SLinus Torvalds if ((rev == 0xFF) && (dmacntrl0 == 0xFF))
13601da177e4SLinus Torvalds return IRQ_NONE;
13611da177e4SLinus Torvalds
1362e2482fa1SJürgen E. Fischer if( TESTLO(DMASTAT, INTSTAT) )
1363e2482fa1SJürgen E. Fischer return IRQ_NONE;
1364e2482fa1SJürgen E. Fischer
13651da177e4SLinus Torvalds /* no more interrupts from the controller, while we're busy.
13661da177e4SLinus Torvalds INTEN is restored by the BH handler */
13671da177e4SLinus Torvalds CLRBITS(DMACNTRL0, INTEN);
13681da177e4SLinus Torvalds
1369e2482fa1SJürgen E. Fischer DO_LOCK(flags);
1370e2482fa1SJürgen E. Fischer if( HOSTDATA(shpnt)->service==0 ) {
1371e2482fa1SJürgen E. Fischer HOSTDATA(shpnt)->service=1;
13721da177e4SLinus Torvalds
13731da177e4SLinus Torvalds /* Poke the BH handler */
1374c4028958SDavid Howells INIT_WORK(&aha152x_tq, run);
13751da177e4SLinus Torvalds schedule_work(&aha152x_tq);
1376e2482fa1SJürgen E. Fischer }
1377e2482fa1SJürgen E. Fischer DO_UNLOCK(flags);
1378e2482fa1SJürgen E. Fischer
13791da177e4SLinus Torvalds return IRQ_HANDLED;
13801da177e4SLinus Torvalds }
13811da177e4SLinus Torvalds
13821da177e4SLinus Torvalds /*
13831da177e4SLinus Torvalds * busfree phase
13841da177e4SLinus Torvalds * - handle completition/disconnection/error of current command
13851da177e4SLinus Torvalds * - start selection for next command (if any)
13861da177e4SLinus Torvalds */
busfree_run(struct Scsi_Host * shpnt)13871da177e4SLinus Torvalds static void busfree_run(struct Scsi_Host *shpnt)
13881da177e4SLinus Torvalds {
13891da177e4SLinus Torvalds unsigned long flags;
13901da177e4SLinus Torvalds #if defined(AHA152X_STAT)
13911da177e4SLinus Torvalds int action=0;
13921da177e4SLinus Torvalds #endif
13931da177e4SLinus Torvalds
13941da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
13951da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1);
13961da177e4SLinus Torvalds
13971da177e4SLinus Torvalds SETPORT(SSTAT1, CLRBUSFREE);
13981da177e4SLinus Torvalds
13991da177e4SLinus Torvalds if(CURRENT_SC) {
140063221571SFinn Thain struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
14013ac6aba3SBart Van Assche
14021da177e4SLinus Torvalds #if defined(AHA152X_STAT)
14031da177e4SLinus Torvalds action++;
14041da177e4SLinus Torvalds #endif
140563221571SFinn Thain acp->phase &= ~syncneg;
14061da177e4SLinus Torvalds
140763221571SFinn Thain if (acp->phase & completed) {
14081da177e4SLinus Torvalds /* target sent COMMAND COMPLETE */
140963221571SFinn Thain done(shpnt, acp->status, DID_OK);
14101da177e4SLinus Torvalds
141163221571SFinn Thain } else if (acp->phase & aborted) {
141263221571SFinn Thain done(shpnt, acp->status, DID_ABORT);
14131da177e4SLinus Torvalds
141463221571SFinn Thain } else if (acp->phase & resetted) {
141563221571SFinn Thain done(shpnt, acp->status, DID_RESET);
14161da177e4SLinus Torvalds
141763221571SFinn Thain } else if (acp->phase & disconnected) {
14181da177e4SLinus Torvalds /* target sent DISCONNECT */
14191da177e4SLinus Torvalds #if defined(AHA152X_STAT)
14201da177e4SLinus Torvalds HOSTDATA(shpnt)->disconnections++;
14211da177e4SLinus Torvalds #endif
14221da177e4SLinus Torvalds append_SC(&DISCONNECTED_SC, CURRENT_SC);
142363221571SFinn Thain acp->phase |= 1 << 16;
14241da177e4SLinus Torvalds CURRENT_SC = NULL;
14251da177e4SLinus Torvalds
14261da177e4SLinus Torvalds } else {
1427fdabe57dSHannes Reinecke done(shpnt, SAM_STAT_GOOD, DID_ERROR);
14281da177e4SLinus Torvalds }
14291da177e4SLinus Torvalds #if defined(AHA152X_STAT)
14301da177e4SLinus Torvalds } else {
14311da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_old_command++;
14321da177e4SLinus Torvalds #endif
14331da177e4SLinus Torvalds }
14341da177e4SLinus Torvalds
14351da177e4SLinus Torvalds DO_LOCK(flags);
14361da177e4SLinus Torvalds
14371da177e4SLinus Torvalds if(DONE_SC) {
14381da177e4SLinus Torvalds #if defined(AHA152X_STAT)
14391da177e4SLinus Torvalds action++;
14401da177e4SLinus Torvalds #endif
14411da177e4SLinus Torvalds
144263221571SFinn Thain if (aha152x_priv(DONE_SC)->phase & check_condition) {
14435e13cdfaSChristoph Hellwig struct scsi_cmnd *cmd = HOSTDATA(shpnt)->done_SC;
14445e13cdfaSChristoph Hellwig struct aha152x_scdata *sc = SCDATA(cmd);
14455e13cdfaSChristoph Hellwig
144673d2cb16SBoaz Harrosh scsi_eh_restore_cmnd(cmd, &sc->ses);
14471da177e4SLinus Torvalds
144863221571SFinn Thain aha152x_priv(cmd)->status = SAM_STAT_CHECK_CONDITION;
14491da177e4SLinus Torvalds
14501da177e4SLinus Torvalds HOSTDATA(shpnt)->commands--;
14511da177e4SLinus Torvalds if (!HOSTDATA(shpnt)->commands)
14521da177e4SLinus Torvalds SETPORT(PORTA, 0); /* turn led off */
145363221571SFinn Thain } else if (aha152x_priv(DONE_SC)->status == SAM_STAT_CHECK_CONDITION) {
14541da177e4SLinus Torvalds #if defined(AHA152X_STAT)
14551da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_with_check_condition++;
14561da177e4SLinus Torvalds #endif
14571da177e4SLinus Torvalds
145863221571SFinn Thain if (!(aha152x_priv(DONE_SC)->phase & not_issued)) {
145945333ffaSBoaz Harrosh struct aha152x_scdata *sc;
146091ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr = DONE_SC;
14611da177e4SLinus Torvalds DONE_SC=NULL;
14621da177e4SLinus Torvalds
146345333ffaSBoaz Harrosh sc = SCDATA(ptr);
146445333ffaSBoaz Harrosh /* It was allocated in aha152x_internal_queue? */
146545333ffaSBoaz Harrosh BUG_ON(!sc);
146673d2cb16SBoaz Harrosh scsi_eh_prep_cmnd(ptr, &sc->ses, NULL, 0, ~0);
14671da177e4SLinus Torvalds
14681da177e4SLinus Torvalds DO_UNLOCK(flags);
14693ab3b151SBart Van Assche aha152x_internal_queue(ptr, NULL, check_condition);
14701da177e4SLinus Torvalds DO_LOCK(flags);
14711da177e4SLinus Torvalds }
14721da177e4SLinus Torvalds }
14731da177e4SLinus Torvalds
14743ab3b151SBart Van Assche if (DONE_SC) {
147591ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr = DONE_SC;
14761da177e4SLinus Torvalds DONE_SC=NULL;
14771da177e4SLinus Torvalds
14781da177e4SLinus Torvalds /* turn led off, when no commands are in the driver */
14791da177e4SLinus Torvalds HOSTDATA(shpnt)->commands--;
14801da177e4SLinus Torvalds if (!HOSTDATA(shpnt)->commands)
14811da177e4SLinus Torvalds SETPORT(PORTA, 0); /* turn led off */
14821da177e4SLinus Torvalds
148363221571SFinn Thain if (!(aha152x_priv(ptr)->phase & resetting)) {
14841da177e4SLinus Torvalds kfree(ptr->host_scribble);
14851da177e4SLinus Torvalds ptr->host_scribble=NULL;
14861da177e4SLinus Torvalds }
14871da177e4SLinus Torvalds
14881da177e4SLinus Torvalds DO_UNLOCK(flags);
14893ab3b151SBart Van Assche aha152x_scsi_done(ptr);
14901da177e4SLinus Torvalds DO_LOCK(flags);
14911da177e4SLinus Torvalds }
14921da177e4SLinus Torvalds
14931da177e4SLinus Torvalds DONE_SC=NULL;
14941da177e4SLinus Torvalds #if defined(AHA152X_STAT)
14951da177e4SLinus Torvalds } else {
14961da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_done_command++;
14971da177e4SLinus Torvalds #endif
14981da177e4SLinus Torvalds }
14991da177e4SLinus Torvalds
15001da177e4SLinus Torvalds if(ISSUE_SC)
15011da177e4SLinus Torvalds CURRENT_SC = remove_first_SC(&ISSUE_SC);
15021da177e4SLinus Torvalds
15031da177e4SLinus Torvalds DO_UNLOCK(flags);
15041da177e4SLinus Torvalds
15051da177e4SLinus Torvalds if(CURRENT_SC) {
150663221571SFinn Thain struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
15073ac6aba3SBart Van Assche
15081da177e4SLinus Torvalds #if defined(AHA152X_STAT)
15091da177e4SLinus Torvalds action++;
15101da177e4SLinus Torvalds #endif
151163221571SFinn Thain acp->phase |= selecting;
15121da177e4SLinus Torvalds
15131da177e4SLinus Torvalds /* clear selection timeout */
15141da177e4SLinus Torvalds SETPORT(SSTAT1, SELTO);
15151da177e4SLinus Torvalds
15161da177e4SLinus Torvalds SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->device->id);
15171da177e4SLinus Torvalds SETPORT(SXFRCTL1, (PARITY ? ENSPCHK : 0 ) | ENSTIMER);
15181da177e4SLinus Torvalds SETPORT(SCSISEQ, ENSELO | ENAUTOATNO | (DISCONNECTED_SC ? ENRESELI : 0));
15191da177e4SLinus Torvalds } else {
15201da177e4SLinus Torvalds #if defined(AHA152X_STAT)
15211da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_new_command++;
15221da177e4SLinus Torvalds #endif
15231da177e4SLinus Torvalds SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
15241da177e4SLinus Torvalds }
15251da177e4SLinus Torvalds
15261da177e4SLinus Torvalds #if defined(AHA152X_STAT)
15271da177e4SLinus Torvalds if(!action)
15281da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_any_action++;
15291da177e4SLinus Torvalds #endif
15301da177e4SLinus Torvalds }
15311da177e4SLinus Torvalds
15321da177e4SLinus Torvalds /*
15331da177e4SLinus Torvalds * Selection done (OUT)
15341da177e4SLinus Torvalds * - queue IDENTIFY message and SDTR to selected target for message out
15351da177e4SLinus Torvalds * (ATN asserted automagically via ENAUTOATNO in busfree())
15361da177e4SLinus Torvalds */
seldo_run(struct Scsi_Host * shpnt)15371da177e4SLinus Torvalds static void seldo_run(struct Scsi_Host *shpnt)
15381da177e4SLinus Torvalds {
153963221571SFinn Thain struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
15403ac6aba3SBart Van Assche
15411da177e4SLinus Torvalds SETPORT(SCSISIG, 0);
15421da177e4SLinus Torvalds SETPORT(SSTAT1, CLRBUSFREE);
15431da177e4SLinus Torvalds SETPORT(SSTAT1, CLRPHASECHG);
15441da177e4SLinus Torvalds
154563221571SFinn Thain acp->phase &= ~(selecting | not_issued);
15461da177e4SLinus Torvalds
15471da177e4SLinus Torvalds SETPORT(SCSISEQ, 0);
15481da177e4SLinus Torvalds
15491da177e4SLinus Torvalds if (TESTLO(SSTAT0, SELDO)) {
1550f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC,
1551f75ae8edSHannes Reinecke "aha152x: passing bus free condition\n");
1552fdabe57dSHannes Reinecke done(shpnt, SAM_STAT_GOOD, DID_NO_CONNECT);
15531da177e4SLinus Torvalds return;
15541da177e4SLinus Torvalds }
15551da177e4SLinus Torvalds
15561da177e4SLinus Torvalds SETPORT(SSTAT0, CLRSELDO);
15571da177e4SLinus Torvalds
15581da177e4SLinus Torvalds ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
15591da177e4SLinus Torvalds
156063221571SFinn Thain if (acp->phase & aborting) {
15611da177e4SLinus Torvalds ADDMSGO(ABORT);
156263221571SFinn Thain } else if (acp->phase & resetting) {
15631da177e4SLinus Torvalds ADDMSGO(BUS_DEVICE_RESET);
15641da177e4SLinus Torvalds } else if (SYNCNEG==0 && SYNCHRONOUS) {
156563221571SFinn Thain acp->phase |= syncneg;
15666ea3c0b2SMatthew Wilcox MSGOLEN += spi_populate_sync_msg(&MSGO(MSGOLEN), 50, 8);
15671da177e4SLinus Torvalds SYNCNEG=1; /* negotiation in progress */
15681da177e4SLinus Torvalds }
15691da177e4SLinus Torvalds
15701da177e4SLinus Torvalds SETRATE(SYNCRATE);
15711da177e4SLinus Torvalds }
15721da177e4SLinus Torvalds
15731da177e4SLinus Torvalds /*
15741da177e4SLinus Torvalds * Selection timeout
15751da177e4SLinus Torvalds * - return command to mid-level with failure cause
15761da177e4SLinus Torvalds *
15771da177e4SLinus Torvalds */
selto_run(struct Scsi_Host * shpnt)15781da177e4SLinus Torvalds static void selto_run(struct Scsi_Host *shpnt)
15791da177e4SLinus Torvalds {
158063221571SFinn Thain struct aha152x_cmd_priv *acp;
15813ac6aba3SBart Van Assche
15821da177e4SLinus Torvalds SETPORT(SCSISEQ, 0);
15831da177e4SLinus Torvalds SETPORT(SSTAT1, CLRSELTIMO);
15841da177e4SLinus Torvalds
1585f75ae8edSHannes Reinecke if (!CURRENT_SC)
15861da177e4SLinus Torvalds return;
15871da177e4SLinus Torvalds
158863221571SFinn Thain acp = aha152x_priv(CURRENT_SC);
158963221571SFinn Thain acp->phase &= ~selecting;
15901da177e4SLinus Torvalds
159163221571SFinn Thain if (acp->phase & aborted)
1592fdabe57dSHannes Reinecke done(shpnt, SAM_STAT_GOOD, DID_ABORT);
1593f75ae8edSHannes Reinecke else if (TESTLO(SSTAT0, SELINGO))
1594fdabe57dSHannes Reinecke done(shpnt, SAM_STAT_GOOD, DID_BUS_BUSY);
1595f75ae8edSHannes Reinecke else
15961da177e4SLinus Torvalds /* ARBITRATION won, but SELECTION failed */
1597fdabe57dSHannes Reinecke done(shpnt, SAM_STAT_GOOD, DID_NO_CONNECT);
15981da177e4SLinus Torvalds }
15991da177e4SLinus Torvalds
16001da177e4SLinus Torvalds /*
16011da177e4SLinus Torvalds * Selection in done
16021da177e4SLinus Torvalds * - put current command back to issue queue
16031da177e4SLinus Torvalds * (reconnection of a disconnected nexus instead
16041da177e4SLinus Torvalds * of successful selection out)
16051da177e4SLinus Torvalds *
16061da177e4SLinus Torvalds */
seldi_run(struct Scsi_Host * shpnt)16071da177e4SLinus Torvalds static void seldi_run(struct Scsi_Host *shpnt)
16081da177e4SLinus Torvalds {
16091da177e4SLinus Torvalds int selid;
16101da177e4SLinus Torvalds int target;
16111da177e4SLinus Torvalds unsigned long flags;
16121da177e4SLinus Torvalds
16131da177e4SLinus Torvalds SETPORT(SCSISIG, 0);
16141da177e4SLinus Torvalds SETPORT(SSTAT0, CLRSELDI);
16151da177e4SLinus Torvalds SETPORT(SSTAT1, CLRBUSFREE);
16161da177e4SLinus Torvalds SETPORT(SSTAT1, CLRPHASECHG);
16171da177e4SLinus Torvalds
16181da177e4SLinus Torvalds if(CURRENT_SC) {
161963221571SFinn Thain struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
16203ac6aba3SBart Van Assche
162163221571SFinn Thain if (!(acp->phase & not_issued))
1622f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC,
1623f75ae8edSHannes Reinecke "command should not have been issued yet\n");
16241da177e4SLinus Torvalds
16251da177e4SLinus Torvalds DO_LOCK(flags);
16261da177e4SLinus Torvalds append_SC(&ISSUE_SC, CURRENT_SC);
16271da177e4SLinus Torvalds DO_UNLOCK(flags);
16281da177e4SLinus Torvalds
16291da177e4SLinus Torvalds CURRENT_SC = NULL;
16301da177e4SLinus Torvalds }
16311da177e4SLinus Torvalds
1632f75ae8edSHannes Reinecke if (!DISCONNECTED_SC)
16331da177e4SLinus Torvalds return;
16341da177e4SLinus Torvalds
16351da177e4SLinus Torvalds RECONN_TARGET=-1;
16361da177e4SLinus Torvalds
16371da177e4SLinus Torvalds selid = GETPORT(SELID) & ~(1 << shpnt->this_id);
16381da177e4SLinus Torvalds
16391da177e4SLinus Torvalds if (selid==0) {
1640f75ae8edSHannes Reinecke shost_printk(KERN_INFO, shpnt,
1641f75ae8edSHannes Reinecke "target id unknown (%02x)\n", selid);
16421da177e4SLinus Torvalds return;
16431da177e4SLinus Torvalds }
16441da177e4SLinus Torvalds
16451da177e4SLinus Torvalds for(target=7; !(selid & (1 << target)); target--)
16461da177e4SLinus Torvalds ;
16471da177e4SLinus Torvalds
16481da177e4SLinus Torvalds if(selid & ~(1 << target)) {
1649f75ae8edSHannes Reinecke shost_printk(KERN_INFO, shpnt,
1650f75ae8edSHannes Reinecke "multiple targets reconnected (%02x)\n", selid);
16511da177e4SLinus Torvalds }
16521da177e4SLinus Torvalds
16531da177e4SLinus Torvalds
16541da177e4SLinus Torvalds SETPORT(SCSIID, (shpnt->this_id << OID_) | target);
16551da177e4SLinus Torvalds SETPORT(SCSISEQ, 0);
16561da177e4SLinus Torvalds
16571da177e4SLinus Torvalds SETRATE(HOSTDATA(shpnt)->syncrate[target]);
16581da177e4SLinus Torvalds
16591da177e4SLinus Torvalds RECONN_TARGET=target;
16601da177e4SLinus Torvalds }
16611da177e4SLinus Torvalds
16621da177e4SLinus Torvalds /*
16631da177e4SLinus Torvalds * message in phase
16641da177e4SLinus Torvalds * - handle initial message after reconnection to identify
16651da177e4SLinus Torvalds * reconnecting nexus
16661da177e4SLinus Torvalds * - queue command on DISCONNECTED_SC on DISCONNECT message
16671da177e4SLinus Torvalds * - set completed flag on COMMAND COMPLETE
16681da177e4SLinus Torvalds * (other completition code moved to busfree_run)
16691da177e4SLinus Torvalds * - handle response to SDTR
16701da177e4SLinus Torvalds * - clear synchronous transfer agreements on BUS RESET
16711da177e4SLinus Torvalds *
16721da177e4SLinus Torvalds * FIXME: what about SAVE POINTERS, RESTORE POINTERS?
16731da177e4SLinus Torvalds *
16741da177e4SLinus Torvalds */
msgi_run(struct Scsi_Host * shpnt)16751da177e4SLinus Torvalds static void msgi_run(struct Scsi_Host *shpnt)
16761da177e4SLinus Torvalds {
16771da177e4SLinus Torvalds for(;;) {
167863221571SFinn Thain struct aha152x_cmd_priv *acp;
16791da177e4SLinus Torvalds int sstat1 = GETPORT(SSTAT1);
16801da177e4SLinus Torvalds
16811da177e4SLinus Torvalds if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT))
16821da177e4SLinus Torvalds return;
16831da177e4SLinus Torvalds
1684f75ae8edSHannes Reinecke if (TESTLO(SSTAT0, SPIORDY))
16851da177e4SLinus Torvalds return;
16861da177e4SLinus Torvalds
16871da177e4SLinus Torvalds ADDMSGI(GETPORT(SCSIDAT));
16881da177e4SLinus Torvalds
16891da177e4SLinus Torvalds if(!CURRENT_SC) {
16901da177e4SLinus Torvalds if(LASTSTATE!=seldi) {
1691f75ae8edSHannes Reinecke shost_printk(KERN_ERR, shpnt,
1692f75ae8edSHannes Reinecke "message in w/o current command"
1693f75ae8edSHannes Reinecke " not after reselection\n");
16941da177e4SLinus Torvalds }
16951da177e4SLinus Torvalds
16961da177e4SLinus Torvalds /*
16971da177e4SLinus Torvalds * Handle reselection
16981da177e4SLinus Torvalds */
16991da177e4SLinus Torvalds if(!(MSGI(0) & IDENTIFY_BASE)) {
1700f75ae8edSHannes Reinecke shost_printk(KERN_ERR, shpnt,
1701f75ae8edSHannes Reinecke "target didn't identify after reselection\n");
17021da177e4SLinus Torvalds continue;
17031da177e4SLinus Torvalds }
17041da177e4SLinus Torvalds
17051da177e4SLinus Torvalds CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f);
17061da177e4SLinus Torvalds
17071da177e4SLinus Torvalds if (!CURRENT_SC) {
17081da177e4SLinus Torvalds show_queues(shpnt);
1709f75ae8edSHannes Reinecke shost_printk(KERN_ERR, shpnt,
1710f75ae8edSHannes Reinecke "no disconnected command"
1711f75ae8edSHannes Reinecke " for target %d/%d\n",
1712f75ae8edSHannes Reinecke RECONN_TARGET, MSGI(0) & 0x3f);
17131da177e4SLinus Torvalds continue;
17141da177e4SLinus Torvalds }
17151da177e4SLinus Torvalds
171663221571SFinn Thain acp = aha152x_priv(CURRENT_SC);
171763221571SFinn Thain acp->message = MSGI(0);
171863221571SFinn Thain acp->phase &= ~disconnected;
17191da177e4SLinus Torvalds
17201da177e4SLinus Torvalds MSGILEN=0;
17211da177e4SLinus Torvalds
17221da177e4SLinus Torvalds /* next message if any */
17231da177e4SLinus Torvalds continue;
17241da177e4SLinus Torvalds }
17251da177e4SLinus Torvalds
172663221571SFinn Thain acp = aha152x_priv(CURRENT_SC);
172763221571SFinn Thain acp->message = MSGI(0);
17281da177e4SLinus Torvalds
17291da177e4SLinus Torvalds switch (MSGI(0)) {
17301da177e4SLinus Torvalds case DISCONNECT:
17311da177e4SLinus Torvalds if (!RECONNECT)
1732f75ae8edSHannes Reinecke scmd_printk(KERN_WARNING, CURRENT_SC,
1733f75ae8edSHannes Reinecke "target was not allowed to disconnect\n");
17341da177e4SLinus Torvalds
173563221571SFinn Thain acp->phase |= disconnected;
17361da177e4SLinus Torvalds break;
17371da177e4SLinus Torvalds
17381da177e4SLinus Torvalds case COMMAND_COMPLETE:
173963221571SFinn Thain acp->phase |= completed;
17401da177e4SLinus Torvalds break;
17411da177e4SLinus Torvalds
17421da177e4SLinus Torvalds case MESSAGE_REJECT:
17431da177e4SLinus Torvalds if (SYNCNEG==1) {
1744f75ae8edSHannes Reinecke scmd_printk(KERN_INFO, CURRENT_SC,
1745f75ae8edSHannes Reinecke "Synchronous Data Transfer Request"
1746f75ae8edSHannes Reinecke " was rejected\n");
17471da177e4SLinus Torvalds SYNCNEG=2; /* negotiation completed */
17481da177e4SLinus Torvalds } else
1749f75ae8edSHannes Reinecke scmd_printk(KERN_INFO, CURRENT_SC,
1750f75ae8edSHannes Reinecke "inbound message (MESSAGE REJECT)\n");
17511da177e4SLinus Torvalds break;
17521da177e4SLinus Torvalds
17531da177e4SLinus Torvalds case SAVE_POINTERS:
17541da177e4SLinus Torvalds break;
17551da177e4SLinus Torvalds
17561da177e4SLinus Torvalds case RESTORE_POINTERS:
17571da177e4SLinus Torvalds break;
17581da177e4SLinus Torvalds
17591da177e4SLinus Torvalds case EXTENDED_MESSAGE:
17601da177e4SLinus Torvalds if(MSGILEN<2 || MSGILEN<MSGI(1)+2) {
17611da177e4SLinus Torvalds /* not yet completed */
17621da177e4SLinus Torvalds continue;
17631da177e4SLinus Torvalds }
17641da177e4SLinus Torvalds
17651da177e4SLinus Torvalds switch (MSGI(2)) {
17661da177e4SLinus Torvalds case EXTENDED_SDTR:
17671da177e4SLinus Torvalds {
17681da177e4SLinus Torvalds long ticks;
17691da177e4SLinus Torvalds
17701da177e4SLinus Torvalds if (MSGI(1) != 3) {
1771f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC,
1772f75ae8edSHannes Reinecke "SDTR message length!=3\n");
17731da177e4SLinus Torvalds break;
17741da177e4SLinus Torvalds }
17751da177e4SLinus Torvalds
17761da177e4SLinus Torvalds if (!HOSTDATA(shpnt)->synchronous)
17771da177e4SLinus Torvalds break;
17781da177e4SLinus Torvalds
17791da177e4SLinus Torvalds printk(INFO_LEAD, CMDINFO(CURRENT_SC));
17801abfd370SMatthew Wilcox spi_print_msg(&MSGI(0));
17811da177e4SLinus Torvalds printk("\n");
17821da177e4SLinus Torvalds
17831da177e4SLinus Torvalds ticks = (MSGI(3) * 4 + 49) / 50;
17841da177e4SLinus Torvalds
17851da177e4SLinus Torvalds if (syncneg) {
17861da177e4SLinus Torvalds /* negotiation in progress */
17871da177e4SLinus Torvalds if (ticks > 9 || MSGI(4) < 1 || MSGI(4) > 8) {
17881da177e4SLinus Torvalds ADDMSGO(MESSAGE_REJECT);
1789f75ae8edSHannes Reinecke scmd_printk(KERN_INFO,
1790f75ae8edSHannes Reinecke CURRENT_SC,
1791f75ae8edSHannes Reinecke "received Synchronous Data Transfer Request invalid - rejected\n");
17921da177e4SLinus Torvalds break;
17931da177e4SLinus Torvalds }
17941da177e4SLinus Torvalds
17951da177e4SLinus Torvalds SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
17961da177e4SLinus Torvalds } else if (ticks <= 9 && MSGI(4) >= 1) {
17971da177e4SLinus Torvalds ADDMSGO(EXTENDED_MESSAGE);
17981da177e4SLinus Torvalds ADDMSGO(3);
17991da177e4SLinus Torvalds ADDMSGO(EXTENDED_SDTR);
18001da177e4SLinus Torvalds if (ticks < 4) {
18011da177e4SLinus Torvalds ticks = 4;
18021da177e4SLinus Torvalds ADDMSGO(50);
18031da177e4SLinus Torvalds } else
18041da177e4SLinus Torvalds ADDMSGO(MSGI(3));
18051da177e4SLinus Torvalds
18061da177e4SLinus Torvalds if (MSGI(4) > 8)
18071da177e4SLinus Torvalds MSGI(4) = 8;
18081da177e4SLinus Torvalds
18091da177e4SLinus Torvalds ADDMSGO(MSGI(4));
18101da177e4SLinus Torvalds
18111da177e4SLinus Torvalds SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
18121da177e4SLinus Torvalds } else {
18131da177e4SLinus Torvalds /* requested SDTR is too slow, do it asynchronously */
1814f75ae8edSHannes Reinecke scmd_printk(KERN_INFO,
1815f75ae8edSHannes Reinecke CURRENT_SC,
1816f75ae8edSHannes Reinecke "Synchronous Data Transfer Request too slow - Rejecting\n");
18171da177e4SLinus Torvalds ADDMSGO(MESSAGE_REJECT);
18181da177e4SLinus Torvalds }
18191da177e4SLinus Torvalds
1820f75ae8edSHannes Reinecke /* negotiation completed */
1821f75ae8edSHannes Reinecke SYNCNEG=2;
18221da177e4SLinus Torvalds SETRATE(SYNCRATE);
18231da177e4SLinus Torvalds }
18241da177e4SLinus Torvalds break;
18251da177e4SLinus Torvalds
18261da177e4SLinus Torvalds case BUS_DEVICE_RESET:
18271da177e4SLinus Torvalds {
18281da177e4SLinus Torvalds int i;
18291da177e4SLinus Torvalds
18301da177e4SLinus Torvalds for(i=0; i<8; i++) {
18311da177e4SLinus Torvalds HOSTDATA(shpnt)->syncrate[i]=0;
18321da177e4SLinus Torvalds HOSTDATA(shpnt)->syncneg[i]=0;
18331da177e4SLinus Torvalds }
18341da177e4SLinus Torvalds
18351da177e4SLinus Torvalds }
18361da177e4SLinus Torvalds break;
18371da177e4SLinus Torvalds
18381da177e4SLinus Torvalds case EXTENDED_MODIFY_DATA_POINTER:
18391da177e4SLinus Torvalds case EXTENDED_EXTENDED_IDENTIFY:
18401da177e4SLinus Torvalds case EXTENDED_WDTR:
18411da177e4SLinus Torvalds default:
18421da177e4SLinus Torvalds ADDMSGO(MESSAGE_REJECT);
18431da177e4SLinus Torvalds break;
18441da177e4SLinus Torvalds }
18451da177e4SLinus Torvalds break;
18461da177e4SLinus Torvalds }
18471da177e4SLinus Torvalds
18481da177e4SLinus Torvalds MSGILEN=0;
18491da177e4SLinus Torvalds }
18501da177e4SLinus Torvalds }
18511da177e4SLinus Torvalds
msgi_end(struct Scsi_Host * shpnt)18521da177e4SLinus Torvalds static void msgi_end(struct Scsi_Host *shpnt)
18531da177e4SLinus Torvalds {
18541da177e4SLinus Torvalds if(MSGILEN>0)
1855f75ae8edSHannes Reinecke scmd_printk(KERN_WARNING, CURRENT_SC,
1856f75ae8edSHannes Reinecke "target left before message completed (%d)\n",
1857f75ae8edSHannes Reinecke MSGILEN);
18581da177e4SLinus Torvalds
1859f75ae8edSHannes Reinecke if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE))
18601da177e4SLinus Torvalds SETPORT(SCSISIG, P_MSGI | SIG_ATNO);
18611da177e4SLinus Torvalds }
18621da177e4SLinus Torvalds
18631da177e4SLinus Torvalds /*
18641da177e4SLinus Torvalds * message out phase
18651da177e4SLinus Torvalds *
18661da177e4SLinus Torvalds */
msgo_init(struct Scsi_Host * shpnt)18671da177e4SLinus Torvalds static void msgo_init(struct Scsi_Host *shpnt)
18681da177e4SLinus Torvalds {
18691da177e4SLinus Torvalds if(MSGOLEN==0) {
187063221571SFinn Thain if ((aha152x_priv(CURRENT_SC)->phase & syncneg) &&
187163221571SFinn Thain SYNCNEG == 2 && SYNCRATE == 0) {
18721da177e4SLinus Torvalds ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
18731da177e4SLinus Torvalds } else {
1874f75ae8edSHannes Reinecke scmd_printk(KERN_INFO, CURRENT_SC,
1875f75ae8edSHannes Reinecke "unexpected MESSAGE OUT phase; rejecting\n");
18761da177e4SLinus Torvalds ADDMSGO(MESSAGE_REJECT);
18771da177e4SLinus Torvalds }
18781da177e4SLinus Torvalds }
18791da177e4SLinus Torvalds
18801da177e4SLinus Torvalds }
18811da177e4SLinus Torvalds
18821da177e4SLinus Torvalds /*
18831da177e4SLinus Torvalds * message out phase
18841da177e4SLinus Torvalds *
18851da177e4SLinus Torvalds */
msgo_run(struct Scsi_Host * shpnt)18861da177e4SLinus Torvalds static void msgo_run(struct Scsi_Host *shpnt)
18871da177e4SLinus Torvalds {
188863221571SFinn Thain struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
18893ac6aba3SBart Van Assche
18901da177e4SLinus Torvalds while(MSGO_I<MSGOLEN) {
1891f75ae8edSHannes Reinecke if (TESTLO(SSTAT0, SPIORDY))
18921da177e4SLinus Torvalds return;
18931da177e4SLinus Torvalds
18941da177e4SLinus Torvalds if (MSGO_I==MSGOLEN-1) {
18951da177e4SLinus Torvalds /* Leave MESSAGE OUT after transfer */
18961da177e4SLinus Torvalds SETPORT(SSTAT1, CLRATNO);
18971da177e4SLinus Torvalds }
18981da177e4SLinus Torvalds
18991da177e4SLinus Torvalds
19001da177e4SLinus Torvalds if (MSGO(MSGO_I) & IDENTIFY_BASE)
190163221571SFinn Thain acp->phase |= identified;
19021da177e4SLinus Torvalds
19031da177e4SLinus Torvalds if (MSGO(MSGO_I)==ABORT)
190463221571SFinn Thain acp->phase |= aborted;
19051da177e4SLinus Torvalds
19061da177e4SLinus Torvalds if (MSGO(MSGO_I)==BUS_DEVICE_RESET)
190763221571SFinn Thain acp->phase |= resetted;
19081da177e4SLinus Torvalds
19091da177e4SLinus Torvalds SETPORT(SCSIDAT, MSGO(MSGO_I++));
19101da177e4SLinus Torvalds }
19111da177e4SLinus Torvalds }
19121da177e4SLinus Torvalds
msgo_end(struct Scsi_Host * shpnt)19131da177e4SLinus Torvalds static void msgo_end(struct Scsi_Host *shpnt)
19141da177e4SLinus Torvalds {
19151da177e4SLinus Torvalds if(MSGO_I<MSGOLEN) {
1916f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC,
1917f75ae8edSHannes Reinecke "message sent incompletely (%d/%d)\n",
1918f75ae8edSHannes Reinecke MSGO_I, MSGOLEN);
19191da177e4SLinus Torvalds if(SYNCNEG==1) {
1920f75ae8edSHannes Reinecke scmd_printk(KERN_INFO, CURRENT_SC,
1921f75ae8edSHannes Reinecke "Synchronous Data Transfer Request was rejected\n");
19221da177e4SLinus Torvalds SYNCNEG=2;
19231da177e4SLinus Torvalds }
19241da177e4SLinus Torvalds }
19251da177e4SLinus Torvalds
19261da177e4SLinus Torvalds MSGO_I = 0;
19271da177e4SLinus Torvalds MSGOLEN = 0;
19281da177e4SLinus Torvalds }
19291da177e4SLinus Torvalds
19301da177e4SLinus Torvalds /*
19311da177e4SLinus Torvalds * command phase
19321da177e4SLinus Torvalds *
19331da177e4SLinus Torvalds */
cmd_init(struct Scsi_Host * shpnt)19341da177e4SLinus Torvalds static void cmd_init(struct Scsi_Host *shpnt)
19351da177e4SLinus Torvalds {
193663221571SFinn Thain if (aha152x_priv(CURRENT_SC)->sent_command) {
1937f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC,
1938f75ae8edSHannes Reinecke "command already sent\n");
1939fdabe57dSHannes Reinecke done(shpnt, SAM_STAT_GOOD, DID_ERROR);
19401da177e4SLinus Torvalds return;
19411da177e4SLinus Torvalds }
19421da177e4SLinus Torvalds
19431da177e4SLinus Torvalds CMD_I=0;
19441da177e4SLinus Torvalds }
19451da177e4SLinus Torvalds
19461da177e4SLinus Torvalds /*
19471da177e4SLinus Torvalds * command phase
19481da177e4SLinus Torvalds *
19491da177e4SLinus Torvalds */
cmd_run(struct Scsi_Host * shpnt)19501da177e4SLinus Torvalds static void cmd_run(struct Scsi_Host *shpnt)
19511da177e4SLinus Torvalds {
19521da177e4SLinus Torvalds while(CMD_I<CURRENT_SC->cmd_len) {
1953f75ae8edSHannes Reinecke if (TESTLO(SSTAT0, SPIORDY))
19541da177e4SLinus Torvalds return;
19551da177e4SLinus Torvalds
19561da177e4SLinus Torvalds SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]);
19571da177e4SLinus Torvalds }
19581da177e4SLinus Torvalds }
19591da177e4SLinus Torvalds
cmd_end(struct Scsi_Host * shpnt)19601da177e4SLinus Torvalds static void cmd_end(struct Scsi_Host *shpnt)
19611da177e4SLinus Torvalds {
19621da177e4SLinus Torvalds if(CMD_I<CURRENT_SC->cmd_len)
1963f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC,
1964f75ae8edSHannes Reinecke "command sent incompletely (%d/%d)\n",
1965f75ae8edSHannes Reinecke CMD_I, CURRENT_SC->cmd_len);
19661da177e4SLinus Torvalds else
196763221571SFinn Thain aha152x_priv(CURRENT_SC)->sent_command++;
19681da177e4SLinus Torvalds }
19691da177e4SLinus Torvalds
19701da177e4SLinus Torvalds /*
19711da177e4SLinus Torvalds * status phase
19721da177e4SLinus Torvalds *
19731da177e4SLinus Torvalds */
status_run(struct Scsi_Host * shpnt)19741da177e4SLinus Torvalds static void status_run(struct Scsi_Host *shpnt)
19751da177e4SLinus Torvalds {
1976f75ae8edSHannes Reinecke if (TESTLO(SSTAT0, SPIORDY))
19771da177e4SLinus Torvalds return;
19781da177e4SLinus Torvalds
197963221571SFinn Thain aha152x_priv(CURRENT_SC)->status = GETPORT(SCSIDAT);
19801da177e4SLinus Torvalds
19811da177e4SLinus Torvalds }
19821da177e4SLinus Torvalds
19831da177e4SLinus Torvalds /*
19841da177e4SLinus Torvalds * data in phase
19851da177e4SLinus Torvalds *
19861da177e4SLinus Torvalds */
datai_init(struct Scsi_Host * shpnt)19871da177e4SLinus Torvalds static void datai_init(struct Scsi_Host *shpnt)
19881da177e4SLinus Torvalds {
19891da177e4SLinus Torvalds SETPORT(DMACNTRL0, RSTFIFO);
19901da177e4SLinus Torvalds SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
19911da177e4SLinus Torvalds
19921da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|CLRSTCNT);
19931da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
19941da177e4SLinus Torvalds
19951da177e4SLinus Torvalds SETPORT(SIMODE0, 0);
19961da177e4SLinus Torvalds SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE);
19971da177e4SLinus Torvalds
19981da177e4SLinus Torvalds DATA_LEN=0;
19991da177e4SLinus Torvalds }
20001da177e4SLinus Torvalds
datai_run(struct Scsi_Host * shpnt)20011da177e4SLinus Torvalds static void datai_run(struct Scsi_Host *shpnt)
20021da177e4SLinus Torvalds {
200363221571SFinn Thain struct aha152x_cmd_priv *acp;
20041da177e4SLinus Torvalds unsigned long the_time;
20051da177e4SLinus Torvalds int fifodata, data_count;
20061da177e4SLinus Torvalds
20071da177e4SLinus Torvalds /*
20081da177e4SLinus Torvalds * loop while the phase persists or the fifos are not empty
20091da177e4SLinus Torvalds *
20101da177e4SLinus Torvalds */
20111da177e4SLinus Torvalds while(TESTLO(DMASTAT, INTSTAT) || TESTLO(DMASTAT, DFIFOEMP) || TESTLO(SSTAT2, SEMPTY)) {
20121da177e4SLinus Torvalds /* FIXME: maybe this should be done by setting up
20131da177e4SLinus Torvalds * STCNT to trigger ENSWRAP interrupt, instead of
20141da177e4SLinus Torvalds * polling for DFIFOFULL
20151da177e4SLinus Torvalds */
20161da177e4SLinus Torvalds the_time=jiffies + 100*HZ;
20171da177e4SLinus Torvalds while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time))
20181da177e4SLinus Torvalds barrier();
20191da177e4SLinus Torvalds
20201da177e4SLinus Torvalds if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) {
2021f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, "datai timeout\n");
20221da177e4SLinus Torvalds break;
20231da177e4SLinus Torvalds }
20241da177e4SLinus Torvalds
20251da177e4SLinus Torvalds if(TESTHI(DMASTAT, DFIFOFULL)) {
20261da177e4SLinus Torvalds fifodata = 128;
20271da177e4SLinus Torvalds } else {
20281da177e4SLinus Torvalds the_time=jiffies + 100*HZ;
20291da177e4SLinus Torvalds while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time))
20301da177e4SLinus Torvalds barrier();
20311da177e4SLinus Torvalds
20321da177e4SLinus Torvalds if(TESTLO(SSTAT2, SEMPTY)) {
2033f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC,
2034f75ae8edSHannes Reinecke "datai sempty timeout");
20351da177e4SLinus Torvalds break;
20361da177e4SLinus Torvalds }
20371da177e4SLinus Torvalds
20381da177e4SLinus Torvalds fifodata = GETPORT(FIFOSTAT);
20391da177e4SLinus Torvalds }
20401da177e4SLinus Torvalds
204163221571SFinn Thain acp = aha152x_priv(CURRENT_SC);
204263221571SFinn Thain if (acp->this_residual > 0) {
204363221571SFinn Thain while (fifodata > 0 && acp->this_residual > 0) {
204463221571SFinn Thain data_count = fifodata > acp->this_residual ?
204563221571SFinn Thain acp->this_residual : fifodata;
20461da177e4SLinus Torvalds fifodata -= data_count;
20471da177e4SLinus Torvalds
20481da177e4SLinus Torvalds if (data_count & 1) {
20491da177e4SLinus Torvalds SETPORT(DMACNTRL0, ENDMA|_8BIT);
205063221571SFinn Thain *acp->ptr++ = GETPORT(DATAPORT);
205163221571SFinn Thain acp->this_residual--;
20521da177e4SLinus Torvalds DATA_LEN++;
20531da177e4SLinus Torvalds SETPORT(DMACNTRL0, ENDMA);
20541da177e4SLinus Torvalds }
20551da177e4SLinus Torvalds
20561da177e4SLinus Torvalds if (data_count > 1) {
20571da177e4SLinus Torvalds data_count >>= 1;
205863221571SFinn Thain insw(DATAPORT, acp->ptr, data_count);
205963221571SFinn Thain acp->ptr += 2 * data_count;
206063221571SFinn Thain acp->this_residual -= 2 * data_count;
20611da177e4SLinus Torvalds DATA_LEN += 2 * data_count;
20621da177e4SLinus Torvalds }
20631da177e4SLinus Torvalds
206463221571SFinn Thain if (acp->this_residual == 0 &&
206563221571SFinn Thain !sg_is_last(acp->buffer)) {
20661da177e4SLinus Torvalds /* advance to next buffer */
206763221571SFinn Thain acp->buffer = sg_next(acp->buffer);
206863221571SFinn Thain acp->ptr = SG_ADDRESS(acp->buffer);
206963221571SFinn Thain acp->this_residual = acp->buffer->length;
20701da177e4SLinus Torvalds }
20711da177e4SLinus Torvalds }
20721da177e4SLinus Torvalds } else if (fifodata > 0) {
2073f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC,
2074f75ae8edSHannes Reinecke "no buffers left for %d(%d) bytes"
2075f75ae8edSHannes Reinecke " (data overrun!?)\n",
2076f75ae8edSHannes Reinecke fifodata, GETPORT(FIFOSTAT));
20771da177e4SLinus Torvalds SETPORT(DMACNTRL0, ENDMA|_8BIT);
20781da177e4SLinus Torvalds while(fifodata>0) {
20793c011793SLee Jones GETPORT(DATAPORT);
20801da177e4SLinus Torvalds fifodata--;
20811da177e4SLinus Torvalds DATA_LEN++;
20821da177e4SLinus Torvalds }
20831da177e4SLinus Torvalds SETPORT(DMACNTRL0, ENDMA|_8BIT);
20841da177e4SLinus Torvalds }
20851da177e4SLinus Torvalds }
20861da177e4SLinus Torvalds
20871da177e4SLinus Torvalds if(TESTLO(DMASTAT, INTSTAT) ||
20881da177e4SLinus Torvalds TESTLO(DMASTAT, DFIFOEMP) ||
20891da177e4SLinus Torvalds TESTLO(SSTAT2, SEMPTY) ||
20901da177e4SLinus Torvalds GETPORT(FIFOSTAT)>0) {
20911da177e4SLinus Torvalds /*
20921da177e4SLinus Torvalds * something went wrong, if there's something left in the fifos
20931da177e4SLinus Torvalds * or the phase didn't change
20941da177e4SLinus Torvalds */
2095f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC,
2096f75ae8edSHannes Reinecke "fifos should be empty and phase should have changed\n");
20971da177e4SLinus Torvalds }
20981da177e4SLinus Torvalds
20991da177e4SLinus Torvalds if(DATA_LEN!=GETSTCNT()) {
2100f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC,
2101f75ae8edSHannes Reinecke "manual transfer count differs from automatic "
2102f75ae8edSHannes Reinecke "(count=%d;stcnt=%d;diff=%d;fifostat=%d)",
2103f75ae8edSHannes Reinecke DATA_LEN, GETSTCNT(), GETSTCNT()-DATA_LEN,
2104f75ae8edSHannes Reinecke GETPORT(FIFOSTAT));
21051da177e4SLinus Torvalds mdelay(10000);
21061da177e4SLinus Torvalds }
21071da177e4SLinus Torvalds }
21081da177e4SLinus Torvalds
datai_end(struct Scsi_Host * shpnt)21091da177e4SLinus Torvalds static void datai_end(struct Scsi_Host *shpnt)
21101da177e4SLinus Torvalds {
21112338545aSBoaz Harrosh CMD_INC_RESID(CURRENT_SC, -GETSTCNT());
21121da177e4SLinus Torvalds
21131da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|CLRSTCNT);
21141da177e4SLinus Torvalds SETPORT(DMACNTRL0, 0);
21151da177e4SLinus Torvalds }
21161da177e4SLinus Torvalds
21171da177e4SLinus Torvalds /*
21181da177e4SLinus Torvalds * data out phase
21191da177e4SLinus Torvalds *
21201da177e4SLinus Torvalds */
datao_init(struct Scsi_Host * shpnt)21211da177e4SLinus Torvalds static void datao_init(struct Scsi_Host *shpnt)
21221da177e4SLinus Torvalds {
21231da177e4SLinus Torvalds SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
21241da177e4SLinus Torvalds SETPORT(DMACNTRL0, WRITE_READ | ENDMA);
21251da177e4SLinus Torvalds
21261da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|CLRSTCNT);
21271da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
21281da177e4SLinus Torvalds
21291da177e4SLinus Torvalds SETPORT(SIMODE0, 0);
21301da177e4SLinus Torvalds SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE );
21311da177e4SLinus Torvalds
21322338545aSBoaz Harrosh DATA_LEN = scsi_get_resid(CURRENT_SC);
21331da177e4SLinus Torvalds }
21341da177e4SLinus Torvalds
datao_run(struct Scsi_Host * shpnt)21351da177e4SLinus Torvalds static void datao_run(struct Scsi_Host *shpnt)
21361da177e4SLinus Torvalds {
213763221571SFinn Thain struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
21381da177e4SLinus Torvalds unsigned long the_time;
21391da177e4SLinus Torvalds int data_count;
21401da177e4SLinus Torvalds
21411da177e4SLinus Torvalds /* until phase changes or all data sent */
214263221571SFinn Thain while (TESTLO(DMASTAT, INTSTAT) && acp->this_residual > 0) {
21431da177e4SLinus Torvalds data_count = 128;
214463221571SFinn Thain if (data_count > acp->this_residual)
214563221571SFinn Thain data_count = acp->this_residual;
21461da177e4SLinus Torvalds
21471da177e4SLinus Torvalds if(TESTLO(DMASTAT, DFIFOEMP)) {
2148f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC,
2149f75ae8edSHannes Reinecke "datao fifo not empty (%d)",
2150f75ae8edSHannes Reinecke GETPORT(FIFOSTAT));
21511da177e4SLinus Torvalds break;
21521da177e4SLinus Torvalds }
21531da177e4SLinus Torvalds
21541da177e4SLinus Torvalds if(data_count & 1) {
21551da177e4SLinus Torvalds SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT);
215663221571SFinn Thain SETPORT(DATAPORT, *acp->ptr++);
215763221571SFinn Thain acp->this_residual--;
21582338545aSBoaz Harrosh CMD_INC_RESID(CURRENT_SC, -1);
21591da177e4SLinus Torvalds SETPORT(DMACNTRL0,WRITE_READ|ENDMA);
21601da177e4SLinus Torvalds }
21611da177e4SLinus Torvalds
21621da177e4SLinus Torvalds if(data_count > 1) {
21631da177e4SLinus Torvalds data_count >>= 1;
216463221571SFinn Thain outsw(DATAPORT, acp->ptr, data_count);
216563221571SFinn Thain acp->ptr += 2 * data_count;
216663221571SFinn Thain acp->this_residual -= 2 * data_count;
21672338545aSBoaz Harrosh CMD_INC_RESID(CURRENT_SC, -2 * data_count);
21681da177e4SLinus Torvalds }
21691da177e4SLinus Torvalds
217063221571SFinn Thain if (acp->this_residual == 0 && !sg_is_last(acp->buffer)) {
21711da177e4SLinus Torvalds /* advance to next buffer */
217263221571SFinn Thain acp->buffer = sg_next(acp->buffer);
217363221571SFinn Thain acp->ptr = SG_ADDRESS(acp->buffer);
217463221571SFinn Thain acp->this_residual = acp->buffer->length;
21751da177e4SLinus Torvalds }
21761da177e4SLinus Torvalds
21771da177e4SLinus Torvalds the_time=jiffies + 100*HZ;
21781da177e4SLinus Torvalds while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time))
21791da177e4SLinus Torvalds barrier();
21801da177e4SLinus Torvalds
21811da177e4SLinus Torvalds if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) {
2182f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, "dataout timeout\n");
21831da177e4SLinus Torvalds break;
21841da177e4SLinus Torvalds }
21851da177e4SLinus Torvalds }
21861da177e4SLinus Torvalds }
21871da177e4SLinus Torvalds
datao_end(struct Scsi_Host * shpnt)21881da177e4SLinus Torvalds static void datao_end(struct Scsi_Host *shpnt)
21891da177e4SLinus Torvalds {
219063221571SFinn Thain struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
21913ac6aba3SBart Van Assche
21921da177e4SLinus Torvalds if(TESTLO(DMASTAT, DFIFOEMP)) {
2193a7a253baSFinn Thain u32 datao_cnt = GETSTCNT();
2194a7a253baSFinn Thain int datao_out = DATA_LEN - scsi_get_resid(CURRENT_SC);
2195a7a253baSFinn Thain int done;
2196a7a253baSFinn Thain struct scatterlist *sg = scsi_sglist(CURRENT_SC);
21971da177e4SLinus Torvalds
2198a7a253baSFinn Thain CMD_INC_RESID(CURRENT_SC, datao_out - datao_cnt);
21991da177e4SLinus Torvalds
2200a7a253baSFinn Thain done = scsi_bufflen(CURRENT_SC) - scsi_get_resid(CURRENT_SC);
2201a7a253baSFinn Thain /* Locate the first SG entry not yet sent */
2202a7a253baSFinn Thain while (done > 0 && !sg_is_last(sg)) {
2203a7a253baSFinn Thain if (done < sg->length)
2204a7a253baSFinn Thain break;
2205a7a253baSFinn Thain done -= sg->length;
2206a7a253baSFinn Thain sg = sg_next(sg);
22071da177e4SLinus Torvalds }
2208a7a253baSFinn Thain
220963221571SFinn Thain acp->buffer = sg;
221063221571SFinn Thain acp->ptr = SG_ADDRESS(acp->buffer) + done;
221163221571SFinn Thain acp->this_residual = acp->buffer->length - done;
22121da177e4SLinus Torvalds }
22131da177e4SLinus Torvalds
22141da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
22151da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1);
22161da177e4SLinus Torvalds
22171da177e4SLinus Torvalds SETPORT(DMACNTRL0, 0);
22181da177e4SLinus Torvalds }
22191da177e4SLinus Torvalds
22201da177e4SLinus Torvalds /*
22211da177e4SLinus Torvalds * figure out what state we're in
22221da177e4SLinus Torvalds *
22231da177e4SLinus Torvalds */
update_state(struct Scsi_Host * shpnt)22241da177e4SLinus Torvalds static int update_state(struct Scsi_Host *shpnt)
22251da177e4SLinus Torvalds {
22261da177e4SLinus Torvalds int dataphase=0;
22271da177e4SLinus Torvalds unsigned int stat0 = GETPORT(SSTAT0);
22281da177e4SLinus Torvalds unsigned int stat1 = GETPORT(SSTAT1);
22291da177e4SLinus Torvalds
22301da177e4SLinus Torvalds PREVSTATE = STATE;
22311da177e4SLinus Torvalds STATE=unknown;
22321da177e4SLinus Torvalds
22331da177e4SLinus Torvalds if(stat1 & SCSIRSTI) {
22341da177e4SLinus Torvalds STATE=rsti;
22351da177e4SLinus Torvalds SETPORT(SCSISEQ,0);
22361da177e4SLinus Torvalds SETPORT(SSTAT1,SCSIRSTI);
22371da177e4SLinus Torvalds } else if (stat0 & SELDI && PREVSTATE == busfree) {
22381da177e4SLinus Torvalds STATE=seldi;
22393ac6aba3SBart Van Assche } else if (stat0 & SELDO && CURRENT_SC &&
224063221571SFinn Thain (aha152x_priv(CURRENT_SC)->phase & selecting)) {
22411da177e4SLinus Torvalds STATE=seldo;
22421da177e4SLinus Torvalds } else if(stat1 & SELTO) {
22431da177e4SLinus Torvalds STATE=selto;
22441da177e4SLinus Torvalds } else if(stat1 & BUSFREE) {
22451da177e4SLinus Torvalds STATE=busfree;
22461da177e4SLinus Torvalds SETPORT(SSTAT1,BUSFREE);
22471da177e4SLinus Torvalds } else if(stat1 & SCSIPERR) {
22481da177e4SLinus Torvalds STATE=parerr;
22491da177e4SLinus Torvalds SETPORT(SSTAT1,SCSIPERR);
22501da177e4SLinus Torvalds } else if(stat1 & REQINIT) {
22511da177e4SLinus Torvalds switch(GETPORT(SCSISIG) & P_MASK) {
22521da177e4SLinus Torvalds case P_MSGI: STATE=msgi; break;
22531da177e4SLinus Torvalds case P_MSGO: STATE=msgo; break;
22541da177e4SLinus Torvalds case P_DATAO: STATE=datao; break;
22551da177e4SLinus Torvalds case P_DATAI: STATE=datai; break;
22561da177e4SLinus Torvalds case P_STATUS: STATE=status; break;
22571da177e4SLinus Torvalds case P_CMD: STATE=cmd; break;
22581da177e4SLinus Torvalds }
22591da177e4SLinus Torvalds dataphase=1;
22601da177e4SLinus Torvalds }
22611da177e4SLinus Torvalds
22621da177e4SLinus Torvalds if((stat0 & SELDI) && STATE!=seldi && !dataphase) {
2263f75ae8edSHannes Reinecke scmd_printk(KERN_INFO, CURRENT_SC, "reselection missed?");
22641da177e4SLinus Torvalds }
22651da177e4SLinus Torvalds
22661da177e4SLinus Torvalds if(STATE!=PREVSTATE) {
22671da177e4SLinus Torvalds LASTSTATE=PREVSTATE;
22681da177e4SLinus Torvalds }
22691da177e4SLinus Torvalds
22701da177e4SLinus Torvalds return dataphase;
22711da177e4SLinus Torvalds }
22721da177e4SLinus Torvalds
22731da177e4SLinus Torvalds /*
22741da177e4SLinus Torvalds * handle parity error
22751da177e4SLinus Torvalds *
22761da177e4SLinus Torvalds * FIXME: in which phase?
22771da177e4SLinus Torvalds *
22781da177e4SLinus Torvalds */
parerr_run(struct Scsi_Host * shpnt)22791da177e4SLinus Torvalds static void parerr_run(struct Scsi_Host *shpnt)
22801da177e4SLinus Torvalds {
2281f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC, "parity error\n");
2282fdabe57dSHannes Reinecke done(shpnt, SAM_STAT_GOOD, DID_PARITY);
22831da177e4SLinus Torvalds }
22841da177e4SLinus Torvalds
22851da177e4SLinus Torvalds /*
22861da177e4SLinus Torvalds * handle reset in
22871da177e4SLinus Torvalds *
22881da177e4SLinus Torvalds */
rsti_run(struct Scsi_Host * shpnt)22891da177e4SLinus Torvalds static void rsti_run(struct Scsi_Host *shpnt)
22901da177e4SLinus Torvalds {
229191ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr;
22921da177e4SLinus Torvalds
2293f75ae8edSHannes Reinecke shost_printk(KERN_NOTICE, shpnt, "scsi reset in\n");
22941da177e4SLinus Torvalds
22951da177e4SLinus Torvalds ptr=DISCONNECTED_SC;
22961da177e4SLinus Torvalds while(ptr) {
229791ebc1faSJohannes Thumshirn struct scsi_cmnd *next = SCNEXT(ptr);
22981da177e4SLinus Torvalds
22991da177e4SLinus Torvalds if (!ptr->device->soft_reset) {
23001da177e4SLinus Torvalds remove_SC(&DISCONNECTED_SC, ptr);
23011da177e4SLinus Torvalds
23021da177e4SLinus Torvalds kfree(ptr->host_scribble);
23031da177e4SLinus Torvalds ptr->host_scribble=NULL;
23041da177e4SLinus Torvalds
2305fdabe57dSHannes Reinecke set_host_byte(ptr, DID_RESET);
23063ab3b151SBart Van Assche aha152x_scsi_done(ptr);
23071da177e4SLinus Torvalds }
23081da177e4SLinus Torvalds
23091da177e4SLinus Torvalds ptr = next;
23101da177e4SLinus Torvalds }
23111da177e4SLinus Torvalds
23121da177e4SLinus Torvalds if(CURRENT_SC && !CURRENT_SC->device->soft_reset)
2313fdabe57dSHannes Reinecke done(shpnt, SAM_STAT_GOOD, DID_RESET);
23141da177e4SLinus Torvalds }
23151da177e4SLinus Torvalds
23161da177e4SLinus Torvalds
23171da177e4SLinus Torvalds /*
23181da177e4SLinus Torvalds * bottom-half handler
23191da177e4SLinus Torvalds *
23201da177e4SLinus Torvalds */
is_complete(struct Scsi_Host * shpnt)23211da177e4SLinus Torvalds static void is_complete(struct Scsi_Host *shpnt)
23221da177e4SLinus Torvalds {
23231da177e4SLinus Torvalds int dataphase;
23241da177e4SLinus Torvalds unsigned long flags;
23251da177e4SLinus Torvalds int pending;
23261da177e4SLinus Torvalds
2327e2482fa1SJürgen E. Fischer if(!shpnt)
2328e2482fa1SJürgen E. Fischer return;
2329e2482fa1SJürgen E. Fischer
23301da177e4SLinus Torvalds DO_LOCK(flags);
2331e2482fa1SJürgen E. Fischer
2332e2482fa1SJürgen E. Fischer if( HOSTDATA(shpnt)->service==0 ) {
2333e2482fa1SJürgen E. Fischer DO_UNLOCK(flags);
2334e2482fa1SJürgen E. Fischer return;
2335e2482fa1SJürgen E. Fischer }
2336e2482fa1SJürgen E. Fischer
2337e2482fa1SJürgen E. Fischer HOSTDATA(shpnt)->service = 0;
2338e2482fa1SJürgen E. Fischer
23391da177e4SLinus Torvalds if(HOSTDATA(shpnt)->in_intr) {
23401da177e4SLinus Torvalds DO_UNLOCK(flags);
23411da177e4SLinus Torvalds /* aha152x_error never returns.. */
23421da177e4SLinus Torvalds aha152x_error(shpnt, "bottom-half already running!?");
23431da177e4SLinus Torvalds }
23441da177e4SLinus Torvalds HOSTDATA(shpnt)->in_intr++;
23451da177e4SLinus Torvalds
23461da177e4SLinus Torvalds /*
23471da177e4SLinus Torvalds * loop while there are interrupt conditions pending
23481da177e4SLinus Torvalds *
23491da177e4SLinus Torvalds */
23501da177e4SLinus Torvalds do {
23511da177e4SLinus Torvalds unsigned long start = jiffies;
23521da177e4SLinus Torvalds DO_UNLOCK(flags);
23531da177e4SLinus Torvalds
23541da177e4SLinus Torvalds dataphase=update_state(shpnt);
23551da177e4SLinus Torvalds
23561da177e4SLinus Torvalds /*
23571da177e4SLinus Torvalds * end previous state
23581da177e4SLinus Torvalds *
23591da177e4SLinus Torvalds */
23601da177e4SLinus Torvalds if(PREVSTATE!=STATE && states[PREVSTATE].end)
23611da177e4SLinus Torvalds states[PREVSTATE].end(shpnt);
23621da177e4SLinus Torvalds
23631da177e4SLinus Torvalds /*
23641da177e4SLinus Torvalds * disable SPIO mode if previous phase used it
23651da177e4SLinus Torvalds * and this one doesn't
23661da177e4SLinus Torvalds *
23671da177e4SLinus Torvalds */
23681da177e4SLinus Torvalds if(states[PREVSTATE].spio && !states[STATE].spio) {
23691da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1);
23701da177e4SLinus Torvalds SETPORT(DMACNTRL0, 0);
23711da177e4SLinus Torvalds if(CURRENT_SC)
237263221571SFinn Thain aha152x_priv(CURRENT_SC)->phase &= ~spiordy;
23731da177e4SLinus Torvalds }
23741da177e4SLinus Torvalds
23751da177e4SLinus Torvalds /*
23761da177e4SLinus Torvalds * accept current dataphase phase
23771da177e4SLinus Torvalds *
23781da177e4SLinus Torvalds */
23791da177e4SLinus Torvalds if(dataphase) {
23801da177e4SLinus Torvalds SETPORT(SSTAT0, REQINIT);
23811da177e4SLinus Torvalds SETPORT(SCSISIG, GETPORT(SCSISIG) & P_MASK);
23821da177e4SLinus Torvalds SETPORT(SSTAT1, PHASECHG);
23831da177e4SLinus Torvalds }
23841da177e4SLinus Torvalds
23851da177e4SLinus Torvalds /*
23861da177e4SLinus Torvalds * enable SPIO mode if previous didn't use it
23871da177e4SLinus Torvalds * and this one does
23881da177e4SLinus Torvalds *
23891da177e4SLinus Torvalds */
23901da177e4SLinus Torvalds if(!states[PREVSTATE].spio && states[STATE].spio) {
23911da177e4SLinus Torvalds SETPORT(DMACNTRL0, 0);
23921da177e4SLinus Torvalds SETPORT(SXFRCTL0, CH1|SPIOEN);
23931da177e4SLinus Torvalds if(CURRENT_SC)
239463221571SFinn Thain aha152x_priv(CURRENT_SC)->phase |= spiordy;
23951da177e4SLinus Torvalds }
23961da177e4SLinus Torvalds
23971da177e4SLinus Torvalds /*
23981da177e4SLinus Torvalds * initialize for new state
23991da177e4SLinus Torvalds *
24001da177e4SLinus Torvalds */
24011da177e4SLinus Torvalds if(PREVSTATE!=STATE && states[STATE].init)
24021da177e4SLinus Torvalds states[STATE].init(shpnt);
24031da177e4SLinus Torvalds
24041da177e4SLinus Torvalds /*
24051da177e4SLinus Torvalds * handle current state
24061da177e4SLinus Torvalds *
24071da177e4SLinus Torvalds */
24081da177e4SLinus Torvalds if(states[STATE].run)
24091da177e4SLinus Torvalds states[STATE].run(shpnt);
24101da177e4SLinus Torvalds else
2411f75ae8edSHannes Reinecke scmd_printk(KERN_ERR, CURRENT_SC,
2412f75ae8edSHannes Reinecke "unexpected state (%x)\n", STATE);
24131da177e4SLinus Torvalds
24141da177e4SLinus Torvalds /*
24151da177e4SLinus Torvalds * setup controller to interrupt on
24161da177e4SLinus Torvalds * the next expected condition and
24171da177e4SLinus Torvalds * loop if it's already there
24181da177e4SLinus Torvalds *
24191da177e4SLinus Torvalds */
24201da177e4SLinus Torvalds DO_LOCK(flags);
24211da177e4SLinus Torvalds pending=setup_expected_interrupts(shpnt);
24221da177e4SLinus Torvalds #if defined(AHA152X_STAT)
24231da177e4SLinus Torvalds HOSTDATA(shpnt)->count[STATE]++;
24241da177e4SLinus Torvalds if(PREVSTATE!=STATE)
24251da177e4SLinus Torvalds HOSTDATA(shpnt)->count_trans[STATE]++;
24261da177e4SLinus Torvalds HOSTDATA(shpnt)->time[STATE] += jiffies-start;
24271da177e4SLinus Torvalds #endif
24281da177e4SLinus Torvalds
24291da177e4SLinus Torvalds } while(pending);
24301da177e4SLinus Torvalds
24311da177e4SLinus Torvalds /*
24321da177e4SLinus Torvalds * enable interrupts and leave bottom-half
24331da177e4SLinus Torvalds *
24341da177e4SLinus Torvalds */
24351da177e4SLinus Torvalds HOSTDATA(shpnt)->in_intr--;
24361da177e4SLinus Torvalds SETBITS(DMACNTRL0, INTEN);
24371da177e4SLinus Torvalds DO_UNLOCK(flags);
24381da177e4SLinus Torvalds }
24391da177e4SLinus Torvalds
24401da177e4SLinus Torvalds
24411da177e4SLinus Torvalds /*
24421da177e4SLinus Torvalds * Dump the current driver status and panic
24431da177e4SLinus Torvalds */
aha152x_error(struct Scsi_Host * shpnt,char * msg)24441da177e4SLinus Torvalds static void aha152x_error(struct Scsi_Host *shpnt, char *msg)
24451da177e4SLinus Torvalds {
2446f75ae8edSHannes Reinecke shost_printk(KERN_EMERG, shpnt, "%s\n", msg);
24471da177e4SLinus Torvalds show_queues(shpnt);
24481da177e4SLinus Torvalds panic("aha152x panic\n");
24491da177e4SLinus Torvalds }
24501da177e4SLinus Torvalds
24511da177e4SLinus Torvalds /*
24521da177e4SLinus Torvalds * display enabled interrupts
24531da177e4SLinus Torvalds */
disp_enintr(struct Scsi_Host * shpnt)24541da177e4SLinus Torvalds static void disp_enintr(struct Scsi_Host *shpnt)
24551da177e4SLinus Torvalds {
2456f75ae8edSHannes Reinecke int s0, s1;
24571da177e4SLinus Torvalds
2458f75ae8edSHannes Reinecke s0 = GETPORT(SIMODE0);
2459f75ae8edSHannes Reinecke s1 = GETPORT(SIMODE1);
24601da177e4SLinus Torvalds
2461f75ae8edSHannes Reinecke shost_printk(KERN_DEBUG, shpnt,
2462f75ae8edSHannes Reinecke "enabled interrupts (%s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n",
2463f75ae8edSHannes Reinecke (s0 & ENSELDO) ? "ENSELDO " : "",
2464f75ae8edSHannes Reinecke (s0 & ENSELDI) ? "ENSELDI " : "",
2465f75ae8edSHannes Reinecke (s0 & ENSELINGO) ? "ENSELINGO " : "",
2466f75ae8edSHannes Reinecke (s0 & ENSWRAP) ? "ENSWRAP " : "",
2467f75ae8edSHannes Reinecke (s0 & ENSDONE) ? "ENSDONE " : "",
2468f75ae8edSHannes Reinecke (s0 & ENSPIORDY) ? "ENSPIORDY " : "",
2469f75ae8edSHannes Reinecke (s0 & ENDMADONE) ? "ENDMADONE " : "",
2470f75ae8edSHannes Reinecke (s1 & ENSELTIMO) ? "ENSELTIMO " : "",
2471f75ae8edSHannes Reinecke (s1 & ENATNTARG) ? "ENATNTARG " : "",
2472f75ae8edSHannes Reinecke (s1 & ENPHASEMIS) ? "ENPHASEMIS " : "",
2473f75ae8edSHannes Reinecke (s1 & ENBUSFREE) ? "ENBUSFREE " : "",
2474f75ae8edSHannes Reinecke (s1 & ENSCSIPERR) ? "ENSCSIPERR " : "",
2475f75ae8edSHannes Reinecke (s1 & ENPHASECHG) ? "ENPHASECHG " : "",
2476f75ae8edSHannes Reinecke (s1 & ENREQINIT) ? "ENREQINIT " : "");
24771da177e4SLinus Torvalds }
24781da177e4SLinus Torvalds
24791da177e4SLinus Torvalds /*
24801da177e4SLinus Torvalds * Show the command data of a command
24811da177e4SLinus Torvalds */
show_command(struct scsi_cmnd * ptr)248291ebc1faSJohannes Thumshirn static void show_command(struct scsi_cmnd *ptr)
24831da177e4SLinus Torvalds {
248463221571SFinn Thain const int phase = aha152x_priv(ptr)->phase;
24853ac6aba3SBart Van Assche
2486f75ae8edSHannes Reinecke scsi_print_command(ptr);
2487f75ae8edSHannes Reinecke scmd_printk(KERN_DEBUG, ptr,
2488f75ae8edSHannes Reinecke "request_bufflen=%d; resid=%d; "
2489f75ae8edSHannes Reinecke "phase |%s%s%s%s%s%s%s%s%s; next=0x%p",
2490f75ae8edSHannes Reinecke scsi_bufflen(ptr), scsi_get_resid(ptr),
24913ac6aba3SBart Van Assche phase & not_issued ? "not issued|" : "",
24923ac6aba3SBart Van Assche phase & selecting ? "selecting|" : "",
24933ac6aba3SBart Van Assche phase & identified ? "identified|" : "",
24943ac6aba3SBart Van Assche phase & disconnected ? "disconnected|" : "",
24953ac6aba3SBart Van Assche phase & completed ? "completed|" : "",
24963ac6aba3SBart Van Assche phase & spiordy ? "spiordy|" : "",
24973ac6aba3SBart Van Assche phase & syncneg ? "syncneg|" : "",
24983ac6aba3SBart Van Assche phase & aborted ? "aborted|" : "",
24993ac6aba3SBart Van Assche phase & resetted ? "resetted|" : "",
25003ac6aba3SBart Van Assche SCDATA(ptr) ? SCNEXT(ptr) : NULL);
25011da177e4SLinus Torvalds }
25021da177e4SLinus Torvalds
25031da177e4SLinus Torvalds /*
25041da177e4SLinus Torvalds * Dump the queued data
25051da177e4SLinus Torvalds */
show_queues(struct Scsi_Host * shpnt)25061da177e4SLinus Torvalds static void show_queues(struct Scsi_Host *shpnt)
25071da177e4SLinus Torvalds {
250891ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr;
25091da177e4SLinus Torvalds unsigned long flags;
25101da177e4SLinus Torvalds
25111da177e4SLinus Torvalds DO_LOCK(flags);
25121da177e4SLinus Torvalds printk(KERN_DEBUG "\nqueue status:\nissue_SC:\n");
25131da177e4SLinus Torvalds for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
25141da177e4SLinus Torvalds show_command(ptr);
25151da177e4SLinus Torvalds DO_UNLOCK(flags);
25161da177e4SLinus Torvalds
25171da177e4SLinus Torvalds printk(KERN_DEBUG "current_SC:\n");
25181da177e4SLinus Torvalds if (CURRENT_SC)
25191da177e4SLinus Torvalds show_command(CURRENT_SC);
25201da177e4SLinus Torvalds else
25211da177e4SLinus Torvalds printk(KERN_DEBUG "none\n");
25221da177e4SLinus Torvalds
25231da177e4SLinus Torvalds printk(KERN_DEBUG "disconnected_SC:\n");
25241da177e4SLinus Torvalds for (ptr = DISCONNECTED_SC; ptr; ptr = SCDATA(ptr) ? SCNEXT(ptr) : NULL)
25251da177e4SLinus Torvalds show_command(ptr);
25261da177e4SLinus Torvalds
25271da177e4SLinus Torvalds disp_enintr(shpnt);
25281da177e4SLinus Torvalds }
25291da177e4SLinus Torvalds
get_command(struct seq_file * m,struct scsi_cmnd * ptr)253091ebc1faSJohannes Thumshirn static void get_command(struct seq_file *m, struct scsi_cmnd * ptr)
25311da177e4SLinus Torvalds {
253263221571SFinn Thain struct aha152x_cmd_priv *acp = aha152x_priv(ptr);
253363221571SFinn Thain const int phase = acp->phase;
25341da177e4SLinus Torvalds int i;
25351da177e4SLinus Torvalds
25360c3de38fSRasmus Villemoes seq_printf(m, "%p: target=%d; lun=%d; cmnd=( ",
25379cb78c16SHannes Reinecke ptr, ptr->device->id, (u8)ptr->device->lun);
25381da177e4SLinus Torvalds
25391da177e4SLinus Torvalds for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++)
25400c3de38fSRasmus Villemoes seq_printf(m, "0x%02x ", ptr->cmnd[i]);
25411da177e4SLinus Torvalds
25420c3de38fSRasmus Villemoes seq_printf(m, "); resid=%d; residual=%d; buffers=%d; phase |",
254363221571SFinn Thain scsi_get_resid(ptr), acp->this_residual,
254463221571SFinn Thain sg_nents(acp->buffer) - 1);
25451da177e4SLinus Torvalds
25463ac6aba3SBart Van Assche if (phase & not_issued)
2547ee7c7277SRasmus Villemoes seq_puts(m, "not issued|");
25483ac6aba3SBart Van Assche if (phase & selecting)
2549ee7c7277SRasmus Villemoes seq_puts(m, "selecting|");
25503ac6aba3SBart Van Assche if (phase & disconnected)
2551ee7c7277SRasmus Villemoes seq_puts(m, "disconnected|");
25523ac6aba3SBart Van Assche if (phase & aborted)
2553ee7c7277SRasmus Villemoes seq_puts(m, "aborted|");
25543ac6aba3SBart Van Assche if (phase & identified)
2555ee7c7277SRasmus Villemoes seq_puts(m, "identified|");
25563ac6aba3SBart Van Assche if (phase & completed)
2557ee7c7277SRasmus Villemoes seq_puts(m, "completed|");
25583ac6aba3SBart Van Assche if (phase & spiordy)
2559ee7c7277SRasmus Villemoes seq_puts(m, "spiordy|");
25603ac6aba3SBart Van Assche if (phase & syncneg)
2561ee7c7277SRasmus Villemoes seq_puts(m, "syncneg|");
25620c3de38fSRasmus Villemoes seq_printf(m, "; next=0x%p\n", SCNEXT(ptr));
25631da177e4SLinus Torvalds }
25641da177e4SLinus Torvalds
get_ports(struct seq_file * m,struct Scsi_Host * shpnt)2565275084cbSAl Viro static void get_ports(struct seq_file *m, struct Scsi_Host *shpnt)
25661da177e4SLinus Torvalds {
25671da177e4SLinus Torvalds int s;
25681da177e4SLinus Torvalds
25690c3de38fSRasmus Villemoes seq_printf(m, "\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name);
25701da177e4SLinus Torvalds
25711da177e4SLinus Torvalds s = GETPORT(SCSISEQ);
2572ee7c7277SRasmus Villemoes seq_puts(m, "SCSISEQ( ");
25731da177e4SLinus Torvalds if (s & TEMODEO)
2574ee7c7277SRasmus Villemoes seq_puts(m, "TARGET MODE ");
25751da177e4SLinus Torvalds if (s & ENSELO)
2576ee7c7277SRasmus Villemoes seq_puts(m, "SELO ");
25771da177e4SLinus Torvalds if (s & ENSELI)
2578ee7c7277SRasmus Villemoes seq_puts(m, "SELI ");
25791da177e4SLinus Torvalds if (s & ENRESELI)
2580ee7c7277SRasmus Villemoes seq_puts(m, "RESELI ");
25811da177e4SLinus Torvalds if (s & ENAUTOATNO)
2582ee7c7277SRasmus Villemoes seq_puts(m, "AUTOATNO ");
25831da177e4SLinus Torvalds if (s & ENAUTOATNI)
2584ee7c7277SRasmus Villemoes seq_puts(m, "AUTOATNI ");
25851da177e4SLinus Torvalds if (s & ENAUTOATNP)
2586ee7c7277SRasmus Villemoes seq_puts(m, "AUTOATNP ");
25871da177e4SLinus Torvalds if (s & SCSIRSTO)
2588ee7c7277SRasmus Villemoes seq_puts(m, "SCSIRSTO ");
2589ee7c7277SRasmus Villemoes seq_puts(m, ");");
25901da177e4SLinus Torvalds
2591ee7c7277SRasmus Villemoes seq_puts(m, " SCSISIG(");
25921da177e4SLinus Torvalds s = GETPORT(SCSISIG);
25931da177e4SLinus Torvalds switch (s & P_MASK) {
25941da177e4SLinus Torvalds case P_DATAO:
2595ee7c7277SRasmus Villemoes seq_puts(m, "DATA OUT");
25961da177e4SLinus Torvalds break;
25971da177e4SLinus Torvalds case P_DATAI:
2598ee7c7277SRasmus Villemoes seq_puts(m, "DATA IN");
25991da177e4SLinus Torvalds break;
26001da177e4SLinus Torvalds case P_CMD:
2601ee7c7277SRasmus Villemoes seq_puts(m, "COMMAND");
26021da177e4SLinus Torvalds break;
26031da177e4SLinus Torvalds case P_STATUS:
2604ee7c7277SRasmus Villemoes seq_puts(m, "STATUS");
26051da177e4SLinus Torvalds break;
26061da177e4SLinus Torvalds case P_MSGO:
2607ee7c7277SRasmus Villemoes seq_puts(m, "MESSAGE OUT");
26081da177e4SLinus Torvalds break;
26091da177e4SLinus Torvalds case P_MSGI:
2610ee7c7277SRasmus Villemoes seq_puts(m, "MESSAGE IN");
26111da177e4SLinus Torvalds break;
26121da177e4SLinus Torvalds default:
2613ee7c7277SRasmus Villemoes seq_puts(m, "*invalid*");
26141da177e4SLinus Torvalds break;
26151da177e4SLinus Torvalds }
26161da177e4SLinus Torvalds
2617ee7c7277SRasmus Villemoes seq_puts(m, "); ");
26181da177e4SLinus Torvalds
26190c3de38fSRasmus Villemoes seq_printf(m, "INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
26201da177e4SLinus Torvalds
2621ee7c7277SRasmus Villemoes seq_puts(m, "SSTAT( ");
26221da177e4SLinus Torvalds s = GETPORT(SSTAT0);
26231da177e4SLinus Torvalds if (s & TARGET)
2624ee7c7277SRasmus Villemoes seq_puts(m, "TARGET ");
26251da177e4SLinus Torvalds if (s & SELDO)
2626ee7c7277SRasmus Villemoes seq_puts(m, "SELDO ");
26271da177e4SLinus Torvalds if (s & SELDI)
2628ee7c7277SRasmus Villemoes seq_puts(m, "SELDI ");
26291da177e4SLinus Torvalds if (s & SELINGO)
2630ee7c7277SRasmus Villemoes seq_puts(m, "SELINGO ");
26311da177e4SLinus Torvalds if (s & SWRAP)
2632ee7c7277SRasmus Villemoes seq_puts(m, "SWRAP ");
26331da177e4SLinus Torvalds if (s & SDONE)
2634ee7c7277SRasmus Villemoes seq_puts(m, "SDONE ");
26351da177e4SLinus Torvalds if (s & SPIORDY)
2636ee7c7277SRasmus Villemoes seq_puts(m, "SPIORDY ");
26371da177e4SLinus Torvalds if (s & DMADONE)
2638ee7c7277SRasmus Villemoes seq_puts(m, "DMADONE ");
26391da177e4SLinus Torvalds
26401da177e4SLinus Torvalds s = GETPORT(SSTAT1);
26411da177e4SLinus Torvalds if (s & SELTO)
2642ee7c7277SRasmus Villemoes seq_puts(m, "SELTO ");
26431da177e4SLinus Torvalds if (s & ATNTARG)
2644ee7c7277SRasmus Villemoes seq_puts(m, "ATNTARG ");
26451da177e4SLinus Torvalds if (s & SCSIRSTI)
2646ee7c7277SRasmus Villemoes seq_puts(m, "SCSIRSTI ");
26471da177e4SLinus Torvalds if (s & PHASEMIS)
2648ee7c7277SRasmus Villemoes seq_puts(m, "PHASEMIS ");
26491da177e4SLinus Torvalds if (s & BUSFREE)
2650ee7c7277SRasmus Villemoes seq_puts(m, "BUSFREE ");
26511da177e4SLinus Torvalds if (s & SCSIPERR)
2652ee7c7277SRasmus Villemoes seq_puts(m, "SCSIPERR ");
26531da177e4SLinus Torvalds if (s & PHASECHG)
2654ee7c7277SRasmus Villemoes seq_puts(m, "PHASECHG ");
26551da177e4SLinus Torvalds if (s & REQINIT)
2656ee7c7277SRasmus Villemoes seq_puts(m, "REQINIT ");
2657ee7c7277SRasmus Villemoes seq_puts(m, "); ");
26581da177e4SLinus Torvalds
26591da177e4SLinus Torvalds
2660ee7c7277SRasmus Villemoes seq_puts(m, "SSTAT( ");
26611da177e4SLinus Torvalds
26621da177e4SLinus Torvalds s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
26631da177e4SLinus Torvalds
26641da177e4SLinus Torvalds if (s & TARGET)
2665ee7c7277SRasmus Villemoes seq_puts(m, "TARGET ");
26661da177e4SLinus Torvalds if (s & SELDO)
2667ee7c7277SRasmus Villemoes seq_puts(m, "SELDO ");
26681da177e4SLinus Torvalds if (s & SELDI)
2669ee7c7277SRasmus Villemoes seq_puts(m, "SELDI ");
26701da177e4SLinus Torvalds if (s & SELINGO)
2671ee7c7277SRasmus Villemoes seq_puts(m, "SELINGO ");
26721da177e4SLinus Torvalds if (s & SWRAP)
2673ee7c7277SRasmus Villemoes seq_puts(m, "SWRAP ");
26741da177e4SLinus Torvalds if (s & SDONE)
2675ee7c7277SRasmus Villemoes seq_puts(m, "SDONE ");
26761da177e4SLinus Torvalds if (s & SPIORDY)
2677ee7c7277SRasmus Villemoes seq_puts(m, "SPIORDY ");
26781da177e4SLinus Torvalds if (s & DMADONE)
2679ee7c7277SRasmus Villemoes seq_puts(m, "DMADONE ");
26801da177e4SLinus Torvalds
26811da177e4SLinus Torvalds s = GETPORT(SSTAT1) & GETPORT(SIMODE1);
26821da177e4SLinus Torvalds
26831da177e4SLinus Torvalds if (s & SELTO)
2684ee7c7277SRasmus Villemoes seq_puts(m, "SELTO ");
26851da177e4SLinus Torvalds if (s & ATNTARG)
2686ee7c7277SRasmus Villemoes seq_puts(m, "ATNTARG ");
26871da177e4SLinus Torvalds if (s & SCSIRSTI)
2688ee7c7277SRasmus Villemoes seq_puts(m, "SCSIRSTI ");
26891da177e4SLinus Torvalds if (s & PHASEMIS)
2690ee7c7277SRasmus Villemoes seq_puts(m, "PHASEMIS ");
26911da177e4SLinus Torvalds if (s & BUSFREE)
2692ee7c7277SRasmus Villemoes seq_puts(m, "BUSFREE ");
26931da177e4SLinus Torvalds if (s & SCSIPERR)
2694ee7c7277SRasmus Villemoes seq_puts(m, "SCSIPERR ");
26951da177e4SLinus Torvalds if (s & PHASECHG)
2696ee7c7277SRasmus Villemoes seq_puts(m, "PHASECHG ");
26971da177e4SLinus Torvalds if (s & REQINIT)
2698ee7c7277SRasmus Villemoes seq_puts(m, "REQINIT ");
2699ee7c7277SRasmus Villemoes seq_puts(m, "); ");
27001da177e4SLinus Torvalds
2701ee7c7277SRasmus Villemoes seq_puts(m, "SXFRCTL0( ");
27021da177e4SLinus Torvalds
27031da177e4SLinus Torvalds s = GETPORT(SXFRCTL0);
27041da177e4SLinus Torvalds if (s & SCSIEN)
2705ee7c7277SRasmus Villemoes seq_puts(m, "SCSIEN ");
27061da177e4SLinus Torvalds if (s & DMAEN)
2707ee7c7277SRasmus Villemoes seq_puts(m, "DMAEN ");
27081da177e4SLinus Torvalds if (s & CH1)
2709ee7c7277SRasmus Villemoes seq_puts(m, "CH1 ");
27101da177e4SLinus Torvalds if (s & CLRSTCNT)
2711ee7c7277SRasmus Villemoes seq_puts(m, "CLRSTCNT ");
27121da177e4SLinus Torvalds if (s & SPIOEN)
2713ee7c7277SRasmus Villemoes seq_puts(m, "SPIOEN ");
27141da177e4SLinus Torvalds if (s & CLRCH1)
2715ee7c7277SRasmus Villemoes seq_puts(m, "CLRCH1 ");
2716ee7c7277SRasmus Villemoes seq_puts(m, "); ");
27171da177e4SLinus Torvalds
2718ee7c7277SRasmus Villemoes seq_puts(m, "SIGNAL( ");
27191da177e4SLinus Torvalds
27201da177e4SLinus Torvalds s = GETPORT(SCSISIG);
27211da177e4SLinus Torvalds if (s & SIG_ATNI)
2722ee7c7277SRasmus Villemoes seq_puts(m, "ATNI ");
27231da177e4SLinus Torvalds if (s & SIG_SELI)
2724ee7c7277SRasmus Villemoes seq_puts(m, "SELI ");
27251da177e4SLinus Torvalds if (s & SIG_BSYI)
2726ee7c7277SRasmus Villemoes seq_puts(m, "BSYI ");
27271da177e4SLinus Torvalds if (s & SIG_REQI)
2728ee7c7277SRasmus Villemoes seq_puts(m, "REQI ");
27291da177e4SLinus Torvalds if (s & SIG_ACKI)
2730ee7c7277SRasmus Villemoes seq_puts(m, "ACKI ");
2731ee7c7277SRasmus Villemoes seq_puts(m, "); ");
27321da177e4SLinus Torvalds
27330c3de38fSRasmus Villemoes seq_printf(m, "SELID(%02x), ", GETPORT(SELID));
27341da177e4SLinus Torvalds
27350c3de38fSRasmus Villemoes seq_printf(m, "STCNT(%d), ", GETSTCNT());
27361da177e4SLinus Torvalds
2737ee7c7277SRasmus Villemoes seq_puts(m, "SSTAT2( ");
27381da177e4SLinus Torvalds
27391da177e4SLinus Torvalds s = GETPORT(SSTAT2);
27401da177e4SLinus Torvalds if (s & SOFFSET)
2741ee7c7277SRasmus Villemoes seq_puts(m, "SOFFSET ");
27421da177e4SLinus Torvalds if (s & SEMPTY)
2743ee7c7277SRasmus Villemoes seq_puts(m, "SEMPTY ");
27441da177e4SLinus Torvalds if (s & SFULL)
2745ee7c7277SRasmus Villemoes seq_puts(m, "SFULL ");
27460c3de38fSRasmus Villemoes seq_printf(m, "); SFCNT (%d); ", s & (SFULL | SFCNT));
27471da177e4SLinus Torvalds
27481da177e4SLinus Torvalds s = GETPORT(SSTAT3);
27490c3de38fSRasmus Villemoes seq_printf(m, "SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
27501da177e4SLinus Torvalds
2751ee7c7277SRasmus Villemoes seq_puts(m, "SSTAT4( ");
27521da177e4SLinus Torvalds s = GETPORT(SSTAT4);
27531da177e4SLinus Torvalds if (s & SYNCERR)
2754ee7c7277SRasmus Villemoes seq_puts(m, "SYNCERR ");
27551da177e4SLinus Torvalds if (s & FWERR)
2756ee7c7277SRasmus Villemoes seq_puts(m, "FWERR ");
27571da177e4SLinus Torvalds if (s & FRERR)
2758ee7c7277SRasmus Villemoes seq_puts(m, "FRERR ");
2759ee7c7277SRasmus Villemoes seq_puts(m, "); ");
27601da177e4SLinus Torvalds
2761ee7c7277SRasmus Villemoes seq_puts(m, "DMACNTRL0( ");
27621da177e4SLinus Torvalds s = GETPORT(DMACNTRL0);
27630c3de38fSRasmus Villemoes seq_printf(m, "%s ", s & _8BIT ? "8BIT" : "16BIT");
27640c3de38fSRasmus Villemoes seq_printf(m, "%s ", s & DMA ? "DMA" : "PIO");
27650c3de38fSRasmus Villemoes seq_printf(m, "%s ", s & WRITE_READ ? "WRITE" : "READ");
27661da177e4SLinus Torvalds if (s & ENDMA)
2767ee7c7277SRasmus Villemoes seq_puts(m, "ENDMA ");
27681da177e4SLinus Torvalds if (s & INTEN)
2769ee7c7277SRasmus Villemoes seq_puts(m, "INTEN ");
27701da177e4SLinus Torvalds if (s & RSTFIFO)
2771ee7c7277SRasmus Villemoes seq_puts(m, "RSTFIFO ");
27721da177e4SLinus Torvalds if (s & SWINT)
2773ee7c7277SRasmus Villemoes seq_puts(m, "SWINT ");
2774ee7c7277SRasmus Villemoes seq_puts(m, "); ");
27751da177e4SLinus Torvalds
2776ee7c7277SRasmus Villemoes seq_puts(m, "DMASTAT( ");
27771da177e4SLinus Torvalds s = GETPORT(DMASTAT);
27781da177e4SLinus Torvalds if (s & ATDONE)
2779ee7c7277SRasmus Villemoes seq_puts(m, "ATDONE ");
27801da177e4SLinus Torvalds if (s & WORDRDY)
2781ee7c7277SRasmus Villemoes seq_puts(m, "WORDRDY ");
27821da177e4SLinus Torvalds if (s & DFIFOFULL)
2783ee7c7277SRasmus Villemoes seq_puts(m, "DFIFOFULL ");
27841da177e4SLinus Torvalds if (s & DFIFOEMP)
2785ee7c7277SRasmus Villemoes seq_puts(m, "DFIFOEMP ");
2786ee7c7277SRasmus Villemoes seq_puts(m, ")\n");
27871da177e4SLinus Torvalds
2788ee7c7277SRasmus Villemoes seq_puts(m, "enabled interrupts( ");
27891da177e4SLinus Torvalds
27901da177e4SLinus Torvalds s = GETPORT(SIMODE0);
27911da177e4SLinus Torvalds if (s & ENSELDO)
2792ee7c7277SRasmus Villemoes seq_puts(m, "ENSELDO ");
27931da177e4SLinus Torvalds if (s & ENSELDI)
2794ee7c7277SRasmus Villemoes seq_puts(m, "ENSELDI ");
27951da177e4SLinus Torvalds if (s & ENSELINGO)
2796ee7c7277SRasmus Villemoes seq_puts(m, "ENSELINGO ");
27971da177e4SLinus Torvalds if (s & ENSWRAP)
2798ee7c7277SRasmus Villemoes seq_puts(m, "ENSWRAP ");
27991da177e4SLinus Torvalds if (s & ENSDONE)
2800ee7c7277SRasmus Villemoes seq_puts(m, "ENSDONE ");
28011da177e4SLinus Torvalds if (s & ENSPIORDY)
2802ee7c7277SRasmus Villemoes seq_puts(m, "ENSPIORDY ");
28031da177e4SLinus Torvalds if (s & ENDMADONE)
2804ee7c7277SRasmus Villemoes seq_puts(m, "ENDMADONE ");
28051da177e4SLinus Torvalds
28061da177e4SLinus Torvalds s = GETPORT(SIMODE1);
28071da177e4SLinus Torvalds if (s & ENSELTIMO)
2808ee7c7277SRasmus Villemoes seq_puts(m, "ENSELTIMO ");
28091da177e4SLinus Torvalds if (s & ENATNTARG)
2810ee7c7277SRasmus Villemoes seq_puts(m, "ENATNTARG ");
28111da177e4SLinus Torvalds if (s & ENPHASEMIS)
2812ee7c7277SRasmus Villemoes seq_puts(m, "ENPHASEMIS ");
28131da177e4SLinus Torvalds if (s & ENBUSFREE)
2814ee7c7277SRasmus Villemoes seq_puts(m, "ENBUSFREE ");
28151da177e4SLinus Torvalds if (s & ENSCSIPERR)
2816ee7c7277SRasmus Villemoes seq_puts(m, "ENSCSIPERR ");
28171da177e4SLinus Torvalds if (s & ENPHASECHG)
2818ee7c7277SRasmus Villemoes seq_puts(m, "ENPHASECHG ");
28191da177e4SLinus Torvalds if (s & ENREQINIT)
2820ee7c7277SRasmus Villemoes seq_puts(m, "ENREQINIT ");
2821ee7c7277SRasmus Villemoes seq_puts(m, ")\n");
28221da177e4SLinus Torvalds }
28231da177e4SLinus Torvalds
aha152x_set_info(struct Scsi_Host * shpnt,char * buffer,int length)2824275084cbSAl Viro static int aha152x_set_info(struct Scsi_Host *shpnt, char *buffer, int length)
28251da177e4SLinus Torvalds {
28261da177e4SLinus Torvalds if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0)
28271da177e4SLinus Torvalds return -EINVAL;
28281da177e4SLinus Torvalds
28291da177e4SLinus Torvalds #if defined(AHA152X_STAT)
28301da177e4SLinus Torvalds if(length>13 && strncmp("reset", buffer+8, 5)==0) {
28311da177e4SLinus Torvalds int i;
28321da177e4SLinus Torvalds
28331da177e4SLinus Torvalds HOSTDATA(shpnt)->total_commands=0;
28341da177e4SLinus Torvalds HOSTDATA(shpnt)->disconnections=0;
28351da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_any_action=0;
28361da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_old_command=0;
28371da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_new_command=0;
28381da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_done_command=0;
28391da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_with_check_condition=0;
28401da177e4SLinus Torvalds for (i = idle; i<maxstate; i++) {
28411da177e4SLinus Torvalds HOSTDATA(shpnt)->count[i]=0;
28421da177e4SLinus Torvalds HOSTDATA(shpnt)->count_trans[i]=0;
28431da177e4SLinus Torvalds HOSTDATA(shpnt)->time[i]=0;
28441da177e4SLinus Torvalds }
28451da177e4SLinus Torvalds
2846f75ae8edSHannes Reinecke shost_printk(KERN_INFO, shpnt, "aha152x: stats reset.\n");
28471da177e4SLinus Torvalds
28481da177e4SLinus Torvalds } else
28491da177e4SLinus Torvalds #endif
28501da177e4SLinus Torvalds {
28511da177e4SLinus Torvalds return -EINVAL;
28521da177e4SLinus Torvalds }
28531da177e4SLinus Torvalds
28541da177e4SLinus Torvalds
28551da177e4SLinus Torvalds return length;
28561da177e4SLinus Torvalds }
28571da177e4SLinus Torvalds
aha152x_show_info(struct seq_file * m,struct Scsi_Host * shpnt)2858275084cbSAl Viro static int aha152x_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
28591da177e4SLinus Torvalds {
28601da177e4SLinus Torvalds int i;
286191ebc1faSJohannes Thumshirn struct scsi_cmnd *ptr;
28621da177e4SLinus Torvalds unsigned long flags;
28631da177e4SLinus Torvalds
2864ee7c7277SRasmus Villemoes seq_puts(m, AHA152X_REVID "\n");
28651da177e4SLinus Torvalds
28660c3de38fSRasmus Villemoes seq_printf(m, "ioports 0x%04lx to 0x%04lx\n",
28671da177e4SLinus Torvalds shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1);
28680c3de38fSRasmus Villemoes seq_printf(m, "interrupt 0x%02x\n", shpnt->irq);
28690c3de38fSRasmus Villemoes seq_printf(m, "disconnection/reconnection %s\n",
28701da177e4SLinus Torvalds RECONNECT ? "enabled" : "disabled");
28710c3de38fSRasmus Villemoes seq_printf(m, "parity checking %s\n",
28721da177e4SLinus Torvalds PARITY ? "enabled" : "disabled");
28730c3de38fSRasmus Villemoes seq_printf(m, "synchronous transfers %s\n",
28741da177e4SLinus Torvalds SYNCHRONOUS ? "enabled" : "disabled");
28750c3de38fSRasmus Villemoes seq_printf(m, "%d commands currently queued\n", HOSTDATA(shpnt)->commands);
28761da177e4SLinus Torvalds
28771da177e4SLinus Torvalds if(SYNCHRONOUS) {
2878ee7c7277SRasmus Villemoes seq_puts(m, "synchronously operating targets (tick=50 ns):\n");
28791da177e4SLinus Torvalds for (i = 0; i < 8; i++)
28801da177e4SLinus Torvalds if (HOSTDATA(shpnt)->syncrate[i] & 0x7f)
28810c3de38fSRasmus Villemoes seq_printf(m, "target %d: period %dT/%dns; req/ack offset %d\n",
28821da177e4SLinus Torvalds i,
28831da177e4SLinus Torvalds (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2),
28841da177e4SLinus Torvalds (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50,
28851da177e4SLinus Torvalds HOSTDATA(shpnt)->syncrate[i] & 0x0f);
28861da177e4SLinus Torvalds }
2887ee7c7277SRasmus Villemoes seq_puts(m, "\nqueue status:\n");
28881da177e4SLinus Torvalds DO_LOCK(flags);
28891da177e4SLinus Torvalds if (ISSUE_SC) {
2890ee7c7277SRasmus Villemoes seq_puts(m, "not yet issued commands:\n");
28911da177e4SLinus Torvalds for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
2892275084cbSAl Viro get_command(m, ptr);
28931da177e4SLinus Torvalds } else
2894ee7c7277SRasmus Villemoes seq_puts(m, "no not yet issued commands\n");
28951da177e4SLinus Torvalds DO_UNLOCK(flags);
28961da177e4SLinus Torvalds
28971da177e4SLinus Torvalds if (CURRENT_SC) {
2898ee7c7277SRasmus Villemoes seq_puts(m, "current command:\n");
2899275084cbSAl Viro get_command(m, CURRENT_SC);
29001da177e4SLinus Torvalds } else
2901ee7c7277SRasmus Villemoes seq_puts(m, "no current command\n");
29021da177e4SLinus Torvalds
29031da177e4SLinus Torvalds if (DISCONNECTED_SC) {
2904ee7c7277SRasmus Villemoes seq_puts(m, "disconnected commands:\n");
29051da177e4SLinus Torvalds for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr))
2906275084cbSAl Viro get_command(m, ptr);
29071da177e4SLinus Torvalds } else
2908ee7c7277SRasmus Villemoes seq_puts(m, "no disconnected commands\n");
29091da177e4SLinus Torvalds
2910275084cbSAl Viro get_ports(m, shpnt);
29111da177e4SLinus Torvalds
29121da177e4SLinus Torvalds #if defined(AHA152X_STAT)
29130c3de38fSRasmus Villemoes seq_printf(m, "statistics:\n"
29141da177e4SLinus Torvalds "total commands: %d\n"
29151da177e4SLinus Torvalds "disconnections: %d\n"
29161da177e4SLinus Torvalds "busfree with check condition: %d\n"
29171da177e4SLinus Torvalds "busfree without old command: %d\n"
29181da177e4SLinus Torvalds "busfree without new command: %d\n"
29191da177e4SLinus Torvalds "busfree without done command: %d\n"
29201da177e4SLinus Torvalds "busfree without any action: %d\n"
29211da177e4SLinus Torvalds "state "
29221da177e4SLinus Torvalds "transitions "
29231da177e4SLinus Torvalds "count "
29241da177e4SLinus Torvalds "time\n",
29251da177e4SLinus Torvalds HOSTDATA(shpnt)->total_commands,
29261da177e4SLinus Torvalds HOSTDATA(shpnt)->disconnections,
29271da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_with_check_condition,
29281da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_old_command,
29291da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_new_command,
29301da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_done_command,
29311da177e4SLinus Torvalds HOSTDATA(shpnt)->busfree_without_any_action);
29321da177e4SLinus Torvalds for(i=0; i<maxstate; i++) {
29330c3de38fSRasmus Villemoes seq_printf(m, "%-10s %-12d %-12d %-12ld\n",
29341da177e4SLinus Torvalds states[i].name,
29351da177e4SLinus Torvalds HOSTDATA(shpnt)->count_trans[i],
29361da177e4SLinus Torvalds HOSTDATA(shpnt)->count[i],
29371da177e4SLinus Torvalds HOSTDATA(shpnt)->time[i]);
29381da177e4SLinus Torvalds }
29391da177e4SLinus Torvalds #endif
29401da177e4SLinus Torvalds return 0;
29411da177e4SLinus Torvalds }
29421da177e4SLinus Torvalds
aha152x_adjust_queue(struct scsi_device * device)2943b1ee0795SBoaz Harrosh static int aha152x_adjust_queue(struct scsi_device *device)
2944b1ee0795SBoaz Harrosh {
2945b1ee0795SBoaz Harrosh blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH);
2946b1ee0795SBoaz Harrosh return 0;
2947b1ee0795SBoaz Harrosh }
2948b1ee0795SBoaz Harrosh
2949*11e58ceaSBart Van Assche static const struct scsi_host_template aha152x_driver_template = {
29501da177e4SLinus Torvalds .module = THIS_MODULE,
29511da177e4SLinus Torvalds .name = AHA152X_REVID,
29521da177e4SLinus Torvalds .proc_name = "aha152x",
2953275084cbSAl Viro .show_info = aha152x_show_info,
2954275084cbSAl Viro .write_info = aha152x_set_info,
29551da177e4SLinus Torvalds .queuecommand = aha152x_queue,
29561da177e4SLinus Torvalds .eh_abort_handler = aha152x_abort,
29571da177e4SLinus Torvalds .eh_device_reset_handler = aha152x_device_reset,
29581da177e4SLinus Torvalds .eh_bus_reset_handler = aha152x_bus_reset,
29591da177e4SLinus Torvalds .bios_param = aha152x_biosparam,
29601da177e4SLinus Torvalds .can_queue = 1,
29611da177e4SLinus Torvalds .this_id = 7,
29621da177e4SLinus Torvalds .sg_tablesize = SG_ALL,
29634af14d11SChristoph Hellwig .dma_boundary = PAGE_SIZE - 1,
2964b1ee0795SBoaz Harrosh .slave_alloc = aha152x_adjust_queue,
29653ac6aba3SBart Van Assche .cmd_size = sizeof(struct aha152x_cmd_priv),
29661da177e4SLinus Torvalds };
29671da177e4SLinus Torvalds
29683eb2ebcbSChristoph Hellwig #if !defined(AHA152X_PCMCIA)
29691da177e4SLinus Torvalds static int setup_count;
29701da177e4SLinus Torvalds static struct aha152x_setup setup[2];
29711da177e4SLinus Torvalds
29721da177e4SLinus Torvalds /* possible i/o addresses for the AIC-6260; default first */
29731da177e4SLinus Torvalds static unsigned short ports[] = { 0x340, 0x140 };
29741da177e4SLinus Torvalds
29751da177e4SLinus Torvalds #if !defined(SKIP_BIOSTEST)
29761da177e4SLinus Torvalds /* possible locations for the Adaptec BIOS; defaults first */
29771da177e4SLinus Torvalds static unsigned int addresses[] =
29781da177e4SLinus Torvalds {
29791da177e4SLinus Torvalds 0xdc000, /* default first */
29801da177e4SLinus Torvalds 0xc8000,
29811da177e4SLinus Torvalds 0xcc000,
29821da177e4SLinus Torvalds 0xd0000,
29831da177e4SLinus Torvalds 0xd4000,
29841da177e4SLinus Torvalds 0xd8000,
29851da177e4SLinus Torvalds 0xe0000,
29861da177e4SLinus Torvalds 0xeb800, /* VTech Platinum SMP */
29871da177e4SLinus Torvalds 0xf0000,
29881da177e4SLinus Torvalds };
29891da177e4SLinus Torvalds
29901da177e4SLinus Torvalds /* signatures for various AIC-6[23]60 based controllers.
29911da177e4SLinus Torvalds The point in detecting signatures is to avoid useless and maybe
29921da177e4SLinus Torvalds harmful probes on ports. I'm not sure that all listed boards pass
29931da177e4SLinus Torvalds auto-configuration. For those which fail the BIOS signature is
29941da177e4SLinus Torvalds obsolete, because user intervention to supply the configuration is
29951da177e4SLinus Torvalds needed anyway. May be an information whether or not the BIOS supports
29961da177e4SLinus Torvalds extended translation could be also useful here. */
29971da177e4SLinus Torvalds static struct signature {
29981da177e4SLinus Torvalds unsigned char *signature;
29991da177e4SLinus Torvalds int sig_offset;
30001da177e4SLinus Torvalds int sig_length;
30011da177e4SLinus Torvalds } signatures[] =
30021da177e4SLinus Torvalds {
30031da177e4SLinus Torvalds { "Adaptec AHA-1520 BIOS", 0x102e, 21 },
30041da177e4SLinus Torvalds /* Adaptec 152x */
30051da177e4SLinus Torvalds { "Adaptec AHA-1520B", 0x000b, 17 },
30061da177e4SLinus Torvalds /* Adaptec 152x rev B */
30071da177e4SLinus Torvalds { "Adaptec AHA-1520B", 0x0026, 17 },
30081da177e4SLinus Torvalds /* Iomega Jaz Jet ISA (AIC6370Q) */
30091da177e4SLinus Torvalds { "Adaptec ASW-B626 BIOS", 0x1029, 21 },
30101da177e4SLinus Torvalds /* on-board controller */
30111da177e4SLinus Torvalds { "Adaptec BIOS: ASW-B626", 0x000f, 22 },
30121da177e4SLinus Torvalds /* on-board controller */
30131da177e4SLinus Torvalds { "Adaptec ASW-B626 S2", 0x2e6c, 19 },
30141da177e4SLinus Torvalds /* on-board controller */
30151da177e4SLinus Torvalds { "Adaptec BIOS:AIC-6360", 0x000c, 21 },
30161da177e4SLinus Torvalds /* on-board controller */
30171da177e4SLinus Torvalds { "ScsiPro SP-360 BIOS", 0x2873, 19 },
30181da177e4SLinus Torvalds /* ScsiPro-Controller */
30191da177e4SLinus Torvalds { "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 },
30201da177e4SLinus Torvalds /* Gigabyte Local-Bus-SCSI */
30211da177e4SLinus Torvalds { "Adaptec BIOS:AVA-282X", 0x000c, 21 },
30221da177e4SLinus Torvalds /* Adaptec 282x */
30231da177e4SLinus Torvalds { "Adaptec IBM Dock II SCSI", 0x2edd, 24 },
30241da177e4SLinus Torvalds /* IBM Thinkpad Dock II */
30251da177e4SLinus Torvalds { "Adaptec BIOS:AHA-1532P", 0x001c, 22 },
30261da177e4SLinus Torvalds /* IBM Thinkpad Dock II SCSI */
30271da177e4SLinus Torvalds { "DTC3520A Host Adapter BIOS", 0x318a, 26 },
30281da177e4SLinus Torvalds /* DTC 3520A ISA SCSI */
30291da177e4SLinus Torvalds };
30301da177e4SLinus Torvalds #endif /* !SKIP_BIOSTEST */
30311da177e4SLinus Torvalds
30321da177e4SLinus Torvalds /*
30331da177e4SLinus Torvalds * Test, if port_base is valid.
30341da177e4SLinus Torvalds *
30351da177e4SLinus Torvalds */
aha152x_porttest(int io_port)30361da177e4SLinus Torvalds static int aha152x_porttest(int io_port)
30371da177e4SLinus Torvalds {
30381da177e4SLinus Torvalds int i;
30391da177e4SLinus Torvalds
30401da177e4SLinus Torvalds SETPORT(io_port + O_DMACNTRL1, 0); /* reset stack pointer */
30411da177e4SLinus Torvalds for (i = 0; i < 16; i++)
30421da177e4SLinus Torvalds SETPORT(io_port + O_STACK, i);
30431da177e4SLinus Torvalds
30441da177e4SLinus Torvalds SETPORT(io_port + O_DMACNTRL1, 0); /* reset stack pointer */
30451da177e4SLinus Torvalds for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++)
30461da177e4SLinus Torvalds ;
30471da177e4SLinus Torvalds
30481da177e4SLinus Torvalds return (i == 16);
30491da177e4SLinus Torvalds }
30501da177e4SLinus Torvalds
tc1550_porttest(int io_port)30511da177e4SLinus Torvalds static int tc1550_porttest(int io_port)
30521da177e4SLinus Torvalds {
30531da177e4SLinus Torvalds int i;
30541da177e4SLinus Torvalds
30551da177e4SLinus Torvalds SETPORT(io_port + O_TC_DMACNTRL1, 0); /* reset stack pointer */
30561da177e4SLinus Torvalds for (i = 0; i < 16; i++)
30571da177e4SLinus Torvalds SETPORT(io_port + O_STACK, i);
30581da177e4SLinus Torvalds
30591da177e4SLinus Torvalds SETPORT(io_port + O_TC_DMACNTRL1, 0); /* reset stack pointer */
30601da177e4SLinus Torvalds for (i = 0; i < 16 && GETPORT(io_port + O_TC_STACK) == i; i++)
30611da177e4SLinus Torvalds ;
30621da177e4SLinus Torvalds
30631da177e4SLinus Torvalds return (i == 16);
30641da177e4SLinus Torvalds }
30651da177e4SLinus Torvalds
30661da177e4SLinus Torvalds
checksetup(struct aha152x_setup * setup)30671da177e4SLinus Torvalds static int checksetup(struct aha152x_setup *setup)
30681da177e4SLinus Torvalds {
30691da177e4SLinus Torvalds int i;
30701da177e4SLinus Torvalds for (i = 0; i < ARRAY_SIZE(ports) && (setup->io_port != ports[i]); i++)
30711da177e4SLinus Torvalds ;
30721da177e4SLinus Torvalds
30731da177e4SLinus Torvalds if (i == ARRAY_SIZE(ports))
30741da177e4SLinus Torvalds return 0;
30751da177e4SLinus Torvalds
30769bcf0910SHarvey Harrison if (!request_region(setup->io_port, IO_RANGE, "aha152x")) {
30771da177e4SLinus Torvalds printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup->io_port);
30781da177e4SLinus Torvalds return 0;
30791da177e4SLinus Torvalds }
30801da177e4SLinus Torvalds
30811da177e4SLinus Torvalds if( aha152x_porttest(setup->io_port) ) {
30821da177e4SLinus Torvalds setup->tc1550=0;
30831da177e4SLinus Torvalds } else if( tc1550_porttest(setup->io_port) ) {
30841da177e4SLinus Torvalds setup->tc1550=1;
30851da177e4SLinus Torvalds } else {
30861da177e4SLinus Torvalds release_region(setup->io_port, IO_RANGE);
30871da177e4SLinus Torvalds return 0;
30881da177e4SLinus Torvalds }
30891da177e4SLinus Torvalds
30901da177e4SLinus Torvalds release_region(setup->io_port, IO_RANGE);
30911da177e4SLinus Torvalds
30921da177e4SLinus Torvalds if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX))
30931da177e4SLinus Torvalds return 0;
30941da177e4SLinus Torvalds
30951da177e4SLinus Torvalds if ((setup->scsiid < 0) || (setup->scsiid > 7))
30961da177e4SLinus Torvalds return 0;
30971da177e4SLinus Torvalds
30981da177e4SLinus Torvalds if ((setup->reconnect < 0) || (setup->reconnect > 1))
30991da177e4SLinus Torvalds return 0;
31001da177e4SLinus Torvalds
31011da177e4SLinus Torvalds if ((setup->parity < 0) || (setup->parity > 1))
31021da177e4SLinus Torvalds return 0;
31031da177e4SLinus Torvalds
31041da177e4SLinus Torvalds if ((setup->synchronous < 0) || (setup->synchronous > 1))
31051da177e4SLinus Torvalds return 0;
31061da177e4SLinus Torvalds
31071da177e4SLinus Torvalds if ((setup->ext_trans < 0) || (setup->ext_trans > 1))
31081da177e4SLinus Torvalds return 0;
31091da177e4SLinus Torvalds
31101da177e4SLinus Torvalds
31111da177e4SLinus Torvalds return 1;
31121da177e4SLinus Torvalds }
31131da177e4SLinus Torvalds
31141da177e4SLinus Torvalds
aha152x_init(void)31151da177e4SLinus Torvalds static int __init aha152x_init(void)
31161da177e4SLinus Torvalds {
31171da177e4SLinus Torvalds int i, j, ok;
31181da177e4SLinus Torvalds #if defined(AUTOCONF)
31191da177e4SLinus Torvalds aha152x_config conf;
31201da177e4SLinus Torvalds #endif
31211da177e4SLinus Torvalds #ifdef __ISAPNP__
31221da177e4SLinus Torvalds struct pnp_dev *dev=NULL, *pnpdev[2] = {NULL, NULL};
31231da177e4SLinus Torvalds #endif
31241da177e4SLinus Torvalds
31251da177e4SLinus Torvalds if ( setup_count ) {
31261da177e4SLinus Torvalds printk(KERN_INFO "aha152x: processing commandline: ");
31271da177e4SLinus Torvalds
31281da177e4SLinus Torvalds for (i = 0; i<setup_count; i++) {
31291da177e4SLinus Torvalds if (!checksetup(&setup[i])) {
31301da177e4SLinus Torvalds printk(KERN_ERR "\naha152x: %s\n", setup[i].conf);
31311da177e4SLinus Torvalds printk(KERN_ERR "aha152x: invalid line\n");
31321da177e4SLinus Torvalds }
31331da177e4SLinus Torvalds }
31341da177e4SLinus Torvalds printk("ok\n");
31351da177e4SLinus Torvalds }
31361da177e4SLinus Torvalds
31371da177e4SLinus Torvalds #if defined(SETUP0)
31381da177e4SLinus Torvalds if (setup_count < ARRAY_SIZE(setup)) {
31391da177e4SLinus Torvalds struct aha152x_setup override = SETUP0;
31401da177e4SLinus Torvalds
31411da177e4SLinus Torvalds if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
31421da177e4SLinus Torvalds if (!checksetup(&override)) {
31431da177e4SLinus Torvalds printk(KERN_ERR "\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
31441da177e4SLinus Torvalds override.io_port,
31451da177e4SLinus Torvalds override.irq,
31461da177e4SLinus Torvalds override.scsiid,
31471da177e4SLinus Torvalds override.reconnect,
31481da177e4SLinus Torvalds override.parity,
31491da177e4SLinus Torvalds override.synchronous,
31501da177e4SLinus Torvalds override.delay,
31511da177e4SLinus Torvalds override.ext_trans);
31521da177e4SLinus Torvalds } else
31531da177e4SLinus Torvalds setup[setup_count++] = override;
31541da177e4SLinus Torvalds }
31551da177e4SLinus Torvalds }
31561da177e4SLinus Torvalds #endif
31571da177e4SLinus Torvalds
31581da177e4SLinus Torvalds #if defined(SETUP1)
31591da177e4SLinus Torvalds if (setup_count < ARRAY_SIZE(setup)) {
31601da177e4SLinus Torvalds struct aha152x_setup override = SETUP1;
31611da177e4SLinus Torvalds
31621da177e4SLinus Torvalds if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
31631da177e4SLinus Torvalds if (!checksetup(&override)) {
31641da177e4SLinus Torvalds printk(KERN_ERR "\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
31651da177e4SLinus Torvalds override.io_port,
31661da177e4SLinus Torvalds override.irq,
31671da177e4SLinus Torvalds override.scsiid,
31681da177e4SLinus Torvalds override.reconnect,
31691da177e4SLinus Torvalds override.parity,
31701da177e4SLinus Torvalds override.synchronous,
31711da177e4SLinus Torvalds override.delay,
31721da177e4SLinus Torvalds override.ext_trans);
31731da177e4SLinus Torvalds } else
31741da177e4SLinus Torvalds setup[setup_count++] = override;
31751da177e4SLinus Torvalds }
31761da177e4SLinus Torvalds }
31771da177e4SLinus Torvalds #endif
31781da177e4SLinus Torvalds
31791da177e4SLinus Torvalds #if defined(MODULE)
31801da177e4SLinus Torvalds if (setup_count<ARRAY_SIZE(setup) && (aha152x[0]!=0 || io[0]!=0 || irq[0]!=0)) {
31811da177e4SLinus Torvalds if(aha152x[0]!=0) {
31821da177e4SLinus Torvalds setup[setup_count].conf = "";
31831da177e4SLinus Torvalds setup[setup_count].io_port = aha152x[0];
31841da177e4SLinus Torvalds setup[setup_count].irq = aha152x[1];
31851da177e4SLinus Torvalds setup[setup_count].scsiid = aha152x[2];
31861da177e4SLinus Torvalds setup[setup_count].reconnect = aha152x[3];
31871da177e4SLinus Torvalds setup[setup_count].parity = aha152x[4];
31881da177e4SLinus Torvalds setup[setup_count].synchronous = aha152x[5];
31891da177e4SLinus Torvalds setup[setup_count].delay = aha152x[6];
31901da177e4SLinus Torvalds setup[setup_count].ext_trans = aha152x[7];
31911da177e4SLinus Torvalds } else if (io[0] != 0 || irq[0] != 0) {
31921da177e4SLinus Torvalds if(io[0]!=0) setup[setup_count].io_port = io[0];
31931da177e4SLinus Torvalds if(irq[0]!=0) setup[setup_count].irq = irq[0];
31941da177e4SLinus Torvalds
31951da177e4SLinus Torvalds setup[setup_count].scsiid = scsiid[0];
31961da177e4SLinus Torvalds setup[setup_count].reconnect = reconnect[0];
31971da177e4SLinus Torvalds setup[setup_count].parity = parity[0];
31981da177e4SLinus Torvalds setup[setup_count].synchronous = sync[0];
31991da177e4SLinus Torvalds setup[setup_count].delay = delay[0];
32001da177e4SLinus Torvalds setup[setup_count].ext_trans = exttrans[0];
32011da177e4SLinus Torvalds }
32021da177e4SLinus Torvalds
32031da177e4SLinus Torvalds if (checksetup(&setup[setup_count]))
32041da177e4SLinus Torvalds setup_count++;
32051da177e4SLinus Torvalds else
32061da177e4SLinus 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",
32071da177e4SLinus Torvalds setup[setup_count].io_port,
32081da177e4SLinus Torvalds setup[setup_count].irq,
32091da177e4SLinus Torvalds setup[setup_count].scsiid,
32101da177e4SLinus Torvalds setup[setup_count].reconnect,
32111da177e4SLinus Torvalds setup[setup_count].parity,
32121da177e4SLinus Torvalds setup[setup_count].synchronous,
32131da177e4SLinus Torvalds setup[setup_count].delay,
32141da177e4SLinus Torvalds setup[setup_count].ext_trans);
32151da177e4SLinus Torvalds }
32161da177e4SLinus Torvalds
32171da177e4SLinus Torvalds if (setup_count<ARRAY_SIZE(setup) && (aha152x1[0]!=0 || io[1]!=0 || irq[1]!=0)) {
32181da177e4SLinus Torvalds if(aha152x1[0]!=0) {
32191da177e4SLinus Torvalds setup[setup_count].conf = "";
32201da177e4SLinus Torvalds setup[setup_count].io_port = aha152x1[0];
32211da177e4SLinus Torvalds setup[setup_count].irq = aha152x1[1];
32221da177e4SLinus Torvalds setup[setup_count].scsiid = aha152x1[2];
32231da177e4SLinus Torvalds setup[setup_count].reconnect = aha152x1[3];
32241da177e4SLinus Torvalds setup[setup_count].parity = aha152x1[4];
32251da177e4SLinus Torvalds setup[setup_count].synchronous = aha152x1[5];
32261da177e4SLinus Torvalds setup[setup_count].delay = aha152x1[6];
32271da177e4SLinus Torvalds setup[setup_count].ext_trans = aha152x1[7];
32281da177e4SLinus Torvalds } else if (io[1] != 0 || irq[1] != 0) {
32291da177e4SLinus Torvalds if(io[1]!=0) setup[setup_count].io_port = io[1];
32301da177e4SLinus Torvalds if(irq[1]!=0) setup[setup_count].irq = irq[1];
32311da177e4SLinus Torvalds
32321da177e4SLinus Torvalds setup[setup_count].scsiid = scsiid[1];
32331da177e4SLinus Torvalds setup[setup_count].reconnect = reconnect[1];
32341da177e4SLinus Torvalds setup[setup_count].parity = parity[1];
32351da177e4SLinus Torvalds setup[setup_count].synchronous = sync[1];
32361da177e4SLinus Torvalds setup[setup_count].delay = delay[1];
32371da177e4SLinus Torvalds setup[setup_count].ext_trans = exttrans[1];
32381da177e4SLinus Torvalds }
32391da177e4SLinus Torvalds if (checksetup(&setup[setup_count]))
32401da177e4SLinus Torvalds setup_count++;
32411da177e4SLinus Torvalds else
32421da177e4SLinus 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",
32431da177e4SLinus Torvalds setup[setup_count].io_port,
32441da177e4SLinus Torvalds setup[setup_count].irq,
32451da177e4SLinus Torvalds setup[setup_count].scsiid,
32461da177e4SLinus Torvalds setup[setup_count].reconnect,
32471da177e4SLinus Torvalds setup[setup_count].parity,
32481da177e4SLinus Torvalds setup[setup_count].synchronous,
32491da177e4SLinus Torvalds setup[setup_count].delay,
32501da177e4SLinus Torvalds setup[setup_count].ext_trans);
32511da177e4SLinus Torvalds }
32521da177e4SLinus Torvalds #endif
32531da177e4SLinus Torvalds
32541da177e4SLinus Torvalds #ifdef __ISAPNP__
32551da177e4SLinus Torvalds for(i=0; setup_count<ARRAY_SIZE(setup) && id_table[i].vendor; i++) {
32561da177e4SLinus Torvalds while ( setup_count<ARRAY_SIZE(setup) &&
32571da177e4SLinus Torvalds (dev=pnp_find_dev(NULL, id_table[i].vendor, id_table[i].function, dev)) ) {
32581da177e4SLinus Torvalds if (pnp_device_attach(dev) < 0)
32591da177e4SLinus Torvalds continue;
32601da177e4SLinus Torvalds
32611da177e4SLinus Torvalds if (pnp_activate_dev(dev) < 0) {
32621da177e4SLinus Torvalds pnp_device_detach(dev);
32631da177e4SLinus Torvalds continue;
32641da177e4SLinus Torvalds }
32651da177e4SLinus Torvalds
32661da177e4SLinus Torvalds if (!pnp_port_valid(dev, 0)) {
32671da177e4SLinus Torvalds pnp_device_detach(dev);
32681da177e4SLinus Torvalds continue;
32691da177e4SLinus Torvalds }
32701da177e4SLinus Torvalds
32711da177e4SLinus Torvalds if (setup_count==1 && pnp_port_start(dev, 0)==setup[0].io_port) {
32721da177e4SLinus Torvalds pnp_device_detach(dev);
32731da177e4SLinus Torvalds continue;
32741da177e4SLinus Torvalds }
32751da177e4SLinus Torvalds
32761da177e4SLinus Torvalds setup[setup_count].io_port = pnp_port_start(dev, 0);
32771da177e4SLinus Torvalds setup[setup_count].irq = pnp_irq(dev, 0);
32781da177e4SLinus Torvalds setup[setup_count].scsiid = 7;
32791da177e4SLinus Torvalds setup[setup_count].reconnect = 1;
32801da177e4SLinus Torvalds setup[setup_count].parity = 1;
32811da177e4SLinus Torvalds setup[setup_count].synchronous = 1;
32821da177e4SLinus Torvalds setup[setup_count].delay = DELAY_DEFAULT;
32831da177e4SLinus Torvalds setup[setup_count].ext_trans = 0;
32841da177e4SLinus Torvalds #if defined(__ISAPNP__)
32851da177e4SLinus Torvalds pnpdev[setup_count] = dev;
32861da177e4SLinus Torvalds #endif
32871da177e4SLinus Torvalds printk (KERN_INFO
32881da177e4SLinus Torvalds "aha152x: found ISAPnP adapter at io=0x%03x, irq=%d\n",
32891da177e4SLinus Torvalds setup[setup_count].io_port, setup[setup_count].irq);
32901da177e4SLinus Torvalds setup_count++;
32911da177e4SLinus Torvalds }
32921da177e4SLinus Torvalds }
32931da177e4SLinus Torvalds #endif
32941da177e4SLinus Torvalds
32951da177e4SLinus Torvalds #if defined(AUTOCONF)
32961da177e4SLinus Torvalds if (setup_count<ARRAY_SIZE(setup)) {
32971da177e4SLinus Torvalds #if !defined(SKIP_BIOSTEST)
32981da177e4SLinus Torvalds ok = 0;
32991da177e4SLinus Torvalds for (i = 0; i < ARRAY_SIZE(addresses) && !ok; i++) {
33001da177e4SLinus Torvalds void __iomem *p = ioremap(addresses[i], 0x4000);
33011da177e4SLinus Torvalds if (!p)
33021da177e4SLinus Torvalds continue;
33031da177e4SLinus Torvalds for (j = 0; j<ARRAY_SIZE(signatures) && !ok; j++)
33041da177e4SLinus Torvalds ok = check_signature(p + signatures[j].sig_offset,
33051da177e4SLinus Torvalds signatures[j].signature, signatures[j].sig_length);
33061da177e4SLinus Torvalds iounmap(p);
33071da177e4SLinus Torvalds }
33081da177e4SLinus Torvalds if (!ok && setup_count == 0)
3309ad2fa42dSJames Bottomley return -ENODEV;
33101da177e4SLinus Torvalds
33111da177e4SLinus Torvalds printk(KERN_INFO "aha152x: BIOS test: passed, ");
33121da177e4SLinus Torvalds #else
33131da177e4SLinus Torvalds printk(KERN_INFO "aha152x: ");
33141da177e4SLinus Torvalds #endif /* !SKIP_BIOSTEST */
33151da177e4SLinus Torvalds
33161da177e4SLinus Torvalds ok = 0;
33171da177e4SLinus Torvalds for (i = 0; i < ARRAY_SIZE(ports) && setup_count < 2; i++) {
33181da177e4SLinus Torvalds if ((setup_count == 1) && (setup[0].io_port == ports[i]))
33191da177e4SLinus Torvalds continue;
33201da177e4SLinus Torvalds
33219bcf0910SHarvey Harrison if (!request_region(ports[i], IO_RANGE, "aha152x")) {
33221da177e4SLinus Torvalds printk(KERN_ERR "aha152x: io port 0x%x busy.\n", ports[i]);
33231da177e4SLinus Torvalds continue;
33241da177e4SLinus Torvalds }
33251da177e4SLinus Torvalds
33261da177e4SLinus Torvalds if (aha152x_porttest(ports[i])) {
33271da177e4SLinus Torvalds setup[setup_count].tc1550 = 0;
33281da177e4SLinus Torvalds
33291da177e4SLinus Torvalds conf.cf_port =
33301da177e4SLinus Torvalds (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB);
33311da177e4SLinus Torvalds } else if (tc1550_porttest(ports[i])) {
33321da177e4SLinus Torvalds setup[setup_count].tc1550 = 1;
33331da177e4SLinus Torvalds
33341da177e4SLinus Torvalds conf.cf_port =
33351da177e4SLinus Torvalds (GETPORT(ports[i] + O_TC_PORTA) << 8) + GETPORT(ports[i] + O_TC_PORTB);
33361da177e4SLinus Torvalds } else {
33371da177e4SLinus Torvalds release_region(ports[i], IO_RANGE);
33381da177e4SLinus Torvalds continue;
33391da177e4SLinus Torvalds }
33401da177e4SLinus Torvalds
33411da177e4SLinus Torvalds release_region(ports[i], IO_RANGE);
33421da177e4SLinus Torvalds
33431da177e4SLinus Torvalds ok++;
33441da177e4SLinus Torvalds setup[setup_count].io_port = ports[i];
33451da177e4SLinus Torvalds setup[setup_count].irq = IRQ_MIN + conf.cf_irq;
33461da177e4SLinus Torvalds setup[setup_count].scsiid = conf.cf_id;
33471da177e4SLinus Torvalds setup[setup_count].reconnect = conf.cf_tardisc;
33481da177e4SLinus Torvalds setup[setup_count].parity = !conf.cf_parity;
33491da177e4SLinus Torvalds setup[setup_count].synchronous = conf.cf_syncneg;
33501da177e4SLinus Torvalds setup[setup_count].delay = DELAY_DEFAULT;
33511da177e4SLinus Torvalds setup[setup_count].ext_trans = 0;
33521da177e4SLinus Torvalds setup_count++;
33531da177e4SLinus Torvalds
33541da177e4SLinus Torvalds }
33551da177e4SLinus Torvalds
33561da177e4SLinus Torvalds if (ok)
33571da177e4SLinus Torvalds printk("auto configuration: ok, ");
33581da177e4SLinus Torvalds }
33591da177e4SLinus Torvalds #endif
33601da177e4SLinus Torvalds
33611da177e4SLinus Torvalds printk("%d controller(s) configured\n", setup_count);
33621da177e4SLinus Torvalds
33631da177e4SLinus Torvalds for (i=0; i<setup_count; i++) {
33641da177e4SLinus Torvalds if ( request_region(setup[i].io_port, IO_RANGE, "aha152x") ) {
33651da177e4SLinus Torvalds struct Scsi_Host *shpnt = aha152x_probe_one(&setup[i]);
33661da177e4SLinus Torvalds
33671da177e4SLinus Torvalds if( !shpnt ) {
33681da177e4SLinus Torvalds release_region(setup[i].io_port, IO_RANGE);
33691da177e4SLinus Torvalds #if defined(__ISAPNP__)
33701da177e4SLinus Torvalds } else if( pnpdev[i] ) {
33711da177e4SLinus Torvalds HOSTDATA(shpnt)->pnpdev=pnpdev[i];
33721da177e4SLinus Torvalds pnpdev[i]=NULL;
33731da177e4SLinus Torvalds #endif
33741da177e4SLinus Torvalds }
33751da177e4SLinus Torvalds } else {
33761da177e4SLinus Torvalds printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup[i].io_port);
33771da177e4SLinus Torvalds }
33781da177e4SLinus Torvalds
33791da177e4SLinus Torvalds #if defined(__ISAPNP__)
33801da177e4SLinus Torvalds if( pnpdev[i] )
33811da177e4SLinus Torvalds pnp_device_detach(pnpdev[i]);
33821da177e4SLinus Torvalds #endif
33831da177e4SLinus Torvalds }
33841da177e4SLinus Torvalds
3385ad2fa42dSJames Bottomley return 0;
33861da177e4SLinus Torvalds }
33871da177e4SLinus Torvalds
aha152x_exit(void)33881da177e4SLinus Torvalds static void __exit aha152x_exit(void)
33891da177e4SLinus Torvalds {
339064976a03SJames Bottomley struct aha152x_hostdata *hd, *tmp;
33911da177e4SLinus Torvalds
339264976a03SJames Bottomley list_for_each_entry_safe(hd, tmp, &aha152x_host_list, host_list) {
33935fcda422SJames Bottomley struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
33945fcda422SJames Bottomley
33955fcda422SJames Bottomley aha152x_release(shost);
33961da177e4SLinus Torvalds }
33971da177e4SLinus Torvalds }
33981da177e4SLinus Torvalds
33991da177e4SLinus Torvalds module_init(aha152x_init);
34001da177e4SLinus Torvalds module_exit(aha152x_exit);
34011da177e4SLinus Torvalds
34021da177e4SLinus Torvalds #if !defined(MODULE)
aha152x_setup(char * str)34031da177e4SLinus Torvalds static int __init aha152x_setup(char *str)
34041da177e4SLinus Torvalds {
34051da177e4SLinus Torvalds int ints[10];
3406f75ae8edSHannes Reinecke
34071da177e4SLinus Torvalds get_options(str, ARRAY_SIZE(ints), ints);
34081da177e4SLinus Torvalds
34091da177e4SLinus Torvalds if(setup_count>=ARRAY_SIZE(setup)) {
34101da177e4SLinus Torvalds printk(KERN_ERR "aha152x: you can only configure up to two controllers\n");
34111da177e4SLinus Torvalds return 1;
34121da177e4SLinus Torvalds }
34131da177e4SLinus Torvalds
34141da177e4SLinus Torvalds setup[setup_count].conf = str;
34151da177e4SLinus Torvalds setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340;
34161da177e4SLinus Torvalds setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11;
34171da177e4SLinus Torvalds setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7;
34181da177e4SLinus Torvalds setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1;
34191da177e4SLinus Torvalds setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1;
34201da177e4SLinus Torvalds setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 1;
34211da177e4SLinus Torvalds setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT;
34221da177e4SLinus Torvalds setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0;
3423cc8294ecSRandy Dunlap if (ints[0] > 8)
34241da177e4SLinus Torvalds printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
34251da177e4SLinus Torvalds "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n");
3426cc8294ecSRandy Dunlap else
34271da177e4SLinus Torvalds setup_count++;
34281da177e4SLinus Torvalds
34291da177e4SLinus Torvalds return 1;
34301da177e4SLinus Torvalds }
34311da177e4SLinus Torvalds __setup("aha152x=", aha152x_setup);
34321da177e4SLinus Torvalds #endif
34331da177e4SLinus Torvalds
34343eb2ebcbSChristoph Hellwig #endif /* !AHA152X_PCMCIA */
3435