18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* aha152x.c -- Adaptec AHA-152x driver
38c2ecf20Sopenharmony_ci * Author: Jürgen E. Fischer, fischer@norbit.de
48c2ecf20Sopenharmony_ci * Copyright 1993-2004 Jürgen E. Fischer
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * $Id: aha152x.c,v 2.7 2004/01/24 11:42:59 fischer Exp $
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * $Log: aha152x.c,v $
98c2ecf20Sopenharmony_ci * Revision 2.7  2004/01/24 11:42:59  fischer
108c2ecf20Sopenharmony_ci * - gather code that is not used by PCMCIA at the end
118c2ecf20Sopenharmony_ci * - move request_region for !PCMCIA case to detection
128c2ecf20Sopenharmony_ci * - migration to new scsi host api (remove legacy code)
138c2ecf20Sopenharmony_ci * - free host scribble before scsi_done
148c2ecf20Sopenharmony_ci * - fix error handling
158c2ecf20Sopenharmony_ci * - one isapnp device added to id_table
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * Revision 2.6  2003/10/30 20:52:47  fischer
188c2ecf20Sopenharmony_ci * - interfaces changes for kernel 2.6
198c2ecf20Sopenharmony_ci * - aha152x_probe_one introduced for pcmcia stub
208c2ecf20Sopenharmony_ci * - fixed pnpdev handling
218c2ecf20Sopenharmony_ci * - instead of allocation a new one, reuse command for request sense after check condition and reset
228c2ecf20Sopenharmony_ci * - fixes race in is_complete
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * Revision 2.5  2002/04/14 11:24:53  fischer
258c2ecf20Sopenharmony_ci * - isapnp support
268c2ecf20Sopenharmony_ci * - abort fixed
278c2ecf20Sopenharmony_ci * - 2.5 support
288c2ecf20Sopenharmony_ci *
298c2ecf20Sopenharmony_ci * Revision 2.4  2000/12/16 12:53:56  fischer
308c2ecf20Sopenharmony_ci * - allow REQUEST SENSE to be queued
318c2ecf20Sopenharmony_ci * - handle shared PCI interrupts
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci * Revision 2.3  2000/11/04 16:40:26  fischer
348c2ecf20Sopenharmony_ci * - handle data overruns
358c2ecf20Sopenharmony_ci * - extend timeout for data phases
368c2ecf20Sopenharmony_ci *
378c2ecf20Sopenharmony_ci * Revision 2.2  2000/08/08 19:54:53  fischer
388c2ecf20Sopenharmony_ci * - minor changes
398c2ecf20Sopenharmony_ci *
408c2ecf20Sopenharmony_ci * Revision 2.1  2000/05/17 16:23:17  fischer
418c2ecf20Sopenharmony_ci * - signature update
428c2ecf20Sopenharmony_ci * - fix for data out w/o scatter gather
438c2ecf20Sopenharmony_ci *
448c2ecf20Sopenharmony_ci * Revision 2.0  1999/12/25 15:07:32  fischer
458c2ecf20Sopenharmony_ci * - interrupt routine completly reworked
468c2ecf20Sopenharmony_ci * - basic support for new eh code
478c2ecf20Sopenharmony_ci *
488c2ecf20Sopenharmony_ci * Revision 1.21  1999/11/10 23:46:36  fischer
498c2ecf20Sopenharmony_ci * - default to synchronous operation
508c2ecf20Sopenharmony_ci * - synchronous negotiation fixed
518c2ecf20Sopenharmony_ci * - added timeout to loops
528c2ecf20Sopenharmony_ci * - debugging output can be controlled through procfs
538c2ecf20Sopenharmony_ci *
548c2ecf20Sopenharmony_ci * Revision 1.20  1999/11/07 18:37:31  fischer
558c2ecf20Sopenharmony_ci * - synchronous operation works
568c2ecf20Sopenharmony_ci * - resid support for sg driver
578c2ecf20Sopenharmony_ci *
588c2ecf20Sopenharmony_ci * Revision 1.19  1999/11/02 22:39:59  fischer
598c2ecf20Sopenharmony_ci * - moved leading comments to README.aha152x
608c2ecf20Sopenharmony_ci * - new additional module parameters
618c2ecf20Sopenharmony_ci * - updates for 2.3
628c2ecf20Sopenharmony_ci * - support for the Tripace TC1550 controller
638c2ecf20Sopenharmony_ci * - interrupt handling changed
648c2ecf20Sopenharmony_ci *
658c2ecf20Sopenharmony_ci * Revision 1.18  1996/09/07 20:10:40  fischer
668c2ecf20Sopenharmony_ci * - fixed can_queue handling (multiple outstanding commands working again)
678c2ecf20Sopenharmony_ci *
688c2ecf20Sopenharmony_ci * Revision 1.17  1996/08/17 16:05:14  fischer
698c2ecf20Sopenharmony_ci * - biosparam improved
708c2ecf20Sopenharmony_ci * - interrupt verification
718c2ecf20Sopenharmony_ci * - updated documentation
728c2ecf20Sopenharmony_ci * - cleanups
738c2ecf20Sopenharmony_ci *
748c2ecf20Sopenharmony_ci * Revision 1.16  1996/06/09 00:04:56  root
758c2ecf20Sopenharmony_ci * - added configuration symbols for insmod (aha152x/aha152x1)
768c2ecf20Sopenharmony_ci *
778c2ecf20Sopenharmony_ci * Revision 1.15  1996/04/30 14:52:06  fischer
788c2ecf20Sopenharmony_ci * - proc info fixed
798c2ecf20Sopenharmony_ci * - support for extended translation for >1GB disks
808c2ecf20Sopenharmony_ci *
818c2ecf20Sopenharmony_ci * Revision 1.14  1996/01/17  15:11:20  fischer
828c2ecf20Sopenharmony_ci * - fixed lockup in MESSAGE IN phase after reconnection
838c2ecf20Sopenharmony_ci *
848c2ecf20Sopenharmony_ci * Revision 1.13  1996/01/09  02:15:53  fischer
858c2ecf20Sopenharmony_ci * - some cleanups
868c2ecf20Sopenharmony_ci * - moved request_irq behind controller initialization
878c2ecf20Sopenharmony_ci *   (to avoid spurious interrupts)
888c2ecf20Sopenharmony_ci *
898c2ecf20Sopenharmony_ci * Revision 1.12  1995/12/16  12:26:07  fischer
908c2ecf20Sopenharmony_ci * - barrier()s added
918c2ecf20Sopenharmony_ci * - configurable RESET delay added
928c2ecf20Sopenharmony_ci *
938c2ecf20Sopenharmony_ci * Revision 1.11  1995/12/06  21:18:35  fischer
948c2ecf20Sopenharmony_ci * - some minor updates
958c2ecf20Sopenharmony_ci *
968c2ecf20Sopenharmony_ci * Revision 1.10  1995/07/22  19:18:45  fischer
978c2ecf20Sopenharmony_ci * - support for 2 controllers
988c2ecf20Sopenharmony_ci * - started synchronous data transfers (not working yet)
998c2ecf20Sopenharmony_ci *
1008c2ecf20Sopenharmony_ci * Revision 1.9  1995/03/18  09:20:24  root
1018c2ecf20Sopenharmony_ci * - patches for PCMCIA and modules
1028c2ecf20Sopenharmony_ci *
1038c2ecf20Sopenharmony_ci * Revision 1.8  1995/01/21  22:07:19  root
1048c2ecf20Sopenharmony_ci * - snarf_region => request_region
1058c2ecf20Sopenharmony_ci * - aha152x_intr interface change
1068c2ecf20Sopenharmony_ci *
1078c2ecf20Sopenharmony_ci * Revision 1.7  1995/01/02  23:19:36  root
1088c2ecf20Sopenharmony_ci * - updated COMMAND_SIZE to cmd_len
1098c2ecf20Sopenharmony_ci * - changed sti() to restore_flags()
1108c2ecf20Sopenharmony_ci * - fixed some #ifdef which generated warnings
1118c2ecf20Sopenharmony_ci *
1128c2ecf20Sopenharmony_ci * Revision 1.6  1994/11/24  20:35:27  root
1138c2ecf20Sopenharmony_ci * - problem with odd number of bytes in fifo fixed
1148c2ecf20Sopenharmony_ci *
1158c2ecf20Sopenharmony_ci * Revision 1.5  1994/10/30  14:39:56  root
1168c2ecf20Sopenharmony_ci * - abort code fixed
1178c2ecf20Sopenharmony_ci * - debugging improved
1188c2ecf20Sopenharmony_ci *
1198c2ecf20Sopenharmony_ci * Revision 1.4  1994/09/12  11:33:01  root
1208c2ecf20Sopenharmony_ci * - irqaction to request_irq
1218c2ecf20Sopenharmony_ci * - abortion updated
1228c2ecf20Sopenharmony_ci *
1238c2ecf20Sopenharmony_ci * Revision 1.3  1994/08/04  13:53:05  root
1248c2ecf20Sopenharmony_ci * - updates for mid-level-driver changes
1258c2ecf20Sopenharmony_ci * - accept unexpected BUSFREE phase as error condition
1268c2ecf20Sopenharmony_ci * - parity check now configurable
1278c2ecf20Sopenharmony_ci *
1288c2ecf20Sopenharmony_ci * Revision 1.2  1994/07/03  12:56:36  root
1298c2ecf20Sopenharmony_ci * - cleaned up debugging code
1308c2ecf20Sopenharmony_ci * - more tweaking on reset delays
1318c2ecf20Sopenharmony_ci * - updated abort/reset code (pretty untested...)
1328c2ecf20Sopenharmony_ci *
1338c2ecf20Sopenharmony_ci * Revision 1.1  1994/05/28  21:18:49  root
1348c2ecf20Sopenharmony_ci * - update for mid-level interface change (abort-reset)
1358c2ecf20Sopenharmony_ci * - delays after resets adjusted for some slow devices
1368c2ecf20Sopenharmony_ci *
1378c2ecf20Sopenharmony_ci * Revision 1.0  1994/03/25  12:52:00  root
1388c2ecf20Sopenharmony_ci * - Fixed "more data than expected" problem
1398c2ecf20Sopenharmony_ci * - added new BIOS signatures
1408c2ecf20Sopenharmony_ci *
1418c2ecf20Sopenharmony_ci * Revision 0.102  1994/01/31  20:44:12  root
1428c2ecf20Sopenharmony_ci * - minor changes in insw/outsw handling
1438c2ecf20Sopenharmony_ci *
1448c2ecf20Sopenharmony_ci * Revision 0.101  1993/12/13  01:16:27  root
1458c2ecf20Sopenharmony_ci * - fixed STATUS phase (non-GOOD stati were dropped sometimes;
1468c2ecf20Sopenharmony_ci *   fixes problems with CD-ROM sector size detection & media change)
1478c2ecf20Sopenharmony_ci *
1488c2ecf20Sopenharmony_ci * Revision 0.100  1993/12/10  16:58:47  root
1498c2ecf20Sopenharmony_ci * - fix for unsuccessful selections in case of non-continuous id assignments
1508c2ecf20Sopenharmony_ci *   on the scsi bus.
1518c2ecf20Sopenharmony_ci *
1528c2ecf20Sopenharmony_ci * Revision 0.99  1993/10/24  16:19:59  root
1538c2ecf20Sopenharmony_ci * - fixed DATA IN (rare read errors gone)
1548c2ecf20Sopenharmony_ci *
1558c2ecf20Sopenharmony_ci * Revision 0.98  1993/10/17  12:54:44  root
1568c2ecf20Sopenharmony_ci * - fixed some recent fixes (shame on me)
1578c2ecf20Sopenharmony_ci * - moved initialization of scratch area to aha152x_queue
1588c2ecf20Sopenharmony_ci *
1598c2ecf20Sopenharmony_ci * Revision 0.97  1993/10/09  18:53:53  root
1608c2ecf20Sopenharmony_ci * - DATA IN fixed. Rarely left data in the fifo.
1618c2ecf20Sopenharmony_ci *
1628c2ecf20Sopenharmony_ci * Revision 0.96  1993/10/03  00:53:59  root
1638c2ecf20Sopenharmony_ci * - minor changes on DATA IN
1648c2ecf20Sopenharmony_ci *
1658c2ecf20Sopenharmony_ci * Revision 0.95  1993/09/24  10:36:01  root
1668c2ecf20Sopenharmony_ci * - change handling of MSGI after reselection
1678c2ecf20Sopenharmony_ci * - fixed sti/cli
1688c2ecf20Sopenharmony_ci * - minor changes
1698c2ecf20Sopenharmony_ci *
1708c2ecf20Sopenharmony_ci * Revision 0.94  1993/09/18  14:08:22  root
1718c2ecf20Sopenharmony_ci * - fixed bug in multiple outstanding command code
1728c2ecf20Sopenharmony_ci * - changed detection
1738c2ecf20Sopenharmony_ci * - support for kernel command line configuration
1748c2ecf20Sopenharmony_ci * - reset corrected
1758c2ecf20Sopenharmony_ci * - changed message handling
1768c2ecf20Sopenharmony_ci *
1778c2ecf20Sopenharmony_ci * Revision 0.93  1993/09/15  20:41:19  root
1788c2ecf20Sopenharmony_ci * - fixed bugs with multiple outstanding commands
1798c2ecf20Sopenharmony_ci *
1808c2ecf20Sopenharmony_ci * Revision 0.92  1993/09/13  02:46:33  root
1818c2ecf20Sopenharmony_ci * - multiple outstanding commands work (no problems with IBM drive)
1828c2ecf20Sopenharmony_ci *
1838c2ecf20Sopenharmony_ci * Revision 0.91  1993/09/12  20:51:46  root
1848c2ecf20Sopenharmony_ci * added multiple outstanding commands
1858c2ecf20Sopenharmony_ci * (some problem with this $%&? IBM device remain)
1868c2ecf20Sopenharmony_ci *
1878c2ecf20Sopenharmony_ci * Revision 0.9  1993/09/12  11:11:22  root
1888c2ecf20Sopenharmony_ci * - corrected auto-configuration
1898c2ecf20Sopenharmony_ci * - changed the auto-configuration (added some '#define's)
1908c2ecf20Sopenharmony_ci * - added support for dis-/reconnection
1918c2ecf20Sopenharmony_ci *
1928c2ecf20Sopenharmony_ci * Revision 0.8  1993/09/06  23:09:39  root
1938c2ecf20Sopenharmony_ci * - added support for the drive activity light
1948c2ecf20Sopenharmony_ci * - minor changes
1958c2ecf20Sopenharmony_ci *
1968c2ecf20Sopenharmony_ci * Revision 0.7  1993/09/05  14:30:15  root
1978c2ecf20Sopenharmony_ci * - improved phase detection
1988c2ecf20Sopenharmony_ci * - now using the new snarf_region code of 0.99pl13
1998c2ecf20Sopenharmony_ci *
2008c2ecf20Sopenharmony_ci * Revision 0.6  1993/09/02  11:01:38  root
2018c2ecf20Sopenharmony_ci * first public release; added some signatures and biosparam()
2028c2ecf20Sopenharmony_ci *
2038c2ecf20Sopenharmony_ci * Revision 0.5  1993/08/30  10:23:30  root
2048c2ecf20Sopenharmony_ci * fixed timing problems with my IBM drive
2058c2ecf20Sopenharmony_ci *
2068c2ecf20Sopenharmony_ci * Revision 0.4  1993/08/29  14:06:52  root
2078c2ecf20Sopenharmony_ci * fixed some problems with timeouts due incomplete commands
2088c2ecf20Sopenharmony_ci *
2098c2ecf20Sopenharmony_ci * Revision 0.3  1993/08/28  15:55:03  root
2108c2ecf20Sopenharmony_ci * writing data works too.  mounted and worked on a dos partition
2118c2ecf20Sopenharmony_ci *
2128c2ecf20Sopenharmony_ci * Revision 0.2  1993/08/27  22:42:07  root
2138c2ecf20Sopenharmony_ci * reading data works.  Mounted a msdos partition.
2148c2ecf20Sopenharmony_ci *
2158c2ecf20Sopenharmony_ci * Revision 0.1  1993/08/25  13:38:30  root
2168c2ecf20Sopenharmony_ci * first "damn thing doesn't work" version
2178c2ecf20Sopenharmony_ci *
2188c2ecf20Sopenharmony_ci * Revision 0.0  1993/08/14  19:54:25  root
2198c2ecf20Sopenharmony_ci * empty function bodies; detect() works.
2208c2ecf20Sopenharmony_ci *
2218c2ecf20Sopenharmony_ci **************************************************************************
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci see Documentation/scsi/aha152x.rst for configuration details
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci **************************************************************************/
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci#include <linux/module.h>
2288c2ecf20Sopenharmony_ci#include <asm/irq.h>
2298c2ecf20Sopenharmony_ci#include <linux/io.h>
2308c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
2318c2ecf20Sopenharmony_ci#include <linux/completion.h>
2328c2ecf20Sopenharmony_ci#include <linux/errno.h>
2338c2ecf20Sopenharmony_ci#include <linux/string.h>
2348c2ecf20Sopenharmony_ci#include <linux/wait.h>
2358c2ecf20Sopenharmony_ci#include <linux/ioport.h>
2368c2ecf20Sopenharmony_ci#include <linux/delay.h>
2378c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
2388c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
2398c2ecf20Sopenharmony_ci#include <linux/init.h>
2408c2ecf20Sopenharmony_ci#include <linux/kernel.h>
2418c2ecf20Sopenharmony_ci#include <linux/isapnp.h>
2428c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
2438c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
2448c2ecf20Sopenharmony_ci#include <linux/list.h>
2458c2ecf20Sopenharmony_ci#include <linux/slab.h>
2468c2ecf20Sopenharmony_ci#include <scsi/scsicam.h>
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci#include "scsi.h"
2498c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h>
2508c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
2518c2ecf20Sopenharmony_ci#include <scsi/scsi_transport_spi.h>
2528c2ecf20Sopenharmony_ci#include <scsi/scsi_eh.h>
2538c2ecf20Sopenharmony_ci#include "aha152x.h"
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic LIST_HEAD(aha152x_host_list);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci/* DEFINES */
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci/* For PCMCIA cards, always use AUTOCONF */
2618c2ecf20Sopenharmony_ci#if defined(AHA152X_PCMCIA) || defined(MODULE)
2628c2ecf20Sopenharmony_ci#if !defined(AUTOCONF)
2638c2ecf20Sopenharmony_ci#define AUTOCONF
2648c2ecf20Sopenharmony_ci#endif
2658c2ecf20Sopenharmony_ci#endif
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci#if !defined(AUTOCONF) && !defined(SETUP0)
2688c2ecf20Sopenharmony_ci#error define AUTOCONF or SETUP0
2698c2ecf20Sopenharmony_ci#endif
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci#define	DO_LOCK(flags)		spin_lock_irqsave(&QLOCK,flags)
2728c2ecf20Sopenharmony_ci#define	DO_UNLOCK(flags)	spin_unlock_irqrestore(&QLOCK,flags)
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci#define LEAD		"(scsi%d:%d:%d) "
2758c2ecf20Sopenharmony_ci#define INFO_LEAD	KERN_INFO	LEAD
2768c2ecf20Sopenharmony_ci#define CMDINFO(cmd) \
2778c2ecf20Sopenharmony_ci			(cmd) ? ((cmd)->device->host->host_no) : -1, \
2788c2ecf20Sopenharmony_ci                        (cmd) ? ((cmd)->device->id & 0x0f) : -1, \
2798c2ecf20Sopenharmony_ci			(cmd) ? ((u8)(cmd)->device->lun & 0x07) : -1
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistatic inline void
2828c2ecf20Sopenharmony_ciCMD_INC_RESID(struct scsi_cmnd *cmd, int inc)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	scsi_set_resid(cmd, scsi_get_resid(cmd) + inc);
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci#define DELAY_DEFAULT 1000
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci#if defined(AHA152X_PCMCIA)
2908c2ecf20Sopenharmony_ci#define IRQ_MIN 0
2918c2ecf20Sopenharmony_ci#define IRQ_MAX 16
2928c2ecf20Sopenharmony_ci#else
2938c2ecf20Sopenharmony_ci#define IRQ_MIN 9
2948c2ecf20Sopenharmony_ci#if defined(__PPC)
2958c2ecf20Sopenharmony_ci#define IRQ_MAX (nr_irqs-1)
2968c2ecf20Sopenharmony_ci#else
2978c2ecf20Sopenharmony_ci#define IRQ_MAX 12
2988c2ecf20Sopenharmony_ci#endif
2998c2ecf20Sopenharmony_ci#endif
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cienum {
3028c2ecf20Sopenharmony_ci	not_issued	= 0x0001,	/* command not yet issued */
3038c2ecf20Sopenharmony_ci	selecting	= 0x0002,	/* target is being selected */
3048c2ecf20Sopenharmony_ci	identified	= 0x0004,	/* IDENTIFY was sent */
3058c2ecf20Sopenharmony_ci	disconnected	= 0x0008,	/* target disconnected */
3068c2ecf20Sopenharmony_ci	completed	= 0x0010,	/* target sent COMMAND COMPLETE */
3078c2ecf20Sopenharmony_ci	aborted		= 0x0020,	/* ABORT was sent */
3088c2ecf20Sopenharmony_ci	resetted	= 0x0040,	/* BUS DEVICE RESET was sent */
3098c2ecf20Sopenharmony_ci	spiordy		= 0x0080,	/* waiting for SPIORDY to raise */
3108c2ecf20Sopenharmony_ci	syncneg		= 0x0100,	/* synchronous negotiation in progress */
3118c2ecf20Sopenharmony_ci	aborting	= 0x0200,	/* ABORT is pending */
3128c2ecf20Sopenharmony_ci	resetting	= 0x0400,	/* BUS DEVICE RESET is pending */
3138c2ecf20Sopenharmony_ci	check_condition = 0x0800,	/* requesting sense after CHECK CONDITION */
3148c2ecf20Sopenharmony_ci};
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jürgen Fischer");
3178c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(AHA152X_REVID);
3188c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci#if !defined(AHA152X_PCMCIA)
3218c2ecf20Sopenharmony_ci#if defined(MODULE)
3228c2ecf20Sopenharmony_cistatic int io[] = {0, 0};
3238c2ecf20Sopenharmony_cimodule_param_hw_array(io, int, ioport, NULL, 0);
3248c2ecf20Sopenharmony_ciMODULE_PARM_DESC(io,"base io address of controller");
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_cistatic int irq[] = {0, 0};
3278c2ecf20Sopenharmony_cimodule_param_hw_array(irq, int, irq, NULL, 0);
3288c2ecf20Sopenharmony_ciMODULE_PARM_DESC(irq,"interrupt for controller");
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic int scsiid[] = {7, 7};
3318c2ecf20Sopenharmony_cimodule_param_array(scsiid, int, NULL, 0);
3328c2ecf20Sopenharmony_ciMODULE_PARM_DESC(scsiid,"scsi id of controller");
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic int reconnect[] = {1, 1};
3358c2ecf20Sopenharmony_cimodule_param_array(reconnect, int, NULL, 0);
3368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(reconnect,"allow targets to disconnect");
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic int parity[] = {1, 1};
3398c2ecf20Sopenharmony_cimodule_param_array(parity, int, NULL, 0);
3408c2ecf20Sopenharmony_ciMODULE_PARM_DESC(parity,"use scsi parity");
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic int sync[] = {1, 1};
3438c2ecf20Sopenharmony_cimodule_param_array(sync, int, NULL, 0);
3448c2ecf20Sopenharmony_ciMODULE_PARM_DESC(sync,"use synchronous transfers");
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic int delay[] = {DELAY_DEFAULT, DELAY_DEFAULT};
3478c2ecf20Sopenharmony_cimodule_param_array(delay, int, NULL, 0);
3488c2ecf20Sopenharmony_ciMODULE_PARM_DESC(delay,"scsi reset delay");
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_cistatic int exttrans[] = {0, 0};
3518c2ecf20Sopenharmony_cimodule_param_array(exttrans, int, NULL, 0);
3528c2ecf20Sopenharmony_ciMODULE_PARM_DESC(exttrans,"use extended translation");
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
3558c2ecf20Sopenharmony_cimodule_param_array(aha152x, int, NULL, 0);
3568c2ecf20Sopenharmony_ciMODULE_PARM_DESC(aha152x, "parameters for first controller");
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
3598c2ecf20Sopenharmony_cimodule_param_array(aha152x1, int, NULL, 0);
3608c2ecf20Sopenharmony_ciMODULE_PARM_DESC(aha152x1, "parameters for second controller");
3618c2ecf20Sopenharmony_ci#endif /* MODULE */
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci#ifdef __ISAPNP__
3648c2ecf20Sopenharmony_cistatic struct isapnp_device_id id_table[] = {
3658c2ecf20Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1502), 0 },
3668c2ecf20Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1505), 0 },
3678c2ecf20Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1510), 0 },
3688c2ecf20Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1515), 0 },
3698c2ecf20Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1520), 0 },
3708c2ecf20Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2015), 0 },
3718c2ecf20Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1522), 0 },
3728c2ecf20Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2215), 0 },
3738c2ecf20Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1530), 0 },
3748c2ecf20Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3015), 0 },
3758c2ecf20Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1532), 0 },
3768c2ecf20Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3215), 0 },
3778c2ecf20Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x6360), 0 },
3788c2ecf20Sopenharmony_ci	{ ISAPNP_DEVICE_SINGLE_END, }
3798c2ecf20Sopenharmony_ci};
3808c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(isapnp, id_table);
3818c2ecf20Sopenharmony_ci#endif /* ISAPNP */
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci#endif /* !AHA152X_PCMCIA */
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cistatic struct scsi_host_template aha152x_driver_template;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci/*
3888c2ecf20Sopenharmony_ci * internal states of the host
3898c2ecf20Sopenharmony_ci *
3908c2ecf20Sopenharmony_ci */
3918c2ecf20Sopenharmony_cienum aha152x_state {
3928c2ecf20Sopenharmony_ci	idle=0,
3938c2ecf20Sopenharmony_ci	unknown,
3948c2ecf20Sopenharmony_ci	seldo,
3958c2ecf20Sopenharmony_ci	seldi,
3968c2ecf20Sopenharmony_ci	selto,
3978c2ecf20Sopenharmony_ci	busfree,
3988c2ecf20Sopenharmony_ci	msgo,
3998c2ecf20Sopenharmony_ci	cmd,
4008c2ecf20Sopenharmony_ci	msgi,
4018c2ecf20Sopenharmony_ci	status,
4028c2ecf20Sopenharmony_ci	datai,
4038c2ecf20Sopenharmony_ci	datao,
4048c2ecf20Sopenharmony_ci	parerr,
4058c2ecf20Sopenharmony_ci	rsti,
4068c2ecf20Sopenharmony_ci	maxstate
4078c2ecf20Sopenharmony_ci};
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci/*
4108c2ecf20Sopenharmony_ci * current state information of the host
4118c2ecf20Sopenharmony_ci *
4128c2ecf20Sopenharmony_ci */
4138c2ecf20Sopenharmony_cistruct aha152x_hostdata {
4148c2ecf20Sopenharmony_ci	struct scsi_cmnd *issue_SC;
4158c2ecf20Sopenharmony_ci		/* pending commands to issue */
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	struct scsi_cmnd *current_SC;
4188c2ecf20Sopenharmony_ci		/* current command on the bus */
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	struct scsi_cmnd *disconnected_SC;
4218c2ecf20Sopenharmony_ci		/* commands that disconnected */
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	struct scsi_cmnd *done_SC;
4248c2ecf20Sopenharmony_ci		/* command that was completed */
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	spinlock_t lock;
4278c2ecf20Sopenharmony_ci		/* host lock */
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT)
4308c2ecf20Sopenharmony_ci	int	      total_commands;
4318c2ecf20Sopenharmony_ci	int	      disconnections;
4328c2ecf20Sopenharmony_ci	int	      busfree_without_any_action;
4338c2ecf20Sopenharmony_ci	int	      busfree_without_old_command;
4348c2ecf20Sopenharmony_ci	int	      busfree_without_new_command;
4358c2ecf20Sopenharmony_ci	int	      busfree_without_done_command;
4368c2ecf20Sopenharmony_ci	int	      busfree_with_check_condition;
4378c2ecf20Sopenharmony_ci	int	      count[maxstate];
4388c2ecf20Sopenharmony_ci	int	      count_trans[maxstate];
4398c2ecf20Sopenharmony_ci	unsigned long time[maxstate];
4408c2ecf20Sopenharmony_ci#endif
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	int commands;		/* current number of commands */
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	int reconnect;		/* disconnection allowed */
4458c2ecf20Sopenharmony_ci	int parity;		/* parity checking enabled */
4468c2ecf20Sopenharmony_ci	int synchronous;	/* synchronous transferes enabled */
4478c2ecf20Sopenharmony_ci	int delay;		/* reset out delay */
4488c2ecf20Sopenharmony_ci	int ext_trans;		/* extended translation enabled */
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	int swint;		/* software-interrupt was fired during detect() */
4518c2ecf20Sopenharmony_ci	int service;		/* bh needs to be run */
4528c2ecf20Sopenharmony_ci	int in_intr;		/* bh is running */
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	/* current state,
4558c2ecf20Sopenharmony_ci	   previous state,
4568c2ecf20Sopenharmony_ci	   last state different from current state */
4578c2ecf20Sopenharmony_ci	enum aha152x_state state, prevstate, laststate;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	int target;
4608c2ecf20Sopenharmony_ci		/* reconnecting target */
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	unsigned char syncrate[8];
4638c2ecf20Sopenharmony_ci		/* current synchronous transfer agreements */
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	unsigned char syncneg[8];
4668c2ecf20Sopenharmony_ci		/* 0: no negotiation;
4678c2ecf20Sopenharmony_ci		 * 1: negotiation in progress;
4688c2ecf20Sopenharmony_ci		 * 2: negotiation completed
4698c2ecf20Sopenharmony_ci		 */
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	int cmd_i;
4728c2ecf20Sopenharmony_ci		/* number of sent bytes of current command */
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	int msgi_len;
4758c2ecf20Sopenharmony_ci		/* number of received message bytes */
4768c2ecf20Sopenharmony_ci	unsigned char msgi[256];
4778c2ecf20Sopenharmony_ci		/* received message bytes */
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	int msgo_i, msgo_len;
4808c2ecf20Sopenharmony_ci		/* number of sent bytes and length of current messages */
4818c2ecf20Sopenharmony_ci	unsigned char msgo[256];
4828c2ecf20Sopenharmony_ci		/* pending messages */
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	int data_len;
4858c2ecf20Sopenharmony_ci		/* number of sent/received bytes in dataphase */
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	unsigned long io_port0;
4888c2ecf20Sopenharmony_ci	unsigned long io_port1;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci#ifdef __ISAPNP__
4918c2ecf20Sopenharmony_ci	struct pnp_dev *pnpdev;
4928c2ecf20Sopenharmony_ci#endif
4938c2ecf20Sopenharmony_ci	struct list_head host_list;
4948c2ecf20Sopenharmony_ci};
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci/*
4988c2ecf20Sopenharmony_ci * host specific command extension
4998c2ecf20Sopenharmony_ci *
5008c2ecf20Sopenharmony_ci */
5018c2ecf20Sopenharmony_cistruct aha152x_scdata {
5028c2ecf20Sopenharmony_ci	struct scsi_cmnd *next;	/* next sc in queue */
5038c2ecf20Sopenharmony_ci	struct completion *done;/* semaphore to block on */
5048c2ecf20Sopenharmony_ci	struct scsi_eh_save ses;
5058c2ecf20Sopenharmony_ci};
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci/* access macros for hostdata */
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci#define HOSTDATA(shpnt)		((struct aha152x_hostdata *) &shpnt->hostdata)
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci#define HOSTNO			((shpnt)->host_no)
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci#define CURRENT_SC		(HOSTDATA(shpnt)->current_SC)
5148c2ecf20Sopenharmony_ci#define DONE_SC			(HOSTDATA(shpnt)->done_SC)
5158c2ecf20Sopenharmony_ci#define ISSUE_SC		(HOSTDATA(shpnt)->issue_SC)
5168c2ecf20Sopenharmony_ci#define DISCONNECTED_SC		(HOSTDATA(shpnt)->disconnected_SC)
5178c2ecf20Sopenharmony_ci#define QLOCK			(HOSTDATA(shpnt)->lock)
5188c2ecf20Sopenharmony_ci#define QLOCKER			(HOSTDATA(shpnt)->locker)
5198c2ecf20Sopenharmony_ci#define QLOCKERL		(HOSTDATA(shpnt)->lockerl)
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci#define STATE			(HOSTDATA(shpnt)->state)
5228c2ecf20Sopenharmony_ci#define PREVSTATE		(HOSTDATA(shpnt)->prevstate)
5238c2ecf20Sopenharmony_ci#define LASTSTATE		(HOSTDATA(shpnt)->laststate)
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci#define RECONN_TARGET		(HOSTDATA(shpnt)->target)
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci#define CMD_I			(HOSTDATA(shpnt)->cmd_i)
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci#define MSGO(i)			(HOSTDATA(shpnt)->msgo[i])
5308c2ecf20Sopenharmony_ci#define MSGO_I			(HOSTDATA(shpnt)->msgo_i)
5318c2ecf20Sopenharmony_ci#define MSGOLEN			(HOSTDATA(shpnt)->msgo_len)
5328c2ecf20Sopenharmony_ci#define ADDMSGO(x)		(MSGOLEN<256 ? (void)(MSGO(MSGOLEN++)=x) : aha152x_error(shpnt,"MSGO overflow"))
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci#define MSGI(i)			(HOSTDATA(shpnt)->msgi[i])
5358c2ecf20Sopenharmony_ci#define MSGILEN			(HOSTDATA(shpnt)->msgi_len)
5368c2ecf20Sopenharmony_ci#define ADDMSGI(x)		(MSGILEN<256 ? (void)(MSGI(MSGILEN++)=x) : aha152x_error(shpnt,"MSGI overflow"))
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci#define DATA_LEN		(HOSTDATA(shpnt)->data_len)
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci#define SYNCRATE		(HOSTDATA(shpnt)->syncrate[CURRENT_SC->device->id])
5418c2ecf20Sopenharmony_ci#define SYNCNEG			(HOSTDATA(shpnt)->syncneg[CURRENT_SC->device->id])
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci#define DELAY			(HOSTDATA(shpnt)->delay)
5448c2ecf20Sopenharmony_ci#define EXT_TRANS		(HOSTDATA(shpnt)->ext_trans)
5458c2ecf20Sopenharmony_ci#define TC1550			(HOSTDATA(shpnt)->tc1550)
5468c2ecf20Sopenharmony_ci#define RECONNECT		(HOSTDATA(shpnt)->reconnect)
5478c2ecf20Sopenharmony_ci#define PARITY			(HOSTDATA(shpnt)->parity)
5488c2ecf20Sopenharmony_ci#define SYNCHRONOUS		(HOSTDATA(shpnt)->synchronous)
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci#define HOSTIOPORT0		(HOSTDATA(shpnt)->io_port0)
5518c2ecf20Sopenharmony_ci#define HOSTIOPORT1		(HOSTDATA(shpnt)->io_port1)
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci#define SCDATA(SCpnt)		((struct aha152x_scdata *) (SCpnt)->host_scribble)
5548c2ecf20Sopenharmony_ci#define SCNEXT(SCpnt)		SCDATA(SCpnt)->next
5558c2ecf20Sopenharmony_ci#define SCSEM(SCpnt)		SCDATA(SCpnt)->done
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci#define SG_ADDRESS(buffer)	((char *) sg_virt((buffer)))
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci/* state handling */
5608c2ecf20Sopenharmony_cistatic void seldi_run(struct Scsi_Host *shpnt);
5618c2ecf20Sopenharmony_cistatic void seldo_run(struct Scsi_Host *shpnt);
5628c2ecf20Sopenharmony_cistatic void selto_run(struct Scsi_Host *shpnt);
5638c2ecf20Sopenharmony_cistatic void busfree_run(struct Scsi_Host *shpnt);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_cistatic void msgo_init(struct Scsi_Host *shpnt);
5668c2ecf20Sopenharmony_cistatic void msgo_run(struct Scsi_Host *shpnt);
5678c2ecf20Sopenharmony_cistatic void msgo_end(struct Scsi_Host *shpnt);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_cistatic void cmd_init(struct Scsi_Host *shpnt);
5708c2ecf20Sopenharmony_cistatic void cmd_run(struct Scsi_Host *shpnt);
5718c2ecf20Sopenharmony_cistatic void cmd_end(struct Scsi_Host *shpnt);
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_cistatic void datai_init(struct Scsi_Host *shpnt);
5748c2ecf20Sopenharmony_cistatic void datai_run(struct Scsi_Host *shpnt);
5758c2ecf20Sopenharmony_cistatic void datai_end(struct Scsi_Host *shpnt);
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_cistatic void datao_init(struct Scsi_Host *shpnt);
5788c2ecf20Sopenharmony_cistatic void datao_run(struct Scsi_Host *shpnt);
5798c2ecf20Sopenharmony_cistatic void datao_end(struct Scsi_Host *shpnt);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_cistatic void status_run(struct Scsi_Host *shpnt);
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_cistatic void msgi_run(struct Scsi_Host *shpnt);
5848c2ecf20Sopenharmony_cistatic void msgi_end(struct Scsi_Host *shpnt);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_cistatic void parerr_run(struct Scsi_Host *shpnt);
5878c2ecf20Sopenharmony_cistatic void rsti_run(struct Scsi_Host *shpnt);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_cistatic void is_complete(struct Scsi_Host *shpnt);
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci/*
5928c2ecf20Sopenharmony_ci * driver states
5938c2ecf20Sopenharmony_ci *
5948c2ecf20Sopenharmony_ci */
5958c2ecf20Sopenharmony_cistatic struct {
5968c2ecf20Sopenharmony_ci	char		*name;
5978c2ecf20Sopenharmony_ci	void		(*init)(struct Scsi_Host *);
5988c2ecf20Sopenharmony_ci	void		(*run)(struct Scsi_Host *);
5998c2ecf20Sopenharmony_ci	void		(*end)(struct Scsi_Host *);
6008c2ecf20Sopenharmony_ci	int		spio;
6018c2ecf20Sopenharmony_ci} states[] = {
6028c2ecf20Sopenharmony_ci	{ "idle",	NULL,		NULL,		NULL,		0},
6038c2ecf20Sopenharmony_ci	{ "unknown",	NULL,		NULL,		NULL,		0},
6048c2ecf20Sopenharmony_ci	{ "seldo",	NULL,		seldo_run,	NULL,		0},
6058c2ecf20Sopenharmony_ci	{ "seldi",	NULL,		seldi_run,	NULL,		0},
6068c2ecf20Sopenharmony_ci	{ "selto",	NULL,		selto_run,	NULL,		0},
6078c2ecf20Sopenharmony_ci	{ "busfree",	NULL,		busfree_run,	NULL,		0},
6088c2ecf20Sopenharmony_ci	{ "msgo",	msgo_init,	msgo_run,	msgo_end,	1},
6098c2ecf20Sopenharmony_ci	{ "cmd",	cmd_init,	cmd_run,	cmd_end,	1},
6108c2ecf20Sopenharmony_ci	{ "msgi",	NULL,		msgi_run,	msgi_end,	1},
6118c2ecf20Sopenharmony_ci	{ "status",	NULL,		status_run,	NULL,		1},
6128c2ecf20Sopenharmony_ci	{ "datai",	datai_init,	datai_run,	datai_end,	0},
6138c2ecf20Sopenharmony_ci	{ "datao",	datao_init,	datao_run,	datao_end,	0},
6148c2ecf20Sopenharmony_ci	{ "parerr",	NULL,		parerr_run,	NULL,		0},
6158c2ecf20Sopenharmony_ci	{ "rsti",	NULL,		rsti_run,	NULL,		0},
6168c2ecf20Sopenharmony_ci};
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci/* setup & interrupt */
6198c2ecf20Sopenharmony_cistatic irqreturn_t intr(int irq, void *dev_id);
6208c2ecf20Sopenharmony_cistatic void reset_ports(struct Scsi_Host *shpnt);
6218c2ecf20Sopenharmony_cistatic void aha152x_error(struct Scsi_Host *shpnt, char *msg);
6228c2ecf20Sopenharmony_cistatic void done(struct Scsi_Host *shpnt, int error);
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci/* diagnostics */
6258c2ecf20Sopenharmony_cistatic void show_command(struct scsi_cmnd * ptr);
6268c2ecf20Sopenharmony_cistatic void show_queues(struct Scsi_Host *shpnt);
6278c2ecf20Sopenharmony_cistatic void disp_enintr(struct Scsi_Host *shpnt);
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci/*
6318c2ecf20Sopenharmony_ci *  queue services:
6328c2ecf20Sopenharmony_ci *
6338c2ecf20Sopenharmony_ci */
6348c2ecf20Sopenharmony_cistatic inline void append_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC)
6358c2ecf20Sopenharmony_ci{
6368c2ecf20Sopenharmony_ci	struct scsi_cmnd *end;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	SCNEXT(new_SC) = NULL;
6398c2ecf20Sopenharmony_ci	if (!*SC)
6408c2ecf20Sopenharmony_ci		*SC = new_SC;
6418c2ecf20Sopenharmony_ci	else {
6428c2ecf20Sopenharmony_ci		for (end = *SC; SCNEXT(end); end = SCNEXT(end))
6438c2ecf20Sopenharmony_ci			;
6448c2ecf20Sopenharmony_ci		SCNEXT(end) = new_SC;
6458c2ecf20Sopenharmony_ci	}
6468c2ecf20Sopenharmony_ci}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_cistatic inline struct scsi_cmnd *remove_first_SC(struct scsi_cmnd ** SC)
6498c2ecf20Sopenharmony_ci{
6508c2ecf20Sopenharmony_ci	struct scsi_cmnd *ptr;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	ptr = *SC;
6538c2ecf20Sopenharmony_ci	if (ptr) {
6548c2ecf20Sopenharmony_ci		*SC = SCNEXT(*SC);
6558c2ecf20Sopenharmony_ci		SCNEXT(ptr)=NULL;
6568c2ecf20Sopenharmony_ci	}
6578c2ecf20Sopenharmony_ci	return ptr;
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cistatic inline struct scsi_cmnd *remove_lun_SC(struct scsi_cmnd ** SC,
6618c2ecf20Sopenharmony_ci					      int target, int lun)
6628c2ecf20Sopenharmony_ci{
6638c2ecf20Sopenharmony_ci	struct scsi_cmnd *ptr, *prev;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	for (ptr = *SC, prev = NULL;
6668c2ecf20Sopenharmony_ci	     ptr && ((ptr->device->id != target) || (ptr->device->lun != lun));
6678c2ecf20Sopenharmony_ci	     prev = ptr, ptr = SCNEXT(ptr))
6688c2ecf20Sopenharmony_ci	     ;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	if (ptr) {
6718c2ecf20Sopenharmony_ci		if (prev)
6728c2ecf20Sopenharmony_ci			SCNEXT(prev) = SCNEXT(ptr);
6738c2ecf20Sopenharmony_ci		else
6748c2ecf20Sopenharmony_ci			*SC = SCNEXT(ptr);
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci		SCNEXT(ptr)=NULL;
6778c2ecf20Sopenharmony_ci	}
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	return ptr;
6808c2ecf20Sopenharmony_ci}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_cistatic inline struct scsi_cmnd *remove_SC(struct scsi_cmnd **SC,
6838c2ecf20Sopenharmony_ci					  struct scsi_cmnd *SCp)
6848c2ecf20Sopenharmony_ci{
6858c2ecf20Sopenharmony_ci	struct scsi_cmnd *ptr, *prev;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	for (ptr = *SC, prev = NULL;
6888c2ecf20Sopenharmony_ci	     ptr && SCp!=ptr;
6898c2ecf20Sopenharmony_ci	     prev = ptr, ptr = SCNEXT(ptr))
6908c2ecf20Sopenharmony_ci	     ;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	if (ptr) {
6938c2ecf20Sopenharmony_ci		if (prev)
6948c2ecf20Sopenharmony_ci			SCNEXT(prev) = SCNEXT(ptr);
6958c2ecf20Sopenharmony_ci		else
6968c2ecf20Sopenharmony_ci			*SC = SCNEXT(ptr);
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci		SCNEXT(ptr)=NULL;
6998c2ecf20Sopenharmony_ci	}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	return ptr;
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_cistatic irqreturn_t swintr(int irqno, void *dev_id)
7058c2ecf20Sopenharmony_ci{
7068c2ecf20Sopenharmony_ci	struct Scsi_Host *shpnt = dev_id;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	HOSTDATA(shpnt)->swint++;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	SETPORT(DMACNTRL0, INTEN);
7118c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
7128c2ecf20Sopenharmony_ci}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_cistruct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	struct Scsi_Host *shpnt;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	shpnt = scsi_host_alloc(&aha152x_driver_template, sizeof(struct aha152x_hostdata));
7198c2ecf20Sopenharmony_ci	if (!shpnt) {
7208c2ecf20Sopenharmony_ci		printk(KERN_ERR "aha152x: scsi_host_alloc failed\n");
7218c2ecf20Sopenharmony_ci		return NULL;
7228c2ecf20Sopenharmony_ci	}
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt));
7258c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&HOSTDATA(shpnt)->host_list);
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	/* need to have host registered before triggering any interrupt */
7288c2ecf20Sopenharmony_ci	list_add_tail(&HOSTDATA(shpnt)->host_list, &aha152x_host_list);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	shpnt->io_port   = setup->io_port;
7318c2ecf20Sopenharmony_ci	shpnt->n_io_port = IO_RANGE;
7328c2ecf20Sopenharmony_ci	shpnt->irq       = setup->irq;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	if (!setup->tc1550) {
7358c2ecf20Sopenharmony_ci		HOSTIOPORT0 = setup->io_port;
7368c2ecf20Sopenharmony_ci		HOSTIOPORT1 = setup->io_port;
7378c2ecf20Sopenharmony_ci	} else {
7388c2ecf20Sopenharmony_ci		HOSTIOPORT0 = setup->io_port+0x10;
7398c2ecf20Sopenharmony_ci		HOSTIOPORT1 = setup->io_port-0x10;
7408c2ecf20Sopenharmony_ci	}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	spin_lock_init(&QLOCK);
7438c2ecf20Sopenharmony_ci	RECONNECT   = setup->reconnect;
7448c2ecf20Sopenharmony_ci	SYNCHRONOUS = setup->synchronous;
7458c2ecf20Sopenharmony_ci	PARITY      = setup->parity;
7468c2ecf20Sopenharmony_ci	DELAY       = setup->delay;
7478c2ecf20Sopenharmony_ci	EXT_TRANS   = setup->ext_trans;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	SETPORT(SCSIID, setup->scsiid << 4);
7508c2ecf20Sopenharmony_ci	shpnt->this_id = setup->scsiid;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	if (setup->reconnect)
7538c2ecf20Sopenharmony_ci		shpnt->can_queue = AHA152X_MAXQUEUE;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	/* RESET OUT */
7568c2ecf20Sopenharmony_ci	printk("aha152x: resetting bus...\n");
7578c2ecf20Sopenharmony_ci	SETPORT(SCSISEQ, SCSIRSTO);
7588c2ecf20Sopenharmony_ci	mdelay(256);
7598c2ecf20Sopenharmony_ci	SETPORT(SCSISEQ, 0);
7608c2ecf20Sopenharmony_ci	mdelay(DELAY);
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	reset_ports(shpnt);
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	printk(KERN_INFO
7658c2ecf20Sopenharmony_ci	       "aha152x%d%s: "
7668c2ecf20Sopenharmony_ci	       "vital data: rev=%x, "
7678c2ecf20Sopenharmony_ci	       "io=0x%03lx (0x%03lx/0x%03lx), "
7688c2ecf20Sopenharmony_ci	       "irq=%d, "
7698c2ecf20Sopenharmony_ci	       "scsiid=%d, "
7708c2ecf20Sopenharmony_ci	       "reconnect=%s, "
7718c2ecf20Sopenharmony_ci	       "parity=%s, "
7728c2ecf20Sopenharmony_ci	       "synchronous=%s, "
7738c2ecf20Sopenharmony_ci	       "delay=%d, "
7748c2ecf20Sopenharmony_ci	       "extended translation=%s\n",
7758c2ecf20Sopenharmony_ci	       shpnt->host_no, setup->tc1550 ? " (tc1550 mode)" : "",
7768c2ecf20Sopenharmony_ci	       GETPORT(REV) & 0x7,
7778c2ecf20Sopenharmony_ci	       shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1,
7788c2ecf20Sopenharmony_ci	       shpnt->irq,
7798c2ecf20Sopenharmony_ci	       shpnt->this_id,
7808c2ecf20Sopenharmony_ci	       RECONNECT ? "enabled" : "disabled",
7818c2ecf20Sopenharmony_ci	       PARITY ? "enabled" : "disabled",
7828c2ecf20Sopenharmony_ci	       SYNCHRONOUS ? "enabled" : "disabled",
7838c2ecf20Sopenharmony_ci	       DELAY,
7848c2ecf20Sopenharmony_ci	       EXT_TRANS ? "enabled" : "disabled");
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	/* not expecting any interrupts */
7878c2ecf20Sopenharmony_ci	SETPORT(SIMODE0, 0);
7888c2ecf20Sopenharmony_ci	SETPORT(SIMODE1, 0);
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	if (request_irq(shpnt->irq, swintr, IRQF_SHARED, "aha152x", shpnt)) {
7918c2ecf20Sopenharmony_ci		printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq);
7928c2ecf20Sopenharmony_ci		goto out_host_put;
7938c2ecf20Sopenharmony_ci	}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	HOSTDATA(shpnt)->swint = 0;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	printk(KERN_INFO "aha152x%d: trying software interrupt, ", shpnt->host_no);
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	mb();
8008c2ecf20Sopenharmony_ci	SETPORT(DMACNTRL0, SWINT|INTEN);
8018c2ecf20Sopenharmony_ci	mdelay(1000);
8028c2ecf20Sopenharmony_ci	free_irq(shpnt->irq, shpnt);
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	if (!HOSTDATA(shpnt)->swint) {
8058c2ecf20Sopenharmony_ci		if (TESTHI(DMASTAT, INTSTAT)) {
8068c2ecf20Sopenharmony_ci			printk("lost.\n");
8078c2ecf20Sopenharmony_ci		} else {
8088c2ecf20Sopenharmony_ci			printk("failed.\n");
8098c2ecf20Sopenharmony_ci		}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci		SETPORT(DMACNTRL0, INTEN);
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci		printk(KERN_ERR "aha152x%d: irq %d possibly wrong.  "
8148c2ecf20Sopenharmony_ci				"Please verify.\n", shpnt->host_no, shpnt->irq);
8158c2ecf20Sopenharmony_ci		goto out_host_put;
8168c2ecf20Sopenharmony_ci	}
8178c2ecf20Sopenharmony_ci	printk("ok.\n");
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	/* clear interrupts */
8218c2ecf20Sopenharmony_ci	SETPORT(SSTAT0, 0x7f);
8228c2ecf20Sopenharmony_ci	SETPORT(SSTAT1, 0xef);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	if (request_irq(shpnt->irq, intr, IRQF_SHARED, "aha152x", shpnt)) {
8258c2ecf20Sopenharmony_ci		printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq);
8268c2ecf20Sopenharmony_ci		goto out_host_put;
8278c2ecf20Sopenharmony_ci	}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	if( scsi_add_host(shpnt, NULL) ) {
8308c2ecf20Sopenharmony_ci		free_irq(shpnt->irq, shpnt);
8318c2ecf20Sopenharmony_ci		printk(KERN_ERR "aha152x%d: failed to add host.\n", shpnt->host_no);
8328c2ecf20Sopenharmony_ci		goto out_host_put;
8338c2ecf20Sopenharmony_ci	}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	scsi_scan_host(shpnt);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	return shpnt;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ciout_host_put:
8408c2ecf20Sopenharmony_ci	list_del(&HOSTDATA(shpnt)->host_list);
8418c2ecf20Sopenharmony_ci	scsi_host_put(shpnt);
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	return NULL;
8448c2ecf20Sopenharmony_ci}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_civoid aha152x_release(struct Scsi_Host *shpnt)
8478c2ecf20Sopenharmony_ci{
8488c2ecf20Sopenharmony_ci	if (!shpnt)
8498c2ecf20Sopenharmony_ci		return;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	scsi_remove_host(shpnt);
8528c2ecf20Sopenharmony_ci	if (shpnt->irq)
8538c2ecf20Sopenharmony_ci		free_irq(shpnt->irq, shpnt);
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci#if !defined(AHA152X_PCMCIA)
8568c2ecf20Sopenharmony_ci	if (shpnt->io_port)
8578c2ecf20Sopenharmony_ci		release_region(shpnt->io_port, IO_RANGE);
8588c2ecf20Sopenharmony_ci#endif
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci#ifdef __ISAPNP__
8618c2ecf20Sopenharmony_ci	if (HOSTDATA(shpnt)->pnpdev)
8628c2ecf20Sopenharmony_ci		pnp_device_detach(HOSTDATA(shpnt)->pnpdev);
8638c2ecf20Sopenharmony_ci#endif
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	list_del(&HOSTDATA(shpnt)->host_list);
8668c2ecf20Sopenharmony_ci	scsi_host_put(shpnt);
8678c2ecf20Sopenharmony_ci}
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci/*
8718c2ecf20Sopenharmony_ci * setup controller to generate interrupts depending
8728c2ecf20Sopenharmony_ci * on current state (lock has to be acquired)
8738c2ecf20Sopenharmony_ci *
8748c2ecf20Sopenharmony_ci */
8758c2ecf20Sopenharmony_cistatic int setup_expected_interrupts(struct Scsi_Host *shpnt)
8768c2ecf20Sopenharmony_ci{
8778c2ecf20Sopenharmony_ci	if(CURRENT_SC) {
8788c2ecf20Sopenharmony_ci		CURRENT_SC->SCp.phase |= 1 << 16;
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci		if(CURRENT_SC->SCp.phase & selecting) {
8818c2ecf20Sopenharmony_ci			SETPORT(SSTAT1, SELTO);
8828c2ecf20Sopenharmony_ci			SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
8838c2ecf20Sopenharmony_ci			SETPORT(SIMODE1, ENSELTIMO);
8848c2ecf20Sopenharmony_ci		} else {
8858c2ecf20Sopenharmony_ci			SETPORT(SIMODE0, (CURRENT_SC->SCp.phase & spiordy) ? ENSPIORDY : 0);
8868c2ecf20Sopenharmony_ci			SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE);
8878c2ecf20Sopenharmony_ci		}
8888c2ecf20Sopenharmony_ci	} else if(STATE==seldi) {
8898c2ecf20Sopenharmony_ci		SETPORT(SIMODE0, 0);
8908c2ecf20Sopenharmony_ci		SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE);
8918c2ecf20Sopenharmony_ci	} else {
8928c2ecf20Sopenharmony_ci		SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
8938c2ecf20Sopenharmony_ci		SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0));
8948c2ecf20Sopenharmony_ci	}
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	if(!HOSTDATA(shpnt)->in_intr)
8978c2ecf20Sopenharmony_ci		SETBITS(DMACNTRL0, INTEN);
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	return TESTHI(DMASTAT, INTSTAT);
9008c2ecf20Sopenharmony_ci}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci/*
9048c2ecf20Sopenharmony_ci *  Queue a command and setup interrupts for a free bus.
9058c2ecf20Sopenharmony_ci */
9068c2ecf20Sopenharmony_cistatic int aha152x_internal_queue(struct scsi_cmnd *SCpnt,
9078c2ecf20Sopenharmony_ci				  struct completion *complete,
9088c2ecf20Sopenharmony_ci				  int phase, void (*done)(struct scsi_cmnd *))
9098c2ecf20Sopenharmony_ci{
9108c2ecf20Sopenharmony_ci	struct Scsi_Host *shpnt = SCpnt->device->host;
9118c2ecf20Sopenharmony_ci	unsigned long flags;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	SCpnt->scsi_done	= done;
9148c2ecf20Sopenharmony_ci	SCpnt->SCp.phase	= not_issued | phase;
9158c2ecf20Sopenharmony_ci	SCpnt->SCp.Status	= 0x1; /* Ilegal status by SCSI standard */
9168c2ecf20Sopenharmony_ci	SCpnt->SCp.Message	= 0;
9178c2ecf20Sopenharmony_ci	SCpnt->SCp.have_data_in	= 0;
9188c2ecf20Sopenharmony_ci	SCpnt->SCp.sent_command	= 0;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	if(SCpnt->SCp.phase & (resetting|check_condition)) {
9218c2ecf20Sopenharmony_ci		if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) {
9228c2ecf20Sopenharmony_ci			scmd_printk(KERN_ERR, SCpnt, "cannot reuse command\n");
9238c2ecf20Sopenharmony_ci			return FAILED;
9248c2ecf20Sopenharmony_ci		}
9258c2ecf20Sopenharmony_ci	} else {
9268c2ecf20Sopenharmony_ci		SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
9278c2ecf20Sopenharmony_ci		if(!SCpnt->host_scribble) {
9288c2ecf20Sopenharmony_ci			scmd_printk(KERN_ERR, SCpnt, "allocation failed\n");
9298c2ecf20Sopenharmony_ci			return FAILED;
9308c2ecf20Sopenharmony_ci		}
9318c2ecf20Sopenharmony_ci	}
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	SCNEXT(SCpnt)		= NULL;
9348c2ecf20Sopenharmony_ci	SCSEM(SCpnt)		= complete;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	/* setup scratch area
9378c2ecf20Sopenharmony_ci	   SCp.ptr              : buffer pointer
9388c2ecf20Sopenharmony_ci	   SCp.this_residual    : buffer length
9398c2ecf20Sopenharmony_ci	   SCp.buffer           : next buffer
9408c2ecf20Sopenharmony_ci	   SCp.phase            : current state of the command */
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	if ((phase & resetting) || !scsi_sglist(SCpnt)) {
9438c2ecf20Sopenharmony_ci		SCpnt->SCp.ptr           = NULL;
9448c2ecf20Sopenharmony_ci		SCpnt->SCp.this_residual = 0;
9458c2ecf20Sopenharmony_ci		scsi_set_resid(SCpnt, 0);
9468c2ecf20Sopenharmony_ci		SCpnt->SCp.buffer           = NULL;
9478c2ecf20Sopenharmony_ci	} else {
9488c2ecf20Sopenharmony_ci		scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
9498c2ecf20Sopenharmony_ci		SCpnt->SCp.buffer           = scsi_sglist(SCpnt);
9508c2ecf20Sopenharmony_ci		SCpnt->SCp.ptr              = SG_ADDRESS(SCpnt->SCp.buffer);
9518c2ecf20Sopenharmony_ci		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
9528c2ecf20Sopenharmony_ci	}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	DO_LOCK(flags);
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT)
9578c2ecf20Sopenharmony_ci	HOSTDATA(shpnt)->total_commands++;
9588c2ecf20Sopenharmony_ci#endif
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	/* Turn led on, when this is the first command. */
9618c2ecf20Sopenharmony_ci	HOSTDATA(shpnt)->commands++;
9628c2ecf20Sopenharmony_ci	if (HOSTDATA(shpnt)->commands==1)
9638c2ecf20Sopenharmony_ci		SETPORT(PORTA, 1);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	append_SC(&ISSUE_SC, SCpnt);
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	if(!HOSTDATA(shpnt)->in_intr)
9688c2ecf20Sopenharmony_ci		setup_expected_interrupts(shpnt);
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	DO_UNLOCK(flags);
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	return 0;
9738c2ecf20Sopenharmony_ci}
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci/*
9768c2ecf20Sopenharmony_ci *  queue a command
9778c2ecf20Sopenharmony_ci *
9788c2ecf20Sopenharmony_ci */
9798c2ecf20Sopenharmony_cistatic int aha152x_queue_lck(struct scsi_cmnd *SCpnt,
9808c2ecf20Sopenharmony_ci			     void (*done)(struct scsi_cmnd *))
9818c2ecf20Sopenharmony_ci{
9828c2ecf20Sopenharmony_ci	return aha152x_internal_queue(SCpnt, NULL, 0, done);
9838c2ecf20Sopenharmony_ci}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(aha152x_queue)
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci/*
9898c2ecf20Sopenharmony_ci *
9908c2ecf20Sopenharmony_ci */
9918c2ecf20Sopenharmony_cistatic void reset_done(struct scsi_cmnd *SCpnt)
9928c2ecf20Sopenharmony_ci{
9938c2ecf20Sopenharmony_ci	if(SCSEM(SCpnt)) {
9948c2ecf20Sopenharmony_ci		complete(SCSEM(SCpnt));
9958c2ecf20Sopenharmony_ci	} else {
9968c2ecf20Sopenharmony_ci		printk(KERN_ERR "aha152x: reset_done w/o completion\n");
9978c2ecf20Sopenharmony_ci	}
9988c2ecf20Sopenharmony_ci}
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci/*
10018c2ecf20Sopenharmony_ci *  Abort a command
10028c2ecf20Sopenharmony_ci *
10038c2ecf20Sopenharmony_ci */
10048c2ecf20Sopenharmony_cistatic int aha152x_abort(struct scsi_cmnd *SCpnt)
10058c2ecf20Sopenharmony_ci{
10068c2ecf20Sopenharmony_ci	struct Scsi_Host *shpnt = SCpnt->device->host;
10078c2ecf20Sopenharmony_ci	struct scsi_cmnd *ptr;
10088c2ecf20Sopenharmony_ci	unsigned long flags;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	DO_LOCK(flags);
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	ptr=remove_SC(&ISSUE_SC, SCpnt);
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	if(ptr) {
10158c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->commands--;
10168c2ecf20Sopenharmony_ci		if (!HOSTDATA(shpnt)->commands)
10178c2ecf20Sopenharmony_ci			SETPORT(PORTA, 0);
10188c2ecf20Sopenharmony_ci		DO_UNLOCK(flags);
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci		kfree(SCpnt->host_scribble);
10218c2ecf20Sopenharmony_ci		SCpnt->host_scribble=NULL;
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci		return SUCCESS;
10248c2ecf20Sopenharmony_ci	}
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	DO_UNLOCK(flags);
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	/*
10298c2ecf20Sopenharmony_ci	 * FIXME:
10308c2ecf20Sopenharmony_ci	 * for current command: queue ABORT for message out and raise ATN
10318c2ecf20Sopenharmony_ci	 * for disconnected command: pseudo SC with ABORT message or ABORT on reselection?
10328c2ecf20Sopenharmony_ci	 *
10338c2ecf20Sopenharmony_ci	 */
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	scmd_printk(KERN_ERR, SCpnt,
10368c2ecf20Sopenharmony_ci		    "cannot abort running or disconnected command\n");
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	return FAILED;
10398c2ecf20Sopenharmony_ci}
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci/*
10428c2ecf20Sopenharmony_ci * Reset a device
10438c2ecf20Sopenharmony_ci *
10448c2ecf20Sopenharmony_ci */
10458c2ecf20Sopenharmony_cistatic int aha152x_device_reset(struct scsi_cmnd * SCpnt)
10468c2ecf20Sopenharmony_ci{
10478c2ecf20Sopenharmony_ci	struct Scsi_Host *shpnt = SCpnt->device->host;
10488c2ecf20Sopenharmony_ci	DECLARE_COMPLETION(done);
10498c2ecf20Sopenharmony_ci	int ret, issued, disconnected;
10508c2ecf20Sopenharmony_ci	unsigned char old_cmd_len = SCpnt->cmd_len;
10518c2ecf20Sopenharmony_ci	unsigned long flags;
10528c2ecf20Sopenharmony_ci	unsigned long timeleft;
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	if(CURRENT_SC==SCpnt) {
10558c2ecf20Sopenharmony_ci		scmd_printk(KERN_ERR, SCpnt, "cannot reset current device\n");
10568c2ecf20Sopenharmony_ci		return FAILED;
10578c2ecf20Sopenharmony_ci	}
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	DO_LOCK(flags);
10608c2ecf20Sopenharmony_ci	issued       = remove_SC(&ISSUE_SC, SCpnt) == NULL;
10618c2ecf20Sopenharmony_ci	disconnected = issued && remove_SC(&DISCONNECTED_SC, SCpnt);
10628c2ecf20Sopenharmony_ci	DO_UNLOCK(flags);
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	SCpnt->cmd_len         = 0;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	aha152x_internal_queue(SCpnt, &done, resetting, reset_done);
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	timeleft = wait_for_completion_timeout(&done, 100*HZ);
10698c2ecf20Sopenharmony_ci	if (!timeleft) {
10708c2ecf20Sopenharmony_ci		/* remove command from issue queue */
10718c2ecf20Sopenharmony_ci		DO_LOCK(flags);
10728c2ecf20Sopenharmony_ci		remove_SC(&ISSUE_SC, SCpnt);
10738c2ecf20Sopenharmony_ci		DO_UNLOCK(flags);
10748c2ecf20Sopenharmony_ci	}
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	SCpnt->cmd_len         = old_cmd_len;
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	DO_LOCK(flags);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	if(SCpnt->SCp.phase & resetted) {
10818c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->commands--;
10828c2ecf20Sopenharmony_ci		if (!HOSTDATA(shpnt)->commands)
10838c2ecf20Sopenharmony_ci			SETPORT(PORTA, 0);
10848c2ecf20Sopenharmony_ci		kfree(SCpnt->host_scribble);
10858c2ecf20Sopenharmony_ci		SCpnt->host_scribble=NULL;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci		ret = SUCCESS;
10888c2ecf20Sopenharmony_ci	} else {
10898c2ecf20Sopenharmony_ci		/* requeue */
10908c2ecf20Sopenharmony_ci		if(!issued) {
10918c2ecf20Sopenharmony_ci			append_SC(&ISSUE_SC, SCpnt);
10928c2ecf20Sopenharmony_ci		} else if(disconnected) {
10938c2ecf20Sopenharmony_ci			append_SC(&DISCONNECTED_SC, SCpnt);
10948c2ecf20Sopenharmony_ci		}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci		ret = FAILED;
10978c2ecf20Sopenharmony_ci	}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	DO_UNLOCK(flags);
11008c2ecf20Sopenharmony_ci	return ret;
11018c2ecf20Sopenharmony_ci}
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_cistatic void free_hard_reset_SCs(struct Scsi_Host *shpnt,
11048c2ecf20Sopenharmony_ci				struct scsi_cmnd **SCs)
11058c2ecf20Sopenharmony_ci{
11068c2ecf20Sopenharmony_ci	struct scsi_cmnd *ptr;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	ptr=*SCs;
11098c2ecf20Sopenharmony_ci	while(ptr) {
11108c2ecf20Sopenharmony_ci		struct scsi_cmnd *next;
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci		if(SCDATA(ptr)) {
11138c2ecf20Sopenharmony_ci			next = SCNEXT(ptr);
11148c2ecf20Sopenharmony_ci		} else {
11158c2ecf20Sopenharmony_ci			scmd_printk(KERN_DEBUG, ptr,
11168c2ecf20Sopenharmony_ci				    "queue corrupted at %p\n", ptr);
11178c2ecf20Sopenharmony_ci			next = NULL;
11188c2ecf20Sopenharmony_ci		}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci		if (!ptr->device->soft_reset) {
11218c2ecf20Sopenharmony_ci			remove_SC(SCs, ptr);
11228c2ecf20Sopenharmony_ci			HOSTDATA(shpnt)->commands--;
11238c2ecf20Sopenharmony_ci			kfree(ptr->host_scribble);
11248c2ecf20Sopenharmony_ci			ptr->host_scribble=NULL;
11258c2ecf20Sopenharmony_ci		}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci		ptr = next;
11288c2ecf20Sopenharmony_ci	}
11298c2ecf20Sopenharmony_ci}
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci/*
11328c2ecf20Sopenharmony_ci * Reset the bus
11338c2ecf20Sopenharmony_ci *
11348c2ecf20Sopenharmony_ci * AIC-6260 has a hard reset (MRST signal), but apparently
11358c2ecf20Sopenharmony_ci * one cannot trigger it via software. So live with
11368c2ecf20Sopenharmony_ci * a soft reset; no-one seemed to have cared.
11378c2ecf20Sopenharmony_ci */
11388c2ecf20Sopenharmony_cistatic int aha152x_bus_reset_host(struct Scsi_Host *shpnt)
11398c2ecf20Sopenharmony_ci{
11408c2ecf20Sopenharmony_ci	unsigned long flags;
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	DO_LOCK(flags);
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	free_hard_reset_SCs(shpnt, &ISSUE_SC);
11458c2ecf20Sopenharmony_ci	free_hard_reset_SCs(shpnt, &DISCONNECTED_SC);
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	SETPORT(SCSISEQ, SCSIRSTO);
11488c2ecf20Sopenharmony_ci	mdelay(256);
11498c2ecf20Sopenharmony_ci	SETPORT(SCSISEQ, 0);
11508c2ecf20Sopenharmony_ci	mdelay(DELAY);
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	setup_expected_interrupts(shpnt);
11538c2ecf20Sopenharmony_ci	if(HOSTDATA(shpnt)->commands==0)
11548c2ecf20Sopenharmony_ci		SETPORT(PORTA, 0);
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	DO_UNLOCK(flags);
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	return SUCCESS;
11598c2ecf20Sopenharmony_ci}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci/*
11628c2ecf20Sopenharmony_ci * Reset the bus
11638c2ecf20Sopenharmony_ci *
11648c2ecf20Sopenharmony_ci */
11658c2ecf20Sopenharmony_cistatic int aha152x_bus_reset(struct scsi_cmnd *SCpnt)
11668c2ecf20Sopenharmony_ci{
11678c2ecf20Sopenharmony_ci	return aha152x_bus_reset_host(SCpnt->device->host);
11688c2ecf20Sopenharmony_ci}
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci/*
11718c2ecf20Sopenharmony_ci *  Restore default values to the AIC-6260 registers and reset the fifos
11728c2ecf20Sopenharmony_ci *
11738c2ecf20Sopenharmony_ci */
11748c2ecf20Sopenharmony_cistatic void reset_ports(struct Scsi_Host *shpnt)
11758c2ecf20Sopenharmony_ci{
11768c2ecf20Sopenharmony_ci	unsigned long flags;
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	/* disable interrupts */
11798c2ecf20Sopenharmony_ci	SETPORT(DMACNTRL0, RSTFIFO);
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	SETPORT(SCSISEQ, 0);
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	SETPORT(SXFRCTL1, 0);
11848c2ecf20Sopenharmony_ci	SETPORT(SCSISIG, 0);
11858c2ecf20Sopenharmony_ci	SETRATE(0);
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	/* clear all interrupt conditions */
11888c2ecf20Sopenharmony_ci	SETPORT(SSTAT0, 0x7f);
11898c2ecf20Sopenharmony_ci	SETPORT(SSTAT1, 0xef);
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	SETPORT(SSTAT4, SYNCERR | FWERR | FRERR);
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	SETPORT(DMACNTRL0, 0);
11948c2ecf20Sopenharmony_ci	SETPORT(DMACNTRL1, 0);
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	SETPORT(BRSTCNTRL, 0xf1);
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	/* clear SCSI fifos and transfer count */
11998c2ecf20Sopenharmony_ci	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
12008c2ecf20Sopenharmony_ci	SETPORT(SXFRCTL0, CH1);
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	DO_LOCK(flags);
12038c2ecf20Sopenharmony_ci	setup_expected_interrupts(shpnt);
12048c2ecf20Sopenharmony_ci	DO_UNLOCK(flags);
12058c2ecf20Sopenharmony_ci}
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci/*
12088c2ecf20Sopenharmony_ci * Reset the host (bus and controller)
12098c2ecf20Sopenharmony_ci *
12108c2ecf20Sopenharmony_ci */
12118c2ecf20Sopenharmony_ciint aha152x_host_reset_host(struct Scsi_Host *shpnt)
12128c2ecf20Sopenharmony_ci{
12138c2ecf20Sopenharmony_ci	aha152x_bus_reset_host(shpnt);
12148c2ecf20Sopenharmony_ci	reset_ports(shpnt);
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	return SUCCESS;
12178c2ecf20Sopenharmony_ci}
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci/*
12208c2ecf20Sopenharmony_ci * Return the "logical geometry"
12218c2ecf20Sopenharmony_ci *
12228c2ecf20Sopenharmony_ci */
12238c2ecf20Sopenharmony_cistatic int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev,
12248c2ecf20Sopenharmony_ci		sector_t capacity, int *info_array)
12258c2ecf20Sopenharmony_ci{
12268c2ecf20Sopenharmony_ci	struct Scsi_Host *shpnt = sdev->host;
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	/* try default translation */
12298c2ecf20Sopenharmony_ci	info_array[0] = 64;
12308c2ecf20Sopenharmony_ci	info_array[1] = 32;
12318c2ecf20Sopenharmony_ci	info_array[2] = (unsigned long)capacity / (64 * 32);
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	/* for disks >1GB do some guessing */
12348c2ecf20Sopenharmony_ci	if (info_array[2] >= 1024) {
12358c2ecf20Sopenharmony_ci		int info[3];
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci		/* try to figure out the geometry from the partition table */
12388c2ecf20Sopenharmony_ci		if (scsicam_bios_param(bdev, capacity, info) < 0 ||
12398c2ecf20Sopenharmony_ci		    !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) {
12408c2ecf20Sopenharmony_ci			if (EXT_TRANS) {
12418c2ecf20Sopenharmony_ci				printk(KERN_NOTICE
12428c2ecf20Sopenharmony_ci				       "aha152x: unable to verify geometry for disk with >1GB.\n"
12438c2ecf20Sopenharmony_ci				       "         using extended translation.\n");
12448c2ecf20Sopenharmony_ci				info_array[0] = 255;
12458c2ecf20Sopenharmony_ci				info_array[1] = 63;
12468c2ecf20Sopenharmony_ci				info_array[2] = (unsigned long)capacity / (255 * 63);
12478c2ecf20Sopenharmony_ci			} else {
12488c2ecf20Sopenharmony_ci				printk(KERN_NOTICE
12498c2ecf20Sopenharmony_ci				       "aha152x: unable to verify geometry for disk with >1GB.\n"
12508c2ecf20Sopenharmony_ci				       "         Using default translation. Please verify yourself.\n"
12518c2ecf20Sopenharmony_ci				       "         Perhaps you need to enable extended translation in the driver.\n"
12528c2ecf20Sopenharmony_ci				       "         See Documentation/scsi/aha152x.rst for details.\n");
12538c2ecf20Sopenharmony_ci			}
12548c2ecf20Sopenharmony_ci		} else {
12558c2ecf20Sopenharmony_ci			info_array[0] = info[0];
12568c2ecf20Sopenharmony_ci			info_array[1] = info[1];
12578c2ecf20Sopenharmony_ci			info_array[2] = info[2];
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci			if (info[0] == 255 && !EXT_TRANS) {
12608c2ecf20Sopenharmony_ci				printk(KERN_NOTICE
12618c2ecf20Sopenharmony_ci				       "aha152x: current partition table is using extended translation.\n"
12628c2ecf20Sopenharmony_ci				       "         using it also, although it's not explicitly enabled.\n");
12638c2ecf20Sopenharmony_ci			}
12648c2ecf20Sopenharmony_ci		}
12658c2ecf20Sopenharmony_ci	}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	return 0;
12688c2ecf20Sopenharmony_ci}
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci/*
12718c2ecf20Sopenharmony_ci *  Internal done function
12728c2ecf20Sopenharmony_ci *
12738c2ecf20Sopenharmony_ci */
12748c2ecf20Sopenharmony_cistatic void done(struct Scsi_Host *shpnt, int error)
12758c2ecf20Sopenharmony_ci{
12768c2ecf20Sopenharmony_ci	if (CURRENT_SC) {
12778c2ecf20Sopenharmony_ci		if(DONE_SC)
12788c2ecf20Sopenharmony_ci			scmd_printk(KERN_ERR, CURRENT_SC,
12798c2ecf20Sopenharmony_ci				    "there's already a completed command %p "
12808c2ecf20Sopenharmony_ci				    "- will cause abort\n", DONE_SC);
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci		DONE_SC = CURRENT_SC;
12838c2ecf20Sopenharmony_ci		CURRENT_SC = NULL;
12848c2ecf20Sopenharmony_ci		DONE_SC->result = error;
12858c2ecf20Sopenharmony_ci	} else
12868c2ecf20Sopenharmony_ci		printk(KERN_ERR "aha152x: done() called outside of command\n");
12878c2ecf20Sopenharmony_ci}
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_cistatic struct work_struct aha152x_tq;
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci/*
12928c2ecf20Sopenharmony_ci * Run service completions on the card with interrupts enabled.
12938c2ecf20Sopenharmony_ci *
12948c2ecf20Sopenharmony_ci */
12958c2ecf20Sopenharmony_cistatic void run(struct work_struct *work)
12968c2ecf20Sopenharmony_ci{
12978c2ecf20Sopenharmony_ci	struct aha152x_hostdata *hd;
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci	list_for_each_entry(hd, &aha152x_host_list, host_list) {
13008c2ecf20Sopenharmony_ci		struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci		is_complete(shost);
13038c2ecf20Sopenharmony_ci	}
13048c2ecf20Sopenharmony_ci}
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci/*
13078c2ecf20Sopenharmony_ci * Interrupt handler
13088c2ecf20Sopenharmony_ci *
13098c2ecf20Sopenharmony_ci */
13108c2ecf20Sopenharmony_cistatic irqreturn_t intr(int irqno, void *dev_id)
13118c2ecf20Sopenharmony_ci{
13128c2ecf20Sopenharmony_ci	struct Scsi_Host *shpnt = dev_id;
13138c2ecf20Sopenharmony_ci	unsigned long flags;
13148c2ecf20Sopenharmony_ci	unsigned char rev, dmacntrl0;
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	/*
13178c2ecf20Sopenharmony_ci	 * Read a couple of registers that are known to not be all 1's. If
13188c2ecf20Sopenharmony_ci	 * we read all 1's (-1), that means that either:
13198c2ecf20Sopenharmony_ci	 *
13208c2ecf20Sopenharmony_ci	 * a. The host adapter chip has gone bad, and we cannot control it,
13218c2ecf20Sopenharmony_ci	 *	OR
13228c2ecf20Sopenharmony_ci	 * b. The host adapter is a PCMCIA card that has been ejected
13238c2ecf20Sopenharmony_ci	 *
13248c2ecf20Sopenharmony_ci	 * In either case, we cannot do anything with the host adapter at
13258c2ecf20Sopenharmony_ci	 * this point in time. So just ignore the interrupt and return.
13268c2ecf20Sopenharmony_ci	 * In the latter case, the interrupt might actually be meant for
13278c2ecf20Sopenharmony_ci	 * someone else sharing this IRQ, and that driver will handle it.
13288c2ecf20Sopenharmony_ci	 */
13298c2ecf20Sopenharmony_ci	rev = GETPORT(REV);
13308c2ecf20Sopenharmony_ci	dmacntrl0 = GETPORT(DMACNTRL0);
13318c2ecf20Sopenharmony_ci	if ((rev == 0xFF) && (dmacntrl0 == 0xFF))
13328c2ecf20Sopenharmony_ci		return IRQ_NONE;
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	if( TESTLO(DMASTAT, INTSTAT) )
13358c2ecf20Sopenharmony_ci		return IRQ_NONE;
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	/* no more interrupts from the controller, while we're busy.
13388c2ecf20Sopenharmony_ci	   INTEN is restored by the BH handler */
13398c2ecf20Sopenharmony_ci	CLRBITS(DMACNTRL0, INTEN);
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	DO_LOCK(flags);
13428c2ecf20Sopenharmony_ci	if( HOSTDATA(shpnt)->service==0 ) {
13438c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->service=1;
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci		/* Poke the BH handler */
13468c2ecf20Sopenharmony_ci		INIT_WORK(&aha152x_tq, run);
13478c2ecf20Sopenharmony_ci		schedule_work(&aha152x_tq);
13488c2ecf20Sopenharmony_ci	}
13498c2ecf20Sopenharmony_ci	DO_UNLOCK(flags);
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
13528c2ecf20Sopenharmony_ci}
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci/*
13558c2ecf20Sopenharmony_ci * busfree phase
13568c2ecf20Sopenharmony_ci * - handle completition/disconnection/error of current command
13578c2ecf20Sopenharmony_ci * - start selection for next command (if any)
13588c2ecf20Sopenharmony_ci */
13598c2ecf20Sopenharmony_cistatic void busfree_run(struct Scsi_Host *shpnt)
13608c2ecf20Sopenharmony_ci{
13618c2ecf20Sopenharmony_ci	unsigned long flags;
13628c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT)
13638c2ecf20Sopenharmony_ci	int action=0;
13648c2ecf20Sopenharmony_ci#endif
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
13678c2ecf20Sopenharmony_ci	SETPORT(SXFRCTL0, CH1);
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	SETPORT(SSTAT1, CLRBUSFREE);
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci	if(CURRENT_SC) {
13728c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT)
13738c2ecf20Sopenharmony_ci		action++;
13748c2ecf20Sopenharmony_ci#endif
13758c2ecf20Sopenharmony_ci		CURRENT_SC->SCp.phase &= ~syncneg;
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci		if(CURRENT_SC->SCp.phase & completed) {
13788c2ecf20Sopenharmony_ci			/* target sent COMMAND COMPLETE */
13798c2ecf20Sopenharmony_ci			done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16));
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci		} else if(CURRENT_SC->SCp.phase & aborted) {
13828c2ecf20Sopenharmony_ci			done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_ABORT << 16));
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci		} else if(CURRENT_SC->SCp.phase & resetted) {
13858c2ecf20Sopenharmony_ci			done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_RESET << 16));
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci		} else if(CURRENT_SC->SCp.phase & disconnected) {
13888c2ecf20Sopenharmony_ci			/* target sent DISCONNECT */
13898c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT)
13908c2ecf20Sopenharmony_ci			HOSTDATA(shpnt)->disconnections++;
13918c2ecf20Sopenharmony_ci#endif
13928c2ecf20Sopenharmony_ci			append_SC(&DISCONNECTED_SC, CURRENT_SC);
13938c2ecf20Sopenharmony_ci			CURRENT_SC->SCp.phase |= 1 << 16;
13948c2ecf20Sopenharmony_ci			CURRENT_SC = NULL;
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci		} else {
13978c2ecf20Sopenharmony_ci			done(shpnt, DID_ERROR << 16);
13988c2ecf20Sopenharmony_ci		}
13998c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT)
14008c2ecf20Sopenharmony_ci	} else {
14018c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_old_command++;
14028c2ecf20Sopenharmony_ci#endif
14038c2ecf20Sopenharmony_ci	}
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	DO_LOCK(flags);
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	if(DONE_SC) {
14088c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT)
14098c2ecf20Sopenharmony_ci		action++;
14108c2ecf20Sopenharmony_ci#endif
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci		if(DONE_SC->SCp.phase & check_condition) {
14138c2ecf20Sopenharmony_ci			struct scsi_cmnd *cmd = HOSTDATA(shpnt)->done_SC;
14148c2ecf20Sopenharmony_ci			struct aha152x_scdata *sc = SCDATA(cmd);
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci			scsi_eh_restore_cmnd(cmd, &sc->ses);
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci			cmd->SCp.Status = SAM_STAT_CHECK_CONDITION;
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci			HOSTDATA(shpnt)->commands--;
14218c2ecf20Sopenharmony_ci			if (!HOSTDATA(shpnt)->commands)
14228c2ecf20Sopenharmony_ci				SETPORT(PORTA, 0);	/* turn led off */
14238c2ecf20Sopenharmony_ci		} else if(DONE_SC->SCp.Status==SAM_STAT_CHECK_CONDITION) {
14248c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT)
14258c2ecf20Sopenharmony_ci			HOSTDATA(shpnt)->busfree_with_check_condition++;
14268c2ecf20Sopenharmony_ci#endif
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci			if(!(DONE_SC->SCp.phase & not_issued)) {
14298c2ecf20Sopenharmony_ci				struct aha152x_scdata *sc;
14308c2ecf20Sopenharmony_ci				struct scsi_cmnd *ptr = DONE_SC;
14318c2ecf20Sopenharmony_ci				DONE_SC=NULL;
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci				sc = SCDATA(ptr);
14348c2ecf20Sopenharmony_ci				/* It was allocated in aha152x_internal_queue? */
14358c2ecf20Sopenharmony_ci				BUG_ON(!sc);
14368c2ecf20Sopenharmony_ci				scsi_eh_prep_cmnd(ptr, &sc->ses, NULL, 0, ~0);
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci				DO_UNLOCK(flags);
14398c2ecf20Sopenharmony_ci				aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done);
14408c2ecf20Sopenharmony_ci				DO_LOCK(flags);
14418c2ecf20Sopenharmony_ci			}
14428c2ecf20Sopenharmony_ci		}
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci		if(DONE_SC && DONE_SC->scsi_done) {
14458c2ecf20Sopenharmony_ci			struct scsi_cmnd *ptr = DONE_SC;
14468c2ecf20Sopenharmony_ci			DONE_SC=NULL;
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci			/* turn led off, when no commands are in the driver */
14498c2ecf20Sopenharmony_ci			HOSTDATA(shpnt)->commands--;
14508c2ecf20Sopenharmony_ci			if (!HOSTDATA(shpnt)->commands)
14518c2ecf20Sopenharmony_ci				SETPORT(PORTA, 0);	/* turn led off */
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci			if(ptr->scsi_done != reset_done) {
14548c2ecf20Sopenharmony_ci				kfree(ptr->host_scribble);
14558c2ecf20Sopenharmony_ci				ptr->host_scribble=NULL;
14568c2ecf20Sopenharmony_ci			}
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci			DO_UNLOCK(flags);
14598c2ecf20Sopenharmony_ci			ptr->scsi_done(ptr);
14608c2ecf20Sopenharmony_ci			DO_LOCK(flags);
14618c2ecf20Sopenharmony_ci		}
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci		DONE_SC=NULL;
14648c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT)
14658c2ecf20Sopenharmony_ci	} else {
14668c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_done_command++;
14678c2ecf20Sopenharmony_ci#endif
14688c2ecf20Sopenharmony_ci	}
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	if(ISSUE_SC)
14718c2ecf20Sopenharmony_ci		CURRENT_SC = remove_first_SC(&ISSUE_SC);
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	DO_UNLOCK(flags);
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	if(CURRENT_SC) {
14768c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT)
14778c2ecf20Sopenharmony_ci		action++;
14788c2ecf20Sopenharmony_ci#endif
14798c2ecf20Sopenharmony_ci		CURRENT_SC->SCp.phase |= selecting;
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci		/* clear selection timeout */
14828c2ecf20Sopenharmony_ci		SETPORT(SSTAT1, SELTO);
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci		SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->device->id);
14858c2ecf20Sopenharmony_ci		SETPORT(SXFRCTL1, (PARITY ? ENSPCHK : 0 ) | ENSTIMER);
14868c2ecf20Sopenharmony_ci		SETPORT(SCSISEQ, ENSELO | ENAUTOATNO | (DISCONNECTED_SC ? ENRESELI : 0));
14878c2ecf20Sopenharmony_ci	} else {
14888c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT)
14898c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_new_command++;
14908c2ecf20Sopenharmony_ci#endif
14918c2ecf20Sopenharmony_ci		SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
14928c2ecf20Sopenharmony_ci	}
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT)
14958c2ecf20Sopenharmony_ci	if(!action)
14968c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_any_action++;
14978c2ecf20Sopenharmony_ci#endif
14988c2ecf20Sopenharmony_ci}
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_ci/*
15018c2ecf20Sopenharmony_ci * Selection done (OUT)
15028c2ecf20Sopenharmony_ci * - queue IDENTIFY message and SDTR to selected target for message out
15038c2ecf20Sopenharmony_ci *   (ATN asserted automagically via ENAUTOATNO in busfree())
15048c2ecf20Sopenharmony_ci */
15058c2ecf20Sopenharmony_cistatic void seldo_run(struct Scsi_Host *shpnt)
15068c2ecf20Sopenharmony_ci{
15078c2ecf20Sopenharmony_ci	SETPORT(SCSISIG, 0);
15088c2ecf20Sopenharmony_ci	SETPORT(SSTAT1, CLRBUSFREE);
15098c2ecf20Sopenharmony_ci	SETPORT(SSTAT1, CLRPHASECHG);
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci	CURRENT_SC->SCp.phase &= ~(selecting|not_issued);
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	SETPORT(SCSISEQ, 0);
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci	if (TESTLO(SSTAT0, SELDO)) {
15168c2ecf20Sopenharmony_ci		scmd_printk(KERN_ERR, CURRENT_SC,
15178c2ecf20Sopenharmony_ci			    "aha152x: passing bus free condition\n");
15188c2ecf20Sopenharmony_ci		done(shpnt, DID_NO_CONNECT << 16);
15198c2ecf20Sopenharmony_ci		return;
15208c2ecf20Sopenharmony_ci	}
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	SETPORT(SSTAT0, CLRSELDO);
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci	ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci	if (CURRENT_SC->SCp.phase & aborting) {
15278c2ecf20Sopenharmony_ci		ADDMSGO(ABORT);
15288c2ecf20Sopenharmony_ci	} else if (CURRENT_SC->SCp.phase & resetting) {
15298c2ecf20Sopenharmony_ci		ADDMSGO(BUS_DEVICE_RESET);
15308c2ecf20Sopenharmony_ci	} else if (SYNCNEG==0 && SYNCHRONOUS) {
15318c2ecf20Sopenharmony_ci		CURRENT_SC->SCp.phase |= syncneg;
15328c2ecf20Sopenharmony_ci		MSGOLEN += spi_populate_sync_msg(&MSGO(MSGOLEN), 50, 8);
15338c2ecf20Sopenharmony_ci		SYNCNEG=1;		/* negotiation in progress */
15348c2ecf20Sopenharmony_ci	}
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci	SETRATE(SYNCRATE);
15378c2ecf20Sopenharmony_ci}
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci/*
15408c2ecf20Sopenharmony_ci * Selection timeout
15418c2ecf20Sopenharmony_ci * - return command to mid-level with failure cause
15428c2ecf20Sopenharmony_ci *
15438c2ecf20Sopenharmony_ci */
15448c2ecf20Sopenharmony_cistatic void selto_run(struct Scsi_Host *shpnt)
15458c2ecf20Sopenharmony_ci{
15468c2ecf20Sopenharmony_ci	SETPORT(SCSISEQ, 0);
15478c2ecf20Sopenharmony_ci	SETPORT(SSTAT1, CLRSELTIMO);
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci	if (!CURRENT_SC)
15508c2ecf20Sopenharmony_ci		return;
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	CURRENT_SC->SCp.phase &= ~selecting;
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_ci	if (CURRENT_SC->SCp.phase & aborted)
15558c2ecf20Sopenharmony_ci		done(shpnt, DID_ABORT << 16);
15568c2ecf20Sopenharmony_ci	else if (TESTLO(SSTAT0, SELINGO))
15578c2ecf20Sopenharmony_ci		done(shpnt, DID_BUS_BUSY << 16);
15588c2ecf20Sopenharmony_ci	else
15598c2ecf20Sopenharmony_ci		/* ARBITRATION won, but SELECTION failed */
15608c2ecf20Sopenharmony_ci		done(shpnt, DID_NO_CONNECT << 16);
15618c2ecf20Sopenharmony_ci}
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci/*
15648c2ecf20Sopenharmony_ci * Selection in done
15658c2ecf20Sopenharmony_ci * - put current command back to issue queue
15668c2ecf20Sopenharmony_ci *   (reconnection of a disconnected nexus instead
15678c2ecf20Sopenharmony_ci *    of successful selection out)
15688c2ecf20Sopenharmony_ci *
15698c2ecf20Sopenharmony_ci */
15708c2ecf20Sopenharmony_cistatic void seldi_run(struct Scsi_Host *shpnt)
15718c2ecf20Sopenharmony_ci{
15728c2ecf20Sopenharmony_ci	int selid;
15738c2ecf20Sopenharmony_ci	int target;
15748c2ecf20Sopenharmony_ci	unsigned long flags;
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci	SETPORT(SCSISIG, 0);
15778c2ecf20Sopenharmony_ci	SETPORT(SSTAT0, CLRSELDI);
15788c2ecf20Sopenharmony_ci	SETPORT(SSTAT1, CLRBUSFREE);
15798c2ecf20Sopenharmony_ci	SETPORT(SSTAT1, CLRPHASECHG);
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	if(CURRENT_SC) {
15828c2ecf20Sopenharmony_ci		if(!(CURRENT_SC->SCp.phase & not_issued))
15838c2ecf20Sopenharmony_ci			scmd_printk(KERN_ERR, CURRENT_SC,
15848c2ecf20Sopenharmony_ci				    "command should not have been issued yet\n");
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci		DO_LOCK(flags);
15878c2ecf20Sopenharmony_ci		append_SC(&ISSUE_SC, CURRENT_SC);
15888c2ecf20Sopenharmony_ci		DO_UNLOCK(flags);
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci		CURRENT_SC = NULL;
15918c2ecf20Sopenharmony_ci	}
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci	if (!DISCONNECTED_SC)
15948c2ecf20Sopenharmony_ci		return;
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci	RECONN_TARGET=-1;
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci	selid = GETPORT(SELID) & ~(1 << shpnt->this_id);
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci	if (selid==0) {
16018c2ecf20Sopenharmony_ci		shost_printk(KERN_INFO, shpnt,
16028c2ecf20Sopenharmony_ci			     "target id unknown (%02x)\n", selid);
16038c2ecf20Sopenharmony_ci		return;
16048c2ecf20Sopenharmony_ci	}
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	for(target=7; !(selid & (1 << target)); target--)
16078c2ecf20Sopenharmony_ci		;
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	if(selid & ~(1 << target)) {
16108c2ecf20Sopenharmony_ci		shost_printk(KERN_INFO, shpnt,
16118c2ecf20Sopenharmony_ci			     "multiple targets reconnected (%02x)\n", selid);
16128c2ecf20Sopenharmony_ci	}
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	SETPORT(SCSIID, (shpnt->this_id << OID_) | target);
16168c2ecf20Sopenharmony_ci	SETPORT(SCSISEQ, 0);
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_ci	SETRATE(HOSTDATA(shpnt)->syncrate[target]);
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	RECONN_TARGET=target;
16218c2ecf20Sopenharmony_ci}
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci/*
16248c2ecf20Sopenharmony_ci * message in phase
16258c2ecf20Sopenharmony_ci * - handle initial message after reconnection to identify
16268c2ecf20Sopenharmony_ci *   reconnecting nexus
16278c2ecf20Sopenharmony_ci * - queue command on DISCONNECTED_SC on DISCONNECT message
16288c2ecf20Sopenharmony_ci * - set completed flag on COMMAND COMPLETE
16298c2ecf20Sopenharmony_ci *   (other completition code moved to busfree_run)
16308c2ecf20Sopenharmony_ci * - handle response to SDTR
16318c2ecf20Sopenharmony_ci * - clear synchronous transfer agreements on BUS RESET
16328c2ecf20Sopenharmony_ci *
16338c2ecf20Sopenharmony_ci * FIXME: what about SAVE POINTERS, RESTORE POINTERS?
16348c2ecf20Sopenharmony_ci *
16358c2ecf20Sopenharmony_ci */
16368c2ecf20Sopenharmony_cistatic void msgi_run(struct Scsi_Host *shpnt)
16378c2ecf20Sopenharmony_ci{
16388c2ecf20Sopenharmony_ci	for(;;) {
16398c2ecf20Sopenharmony_ci		int sstat1 = GETPORT(SSTAT1);
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci		if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT))
16428c2ecf20Sopenharmony_ci			return;
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci		if (TESTLO(SSTAT0, SPIORDY))
16458c2ecf20Sopenharmony_ci			return;
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci		ADDMSGI(GETPORT(SCSIDAT));
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci		if(!CURRENT_SC) {
16508c2ecf20Sopenharmony_ci			if(LASTSTATE!=seldi) {
16518c2ecf20Sopenharmony_ci				shost_printk(KERN_ERR, shpnt,
16528c2ecf20Sopenharmony_ci					     "message in w/o current command"
16538c2ecf20Sopenharmony_ci					     " not after reselection\n");
16548c2ecf20Sopenharmony_ci			}
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci			/*
16578c2ecf20Sopenharmony_ci			 * Handle reselection
16588c2ecf20Sopenharmony_ci			 */
16598c2ecf20Sopenharmony_ci			if(!(MSGI(0) & IDENTIFY_BASE)) {
16608c2ecf20Sopenharmony_ci				shost_printk(KERN_ERR, shpnt,
16618c2ecf20Sopenharmony_ci					     "target didn't identify after reselection\n");
16628c2ecf20Sopenharmony_ci				continue;
16638c2ecf20Sopenharmony_ci			}
16648c2ecf20Sopenharmony_ci
16658c2ecf20Sopenharmony_ci			CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f);
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci			if (!CURRENT_SC) {
16688c2ecf20Sopenharmony_ci				show_queues(shpnt);
16698c2ecf20Sopenharmony_ci				shost_printk(KERN_ERR, shpnt,
16708c2ecf20Sopenharmony_ci					     "no disconnected command"
16718c2ecf20Sopenharmony_ci					     " for target %d/%d\n",
16728c2ecf20Sopenharmony_ci					     RECONN_TARGET, MSGI(0) & 0x3f);
16738c2ecf20Sopenharmony_ci				continue;
16748c2ecf20Sopenharmony_ci			}
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci			CURRENT_SC->SCp.Message = MSGI(0);
16778c2ecf20Sopenharmony_ci			CURRENT_SC->SCp.phase &= ~disconnected;
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci			MSGILEN=0;
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci			/* next message if any */
16828c2ecf20Sopenharmony_ci			continue;
16838c2ecf20Sopenharmony_ci		}
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci		CURRENT_SC->SCp.Message = MSGI(0);
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci		switch (MSGI(0)) {
16888c2ecf20Sopenharmony_ci		case DISCONNECT:
16898c2ecf20Sopenharmony_ci			if (!RECONNECT)
16908c2ecf20Sopenharmony_ci				scmd_printk(KERN_WARNING, CURRENT_SC,
16918c2ecf20Sopenharmony_ci					    "target was not allowed to disconnect\n");
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci			CURRENT_SC->SCp.phase |= disconnected;
16948c2ecf20Sopenharmony_ci			break;
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci		case COMMAND_COMPLETE:
16978c2ecf20Sopenharmony_ci			CURRENT_SC->SCp.phase |= completed;
16988c2ecf20Sopenharmony_ci			break;
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci		case MESSAGE_REJECT:
17018c2ecf20Sopenharmony_ci			if (SYNCNEG==1) {
17028c2ecf20Sopenharmony_ci				scmd_printk(KERN_INFO, CURRENT_SC,
17038c2ecf20Sopenharmony_ci					    "Synchronous Data Transfer Request"
17048c2ecf20Sopenharmony_ci					    " was rejected\n");
17058c2ecf20Sopenharmony_ci				SYNCNEG=2;	/* negotiation completed */
17068c2ecf20Sopenharmony_ci			} else
17078c2ecf20Sopenharmony_ci				scmd_printk(KERN_INFO, CURRENT_SC,
17088c2ecf20Sopenharmony_ci					    "inbound message (MESSAGE REJECT)\n");
17098c2ecf20Sopenharmony_ci			break;
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci		case SAVE_POINTERS:
17128c2ecf20Sopenharmony_ci			break;
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci		case RESTORE_POINTERS:
17158c2ecf20Sopenharmony_ci			break;
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci		case EXTENDED_MESSAGE:
17188c2ecf20Sopenharmony_ci			if(MSGILEN<2 || MSGILEN<MSGI(1)+2) {
17198c2ecf20Sopenharmony_ci				/* not yet completed */
17208c2ecf20Sopenharmony_ci				continue;
17218c2ecf20Sopenharmony_ci			}
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci			switch (MSGI(2)) {
17248c2ecf20Sopenharmony_ci			case EXTENDED_SDTR:
17258c2ecf20Sopenharmony_ci				{
17268c2ecf20Sopenharmony_ci					long ticks;
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci					if (MSGI(1) != 3) {
17298c2ecf20Sopenharmony_ci						scmd_printk(KERN_ERR, CURRENT_SC,
17308c2ecf20Sopenharmony_ci							    "SDTR message length!=3\n");
17318c2ecf20Sopenharmony_ci						break;
17328c2ecf20Sopenharmony_ci					}
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci					if (!HOSTDATA(shpnt)->synchronous)
17358c2ecf20Sopenharmony_ci						break;
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci					printk(INFO_LEAD, CMDINFO(CURRENT_SC));
17388c2ecf20Sopenharmony_ci					spi_print_msg(&MSGI(0));
17398c2ecf20Sopenharmony_ci					printk("\n");
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci					ticks = (MSGI(3) * 4 + 49) / 50;
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci					if (syncneg) {
17448c2ecf20Sopenharmony_ci						/* negotiation in progress */
17458c2ecf20Sopenharmony_ci						if (ticks > 9 || MSGI(4) < 1 || MSGI(4) > 8) {
17468c2ecf20Sopenharmony_ci							ADDMSGO(MESSAGE_REJECT);
17478c2ecf20Sopenharmony_ci							scmd_printk(KERN_INFO,
17488c2ecf20Sopenharmony_ci								    CURRENT_SC,
17498c2ecf20Sopenharmony_ci								    "received Synchronous Data Transfer Request invalid - rejected\n");
17508c2ecf20Sopenharmony_ci							break;
17518c2ecf20Sopenharmony_ci						}
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci						SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
17548c2ecf20Sopenharmony_ci					} else if (ticks <= 9 && MSGI(4) >= 1) {
17558c2ecf20Sopenharmony_ci						ADDMSGO(EXTENDED_MESSAGE);
17568c2ecf20Sopenharmony_ci						ADDMSGO(3);
17578c2ecf20Sopenharmony_ci						ADDMSGO(EXTENDED_SDTR);
17588c2ecf20Sopenharmony_ci						if (ticks < 4) {
17598c2ecf20Sopenharmony_ci							ticks = 4;
17608c2ecf20Sopenharmony_ci							ADDMSGO(50);
17618c2ecf20Sopenharmony_ci						} else
17628c2ecf20Sopenharmony_ci							ADDMSGO(MSGI(3));
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci						if (MSGI(4) > 8)
17658c2ecf20Sopenharmony_ci							MSGI(4) = 8;
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci						ADDMSGO(MSGI(4));
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_ci						SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
17708c2ecf20Sopenharmony_ci					} else {
17718c2ecf20Sopenharmony_ci						/* requested SDTR is too slow, do it asynchronously */
17728c2ecf20Sopenharmony_ci						scmd_printk(KERN_INFO,
17738c2ecf20Sopenharmony_ci							    CURRENT_SC,
17748c2ecf20Sopenharmony_ci							    "Synchronous Data Transfer Request too slow - Rejecting\n");
17758c2ecf20Sopenharmony_ci						ADDMSGO(MESSAGE_REJECT);
17768c2ecf20Sopenharmony_ci					}
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci					/* negotiation completed */
17798c2ecf20Sopenharmony_ci					SYNCNEG=2;
17808c2ecf20Sopenharmony_ci					SETRATE(SYNCRATE);
17818c2ecf20Sopenharmony_ci				}
17828c2ecf20Sopenharmony_ci				break;
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci			case BUS_DEVICE_RESET:
17858c2ecf20Sopenharmony_ci				{
17868c2ecf20Sopenharmony_ci					int i;
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci					for(i=0; i<8; i++) {
17898c2ecf20Sopenharmony_ci						HOSTDATA(shpnt)->syncrate[i]=0;
17908c2ecf20Sopenharmony_ci						HOSTDATA(shpnt)->syncneg[i]=0;
17918c2ecf20Sopenharmony_ci					}
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci				}
17948c2ecf20Sopenharmony_ci				break;
17958c2ecf20Sopenharmony_ci
17968c2ecf20Sopenharmony_ci			case EXTENDED_MODIFY_DATA_POINTER:
17978c2ecf20Sopenharmony_ci			case EXTENDED_EXTENDED_IDENTIFY:
17988c2ecf20Sopenharmony_ci			case EXTENDED_WDTR:
17998c2ecf20Sopenharmony_ci			default:
18008c2ecf20Sopenharmony_ci				ADDMSGO(MESSAGE_REJECT);
18018c2ecf20Sopenharmony_ci				break;
18028c2ecf20Sopenharmony_ci			}
18038c2ecf20Sopenharmony_ci			break;
18048c2ecf20Sopenharmony_ci		}
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci		MSGILEN=0;
18078c2ecf20Sopenharmony_ci	}
18088c2ecf20Sopenharmony_ci}
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_cistatic void msgi_end(struct Scsi_Host *shpnt)
18118c2ecf20Sopenharmony_ci{
18128c2ecf20Sopenharmony_ci	if(MSGILEN>0)
18138c2ecf20Sopenharmony_ci		scmd_printk(KERN_WARNING, CURRENT_SC,
18148c2ecf20Sopenharmony_ci			    "target left before message completed (%d)\n",
18158c2ecf20Sopenharmony_ci			    MSGILEN);
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci	if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE))
18188c2ecf20Sopenharmony_ci		SETPORT(SCSISIG, P_MSGI | SIG_ATNO);
18198c2ecf20Sopenharmony_ci}
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci/*
18228c2ecf20Sopenharmony_ci * message out phase
18238c2ecf20Sopenharmony_ci *
18248c2ecf20Sopenharmony_ci */
18258c2ecf20Sopenharmony_cistatic void msgo_init(struct Scsi_Host *shpnt)
18268c2ecf20Sopenharmony_ci{
18278c2ecf20Sopenharmony_ci	if(MSGOLEN==0) {
18288c2ecf20Sopenharmony_ci		if((CURRENT_SC->SCp.phase & syncneg) && SYNCNEG==2 && SYNCRATE==0) {
18298c2ecf20Sopenharmony_ci			ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
18308c2ecf20Sopenharmony_ci		} else {
18318c2ecf20Sopenharmony_ci			scmd_printk(KERN_INFO, CURRENT_SC,
18328c2ecf20Sopenharmony_ci				    "unexpected MESSAGE OUT phase; rejecting\n");
18338c2ecf20Sopenharmony_ci			ADDMSGO(MESSAGE_REJECT);
18348c2ecf20Sopenharmony_ci		}
18358c2ecf20Sopenharmony_ci	}
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci}
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci/*
18408c2ecf20Sopenharmony_ci * message out phase
18418c2ecf20Sopenharmony_ci *
18428c2ecf20Sopenharmony_ci */
18438c2ecf20Sopenharmony_cistatic void msgo_run(struct Scsi_Host *shpnt)
18448c2ecf20Sopenharmony_ci{
18458c2ecf20Sopenharmony_ci	while(MSGO_I<MSGOLEN) {
18468c2ecf20Sopenharmony_ci		if (TESTLO(SSTAT0, SPIORDY))
18478c2ecf20Sopenharmony_ci			return;
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_ci		if (MSGO_I==MSGOLEN-1) {
18508c2ecf20Sopenharmony_ci			/* Leave MESSAGE OUT after transfer */
18518c2ecf20Sopenharmony_ci			SETPORT(SSTAT1, CLRATNO);
18528c2ecf20Sopenharmony_ci		}
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci		if (MSGO(MSGO_I) & IDENTIFY_BASE)
18568c2ecf20Sopenharmony_ci			CURRENT_SC->SCp.phase |= identified;
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci		if (MSGO(MSGO_I)==ABORT)
18598c2ecf20Sopenharmony_ci			CURRENT_SC->SCp.phase |= aborted;
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci		if (MSGO(MSGO_I)==BUS_DEVICE_RESET)
18628c2ecf20Sopenharmony_ci			CURRENT_SC->SCp.phase |= resetted;
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_ci		SETPORT(SCSIDAT, MSGO(MSGO_I++));
18658c2ecf20Sopenharmony_ci	}
18668c2ecf20Sopenharmony_ci}
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_cistatic void msgo_end(struct Scsi_Host *shpnt)
18698c2ecf20Sopenharmony_ci{
18708c2ecf20Sopenharmony_ci	if(MSGO_I<MSGOLEN) {
18718c2ecf20Sopenharmony_ci		scmd_printk(KERN_ERR, CURRENT_SC,
18728c2ecf20Sopenharmony_ci			    "message sent incompletely (%d/%d)\n",
18738c2ecf20Sopenharmony_ci			    MSGO_I, MSGOLEN);
18748c2ecf20Sopenharmony_ci		if(SYNCNEG==1) {
18758c2ecf20Sopenharmony_ci			scmd_printk(KERN_INFO, CURRENT_SC,
18768c2ecf20Sopenharmony_ci				    "Synchronous Data Transfer Request was rejected\n");
18778c2ecf20Sopenharmony_ci			SYNCNEG=2;
18788c2ecf20Sopenharmony_ci		}
18798c2ecf20Sopenharmony_ci	}
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci	MSGO_I  = 0;
18828c2ecf20Sopenharmony_ci	MSGOLEN = 0;
18838c2ecf20Sopenharmony_ci}
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci/*
18868c2ecf20Sopenharmony_ci * command phase
18878c2ecf20Sopenharmony_ci *
18888c2ecf20Sopenharmony_ci */
18898c2ecf20Sopenharmony_cistatic void cmd_init(struct Scsi_Host *shpnt)
18908c2ecf20Sopenharmony_ci{
18918c2ecf20Sopenharmony_ci	if (CURRENT_SC->SCp.sent_command) {
18928c2ecf20Sopenharmony_ci		scmd_printk(KERN_ERR, CURRENT_SC,
18938c2ecf20Sopenharmony_ci			    "command already sent\n");
18948c2ecf20Sopenharmony_ci		done(shpnt, DID_ERROR << 16);
18958c2ecf20Sopenharmony_ci		return;
18968c2ecf20Sopenharmony_ci	}
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	CMD_I=0;
18998c2ecf20Sopenharmony_ci}
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_ci/*
19028c2ecf20Sopenharmony_ci * command phase
19038c2ecf20Sopenharmony_ci *
19048c2ecf20Sopenharmony_ci */
19058c2ecf20Sopenharmony_cistatic void cmd_run(struct Scsi_Host *shpnt)
19068c2ecf20Sopenharmony_ci{
19078c2ecf20Sopenharmony_ci	while(CMD_I<CURRENT_SC->cmd_len) {
19088c2ecf20Sopenharmony_ci		if (TESTLO(SSTAT0, SPIORDY))
19098c2ecf20Sopenharmony_ci			return;
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci		SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]);
19128c2ecf20Sopenharmony_ci	}
19138c2ecf20Sopenharmony_ci}
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_cistatic void cmd_end(struct Scsi_Host *shpnt)
19168c2ecf20Sopenharmony_ci{
19178c2ecf20Sopenharmony_ci	if(CMD_I<CURRENT_SC->cmd_len)
19188c2ecf20Sopenharmony_ci		scmd_printk(KERN_ERR, CURRENT_SC,
19198c2ecf20Sopenharmony_ci			    "command sent incompletely (%d/%d)\n",
19208c2ecf20Sopenharmony_ci			    CMD_I, CURRENT_SC->cmd_len);
19218c2ecf20Sopenharmony_ci	else
19228c2ecf20Sopenharmony_ci		CURRENT_SC->SCp.sent_command++;
19238c2ecf20Sopenharmony_ci}
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci/*
19268c2ecf20Sopenharmony_ci * status phase
19278c2ecf20Sopenharmony_ci *
19288c2ecf20Sopenharmony_ci */
19298c2ecf20Sopenharmony_cistatic void status_run(struct Scsi_Host *shpnt)
19308c2ecf20Sopenharmony_ci{
19318c2ecf20Sopenharmony_ci	if (TESTLO(SSTAT0, SPIORDY))
19328c2ecf20Sopenharmony_ci		return;
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci	CURRENT_SC->SCp.Status = GETPORT(SCSIDAT);
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci}
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci/*
19398c2ecf20Sopenharmony_ci * data in phase
19408c2ecf20Sopenharmony_ci *
19418c2ecf20Sopenharmony_ci */
19428c2ecf20Sopenharmony_cistatic void datai_init(struct Scsi_Host *shpnt)
19438c2ecf20Sopenharmony_ci{
19448c2ecf20Sopenharmony_ci	SETPORT(DMACNTRL0, RSTFIFO);
19458c2ecf20Sopenharmony_ci	SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
19468c2ecf20Sopenharmony_ci
19478c2ecf20Sopenharmony_ci	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
19488c2ecf20Sopenharmony_ci	SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci	SETPORT(SIMODE0, 0);
19518c2ecf20Sopenharmony_ci	SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE);
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci	DATA_LEN=0;
19548c2ecf20Sopenharmony_ci}
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_cistatic void datai_run(struct Scsi_Host *shpnt)
19578c2ecf20Sopenharmony_ci{
19588c2ecf20Sopenharmony_ci	unsigned long the_time;
19598c2ecf20Sopenharmony_ci	int fifodata, data_count;
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci	/*
19628c2ecf20Sopenharmony_ci	 * loop while the phase persists or the fifos are not empty
19638c2ecf20Sopenharmony_ci	 *
19648c2ecf20Sopenharmony_ci	 */
19658c2ecf20Sopenharmony_ci	while(TESTLO(DMASTAT, INTSTAT) || TESTLO(DMASTAT, DFIFOEMP) || TESTLO(SSTAT2, SEMPTY)) {
19668c2ecf20Sopenharmony_ci		/* FIXME: maybe this should be done by setting up
19678c2ecf20Sopenharmony_ci		 * STCNT to trigger ENSWRAP interrupt, instead of
19688c2ecf20Sopenharmony_ci		 * polling for DFIFOFULL
19698c2ecf20Sopenharmony_ci		 */
19708c2ecf20Sopenharmony_ci		the_time=jiffies + 100*HZ;
19718c2ecf20Sopenharmony_ci		while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time))
19728c2ecf20Sopenharmony_ci			barrier();
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci		if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) {
19758c2ecf20Sopenharmony_ci			scmd_printk(KERN_ERR, CURRENT_SC, "datai timeout\n");
19768c2ecf20Sopenharmony_ci			break;
19778c2ecf20Sopenharmony_ci		}
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci		if(TESTHI(DMASTAT, DFIFOFULL)) {
19808c2ecf20Sopenharmony_ci			fifodata = 128;
19818c2ecf20Sopenharmony_ci		} else {
19828c2ecf20Sopenharmony_ci			the_time=jiffies + 100*HZ;
19838c2ecf20Sopenharmony_ci			while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time))
19848c2ecf20Sopenharmony_ci				barrier();
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_ci			if(TESTLO(SSTAT2, SEMPTY)) {
19878c2ecf20Sopenharmony_ci				scmd_printk(KERN_ERR, CURRENT_SC,
19888c2ecf20Sopenharmony_ci					    "datai sempty timeout");
19898c2ecf20Sopenharmony_ci				break;
19908c2ecf20Sopenharmony_ci			}
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_ci			fifodata = GETPORT(FIFOSTAT);
19938c2ecf20Sopenharmony_ci		}
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci		if(CURRENT_SC->SCp.this_residual>0) {
19968c2ecf20Sopenharmony_ci			while(fifodata>0 && CURRENT_SC->SCp.this_residual>0) {
19978c2ecf20Sopenharmony_ci				data_count = fifodata > CURRENT_SC->SCp.this_residual ?
19988c2ecf20Sopenharmony_ci						CURRENT_SC->SCp.this_residual :
19998c2ecf20Sopenharmony_ci						fifodata;
20008c2ecf20Sopenharmony_ci				fifodata -= data_count;
20018c2ecf20Sopenharmony_ci
20028c2ecf20Sopenharmony_ci				if (data_count & 1) {
20038c2ecf20Sopenharmony_ci					SETPORT(DMACNTRL0, ENDMA|_8BIT);
20048c2ecf20Sopenharmony_ci					*CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
20058c2ecf20Sopenharmony_ci					CURRENT_SC->SCp.this_residual--;
20068c2ecf20Sopenharmony_ci					DATA_LEN++;
20078c2ecf20Sopenharmony_ci					SETPORT(DMACNTRL0, ENDMA);
20088c2ecf20Sopenharmony_ci				}
20098c2ecf20Sopenharmony_ci
20108c2ecf20Sopenharmony_ci				if (data_count > 1) {
20118c2ecf20Sopenharmony_ci					data_count >>= 1;
20128c2ecf20Sopenharmony_ci					insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
20138c2ecf20Sopenharmony_ci					CURRENT_SC->SCp.ptr += 2 * data_count;
20148c2ecf20Sopenharmony_ci					CURRENT_SC->SCp.this_residual -= 2 * data_count;
20158c2ecf20Sopenharmony_ci					DATA_LEN += 2 * data_count;
20168c2ecf20Sopenharmony_ci				}
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_ci				if (CURRENT_SC->SCp.this_residual == 0 &&
20198c2ecf20Sopenharmony_ci				    !sg_is_last(CURRENT_SC->SCp.buffer)) {
20208c2ecf20Sopenharmony_ci					/* advance to next buffer */
20218c2ecf20Sopenharmony_ci					CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer);
20228c2ecf20Sopenharmony_ci					CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer);
20238c2ecf20Sopenharmony_ci					CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
20248c2ecf20Sopenharmony_ci				}
20258c2ecf20Sopenharmony_ci			}
20268c2ecf20Sopenharmony_ci		} else if (fifodata > 0) {
20278c2ecf20Sopenharmony_ci			scmd_printk(KERN_ERR, CURRENT_SC,
20288c2ecf20Sopenharmony_ci				    "no buffers left for %d(%d) bytes"
20298c2ecf20Sopenharmony_ci				    " (data overrun!?)\n",
20308c2ecf20Sopenharmony_ci				    fifodata, GETPORT(FIFOSTAT));
20318c2ecf20Sopenharmony_ci			SETPORT(DMACNTRL0, ENDMA|_8BIT);
20328c2ecf20Sopenharmony_ci			while(fifodata>0) {
20338c2ecf20Sopenharmony_ci				GETPORT(DATAPORT);
20348c2ecf20Sopenharmony_ci				fifodata--;
20358c2ecf20Sopenharmony_ci				DATA_LEN++;
20368c2ecf20Sopenharmony_ci			}
20378c2ecf20Sopenharmony_ci			SETPORT(DMACNTRL0, ENDMA|_8BIT);
20388c2ecf20Sopenharmony_ci		}
20398c2ecf20Sopenharmony_ci	}
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_ci	if(TESTLO(DMASTAT, INTSTAT) ||
20428c2ecf20Sopenharmony_ci	   TESTLO(DMASTAT, DFIFOEMP) ||
20438c2ecf20Sopenharmony_ci	   TESTLO(SSTAT2, SEMPTY) ||
20448c2ecf20Sopenharmony_ci	   GETPORT(FIFOSTAT)>0) {
20458c2ecf20Sopenharmony_ci		/*
20468c2ecf20Sopenharmony_ci		 * something went wrong, if there's something left in the fifos
20478c2ecf20Sopenharmony_ci		 * or the phase didn't change
20488c2ecf20Sopenharmony_ci		 */
20498c2ecf20Sopenharmony_ci		scmd_printk(KERN_ERR, CURRENT_SC,
20508c2ecf20Sopenharmony_ci			    "fifos should be empty and phase should have changed\n");
20518c2ecf20Sopenharmony_ci	}
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_ci	if(DATA_LEN!=GETSTCNT()) {
20548c2ecf20Sopenharmony_ci		scmd_printk(KERN_ERR, CURRENT_SC,
20558c2ecf20Sopenharmony_ci			    "manual transfer count differs from automatic "
20568c2ecf20Sopenharmony_ci			    "(count=%d;stcnt=%d;diff=%d;fifostat=%d)",
20578c2ecf20Sopenharmony_ci			    DATA_LEN, GETSTCNT(), GETSTCNT()-DATA_LEN,
20588c2ecf20Sopenharmony_ci			    GETPORT(FIFOSTAT));
20598c2ecf20Sopenharmony_ci		mdelay(10000);
20608c2ecf20Sopenharmony_ci	}
20618c2ecf20Sopenharmony_ci}
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_cistatic void datai_end(struct Scsi_Host *shpnt)
20648c2ecf20Sopenharmony_ci{
20658c2ecf20Sopenharmony_ci	CMD_INC_RESID(CURRENT_SC, -GETSTCNT());
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_ci	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
20688c2ecf20Sopenharmony_ci	SETPORT(DMACNTRL0, 0);
20698c2ecf20Sopenharmony_ci}
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci/*
20728c2ecf20Sopenharmony_ci * data out phase
20738c2ecf20Sopenharmony_ci *
20748c2ecf20Sopenharmony_ci */
20758c2ecf20Sopenharmony_cistatic void datao_init(struct Scsi_Host *shpnt)
20768c2ecf20Sopenharmony_ci{
20778c2ecf20Sopenharmony_ci	SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
20788c2ecf20Sopenharmony_ci	SETPORT(DMACNTRL0, WRITE_READ | ENDMA);
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
20818c2ecf20Sopenharmony_ci	SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci	SETPORT(SIMODE0, 0);
20848c2ecf20Sopenharmony_ci	SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE );
20858c2ecf20Sopenharmony_ci
20868c2ecf20Sopenharmony_ci	DATA_LEN = scsi_get_resid(CURRENT_SC);
20878c2ecf20Sopenharmony_ci}
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_cistatic void datao_run(struct Scsi_Host *shpnt)
20908c2ecf20Sopenharmony_ci{
20918c2ecf20Sopenharmony_ci	unsigned long the_time;
20928c2ecf20Sopenharmony_ci	int data_count;
20938c2ecf20Sopenharmony_ci
20948c2ecf20Sopenharmony_ci	/* until phase changes or all data sent */
20958c2ecf20Sopenharmony_ci	while(TESTLO(DMASTAT, INTSTAT) && CURRENT_SC->SCp.this_residual>0) {
20968c2ecf20Sopenharmony_ci		data_count = 128;
20978c2ecf20Sopenharmony_ci		if(data_count > CURRENT_SC->SCp.this_residual)
20988c2ecf20Sopenharmony_ci			data_count=CURRENT_SC->SCp.this_residual;
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_ci		if(TESTLO(DMASTAT, DFIFOEMP)) {
21018c2ecf20Sopenharmony_ci			scmd_printk(KERN_ERR, CURRENT_SC,
21028c2ecf20Sopenharmony_ci				    "datao fifo not empty (%d)",
21038c2ecf20Sopenharmony_ci				    GETPORT(FIFOSTAT));
21048c2ecf20Sopenharmony_ci			break;
21058c2ecf20Sopenharmony_ci		}
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_ci		if(data_count & 1) {
21088c2ecf20Sopenharmony_ci			SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT);
21098c2ecf20Sopenharmony_ci			SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++);
21108c2ecf20Sopenharmony_ci			CURRENT_SC->SCp.this_residual--;
21118c2ecf20Sopenharmony_ci			CMD_INC_RESID(CURRENT_SC, -1);
21128c2ecf20Sopenharmony_ci			SETPORT(DMACNTRL0,WRITE_READ|ENDMA);
21138c2ecf20Sopenharmony_ci		}
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci		if(data_count > 1) {
21168c2ecf20Sopenharmony_ci			data_count >>= 1;
21178c2ecf20Sopenharmony_ci			outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
21188c2ecf20Sopenharmony_ci			CURRENT_SC->SCp.ptr           += 2 * data_count;
21198c2ecf20Sopenharmony_ci			CURRENT_SC->SCp.this_residual -= 2 * data_count;
21208c2ecf20Sopenharmony_ci			CMD_INC_RESID(CURRENT_SC, -2 * data_count);
21218c2ecf20Sopenharmony_ci		}
21228c2ecf20Sopenharmony_ci
21238c2ecf20Sopenharmony_ci		if (CURRENT_SC->SCp.this_residual == 0 &&
21248c2ecf20Sopenharmony_ci		    !sg_is_last(CURRENT_SC->SCp.buffer)) {
21258c2ecf20Sopenharmony_ci			/* advance to next buffer */
21268c2ecf20Sopenharmony_ci			CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer);
21278c2ecf20Sopenharmony_ci			CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer);
21288c2ecf20Sopenharmony_ci			CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
21298c2ecf20Sopenharmony_ci		}
21308c2ecf20Sopenharmony_ci
21318c2ecf20Sopenharmony_ci		the_time=jiffies + 100*HZ;
21328c2ecf20Sopenharmony_ci		while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time))
21338c2ecf20Sopenharmony_ci			barrier();
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_ci		if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) {
21368c2ecf20Sopenharmony_ci			scmd_printk(KERN_ERR, CURRENT_SC, "dataout timeout\n");
21378c2ecf20Sopenharmony_ci			break;
21388c2ecf20Sopenharmony_ci		}
21398c2ecf20Sopenharmony_ci	}
21408c2ecf20Sopenharmony_ci}
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_cistatic void datao_end(struct Scsi_Host *shpnt)
21438c2ecf20Sopenharmony_ci{
21448c2ecf20Sopenharmony_ci	if(TESTLO(DMASTAT, DFIFOEMP)) {
21458c2ecf20Sopenharmony_ci		u32 datao_cnt = GETSTCNT();
21468c2ecf20Sopenharmony_ci		int datao_out = DATA_LEN - scsi_get_resid(CURRENT_SC);
21478c2ecf20Sopenharmony_ci		int done;
21488c2ecf20Sopenharmony_ci		struct scatterlist *sg = scsi_sglist(CURRENT_SC);
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci		CMD_INC_RESID(CURRENT_SC, datao_out - datao_cnt);
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci		done = scsi_bufflen(CURRENT_SC) - scsi_get_resid(CURRENT_SC);
21538c2ecf20Sopenharmony_ci		/* Locate the first SG entry not yet sent */
21548c2ecf20Sopenharmony_ci		while (done > 0 && !sg_is_last(sg)) {
21558c2ecf20Sopenharmony_ci			if (done < sg->length)
21568c2ecf20Sopenharmony_ci				break;
21578c2ecf20Sopenharmony_ci			done -= sg->length;
21588c2ecf20Sopenharmony_ci			sg = sg_next(sg);
21598c2ecf20Sopenharmony_ci		}
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_ci		CURRENT_SC->SCp.buffer = sg;
21628c2ecf20Sopenharmony_ci		CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) + done;
21638c2ecf20Sopenharmony_ci		CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length -
21648c2ecf20Sopenharmony_ci			done;
21658c2ecf20Sopenharmony_ci	}
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
21688c2ecf20Sopenharmony_ci	SETPORT(SXFRCTL0, CH1);
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_ci	SETPORT(DMACNTRL0, 0);
21718c2ecf20Sopenharmony_ci}
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci/*
21748c2ecf20Sopenharmony_ci * figure out what state we're in
21758c2ecf20Sopenharmony_ci *
21768c2ecf20Sopenharmony_ci */
21778c2ecf20Sopenharmony_cistatic int update_state(struct Scsi_Host *shpnt)
21788c2ecf20Sopenharmony_ci{
21798c2ecf20Sopenharmony_ci	int dataphase=0;
21808c2ecf20Sopenharmony_ci	unsigned int stat0 = GETPORT(SSTAT0);
21818c2ecf20Sopenharmony_ci	unsigned int stat1 = GETPORT(SSTAT1);
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_ci	PREVSTATE = STATE;
21848c2ecf20Sopenharmony_ci	STATE=unknown;
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_ci	if(stat1 & SCSIRSTI) {
21878c2ecf20Sopenharmony_ci		STATE=rsti;
21888c2ecf20Sopenharmony_ci		SETPORT(SCSISEQ,0);
21898c2ecf20Sopenharmony_ci		SETPORT(SSTAT1,SCSIRSTI);
21908c2ecf20Sopenharmony_ci	} else if (stat0 & SELDI && PREVSTATE == busfree) {
21918c2ecf20Sopenharmony_ci		STATE=seldi;
21928c2ecf20Sopenharmony_ci	} else if(stat0 & SELDO && CURRENT_SC && (CURRENT_SC->SCp.phase & selecting)) {
21938c2ecf20Sopenharmony_ci		STATE=seldo;
21948c2ecf20Sopenharmony_ci	} else if(stat1 & SELTO) {
21958c2ecf20Sopenharmony_ci		STATE=selto;
21968c2ecf20Sopenharmony_ci	} else if(stat1 & BUSFREE) {
21978c2ecf20Sopenharmony_ci		STATE=busfree;
21988c2ecf20Sopenharmony_ci		SETPORT(SSTAT1,BUSFREE);
21998c2ecf20Sopenharmony_ci	} else if(stat1 & SCSIPERR) {
22008c2ecf20Sopenharmony_ci		STATE=parerr;
22018c2ecf20Sopenharmony_ci		SETPORT(SSTAT1,SCSIPERR);
22028c2ecf20Sopenharmony_ci	} else if(stat1 & REQINIT) {
22038c2ecf20Sopenharmony_ci		switch(GETPORT(SCSISIG) & P_MASK) {
22048c2ecf20Sopenharmony_ci		case P_MSGI:	STATE=msgi;	break;
22058c2ecf20Sopenharmony_ci		case P_MSGO:	STATE=msgo;	break;
22068c2ecf20Sopenharmony_ci		case P_DATAO:	STATE=datao;	break;
22078c2ecf20Sopenharmony_ci		case P_DATAI:	STATE=datai;	break;
22088c2ecf20Sopenharmony_ci		case P_STATUS:	STATE=status;	break;
22098c2ecf20Sopenharmony_ci		case P_CMD:	STATE=cmd;	break;
22108c2ecf20Sopenharmony_ci		}
22118c2ecf20Sopenharmony_ci		dataphase=1;
22128c2ecf20Sopenharmony_ci	}
22138c2ecf20Sopenharmony_ci
22148c2ecf20Sopenharmony_ci	if((stat0 & SELDI) && STATE!=seldi && !dataphase) {
22158c2ecf20Sopenharmony_ci		scmd_printk(KERN_INFO, CURRENT_SC, "reselection missed?");
22168c2ecf20Sopenharmony_ci	}
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_ci	if(STATE!=PREVSTATE) {
22198c2ecf20Sopenharmony_ci		LASTSTATE=PREVSTATE;
22208c2ecf20Sopenharmony_ci	}
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci	return dataphase;
22238c2ecf20Sopenharmony_ci}
22248c2ecf20Sopenharmony_ci
22258c2ecf20Sopenharmony_ci/*
22268c2ecf20Sopenharmony_ci * handle parity error
22278c2ecf20Sopenharmony_ci *
22288c2ecf20Sopenharmony_ci * FIXME: in which phase?
22298c2ecf20Sopenharmony_ci *
22308c2ecf20Sopenharmony_ci */
22318c2ecf20Sopenharmony_cistatic void parerr_run(struct Scsi_Host *shpnt)
22328c2ecf20Sopenharmony_ci{
22338c2ecf20Sopenharmony_ci	scmd_printk(KERN_ERR, CURRENT_SC, "parity error\n");
22348c2ecf20Sopenharmony_ci	done(shpnt, DID_PARITY << 16);
22358c2ecf20Sopenharmony_ci}
22368c2ecf20Sopenharmony_ci
22378c2ecf20Sopenharmony_ci/*
22388c2ecf20Sopenharmony_ci * handle reset in
22398c2ecf20Sopenharmony_ci *
22408c2ecf20Sopenharmony_ci */
22418c2ecf20Sopenharmony_cistatic void rsti_run(struct Scsi_Host *shpnt)
22428c2ecf20Sopenharmony_ci{
22438c2ecf20Sopenharmony_ci	struct scsi_cmnd *ptr;
22448c2ecf20Sopenharmony_ci
22458c2ecf20Sopenharmony_ci	shost_printk(KERN_NOTICE, shpnt, "scsi reset in\n");
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_ci	ptr=DISCONNECTED_SC;
22488c2ecf20Sopenharmony_ci	while(ptr) {
22498c2ecf20Sopenharmony_ci		struct scsi_cmnd *next = SCNEXT(ptr);
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_ci		if (!ptr->device->soft_reset) {
22528c2ecf20Sopenharmony_ci			remove_SC(&DISCONNECTED_SC, ptr);
22538c2ecf20Sopenharmony_ci
22548c2ecf20Sopenharmony_ci			kfree(ptr->host_scribble);
22558c2ecf20Sopenharmony_ci			ptr->host_scribble=NULL;
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci			ptr->result =  DID_RESET << 16;
22588c2ecf20Sopenharmony_ci			ptr->scsi_done(ptr);
22598c2ecf20Sopenharmony_ci		}
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_ci		ptr = next;
22628c2ecf20Sopenharmony_ci	}
22638c2ecf20Sopenharmony_ci
22648c2ecf20Sopenharmony_ci	if(CURRENT_SC && !CURRENT_SC->device->soft_reset)
22658c2ecf20Sopenharmony_ci		done(shpnt, DID_RESET << 16 );
22668c2ecf20Sopenharmony_ci}
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_ci
22698c2ecf20Sopenharmony_ci/*
22708c2ecf20Sopenharmony_ci * bottom-half handler
22718c2ecf20Sopenharmony_ci *
22728c2ecf20Sopenharmony_ci */
22738c2ecf20Sopenharmony_cistatic void is_complete(struct Scsi_Host *shpnt)
22748c2ecf20Sopenharmony_ci{
22758c2ecf20Sopenharmony_ci	int dataphase;
22768c2ecf20Sopenharmony_ci	unsigned long flags;
22778c2ecf20Sopenharmony_ci	int pending;
22788c2ecf20Sopenharmony_ci
22798c2ecf20Sopenharmony_ci	if(!shpnt)
22808c2ecf20Sopenharmony_ci		return;
22818c2ecf20Sopenharmony_ci
22828c2ecf20Sopenharmony_ci	DO_LOCK(flags);
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_ci	if( HOSTDATA(shpnt)->service==0 )  {
22858c2ecf20Sopenharmony_ci		DO_UNLOCK(flags);
22868c2ecf20Sopenharmony_ci		return;
22878c2ecf20Sopenharmony_ci	}
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_ci	HOSTDATA(shpnt)->service = 0;
22908c2ecf20Sopenharmony_ci
22918c2ecf20Sopenharmony_ci	if(HOSTDATA(shpnt)->in_intr) {
22928c2ecf20Sopenharmony_ci		DO_UNLOCK(flags);
22938c2ecf20Sopenharmony_ci		/* aha152x_error never returns.. */
22948c2ecf20Sopenharmony_ci		aha152x_error(shpnt, "bottom-half already running!?");
22958c2ecf20Sopenharmony_ci	}
22968c2ecf20Sopenharmony_ci	HOSTDATA(shpnt)->in_intr++;
22978c2ecf20Sopenharmony_ci
22988c2ecf20Sopenharmony_ci	/*
22998c2ecf20Sopenharmony_ci	 * loop while there are interrupt conditions pending
23008c2ecf20Sopenharmony_ci	 *
23018c2ecf20Sopenharmony_ci	 */
23028c2ecf20Sopenharmony_ci	do {
23038c2ecf20Sopenharmony_ci		unsigned long start = jiffies;
23048c2ecf20Sopenharmony_ci		DO_UNLOCK(flags);
23058c2ecf20Sopenharmony_ci
23068c2ecf20Sopenharmony_ci		dataphase=update_state(shpnt);
23078c2ecf20Sopenharmony_ci
23088c2ecf20Sopenharmony_ci		/*
23098c2ecf20Sopenharmony_ci		 * end previous state
23108c2ecf20Sopenharmony_ci		 *
23118c2ecf20Sopenharmony_ci		 */
23128c2ecf20Sopenharmony_ci		if(PREVSTATE!=STATE && states[PREVSTATE].end)
23138c2ecf20Sopenharmony_ci			states[PREVSTATE].end(shpnt);
23148c2ecf20Sopenharmony_ci
23158c2ecf20Sopenharmony_ci		/*
23168c2ecf20Sopenharmony_ci		 * disable SPIO mode if previous phase used it
23178c2ecf20Sopenharmony_ci		 * and this one doesn't
23188c2ecf20Sopenharmony_ci		 *
23198c2ecf20Sopenharmony_ci		 */
23208c2ecf20Sopenharmony_ci		if(states[PREVSTATE].spio && !states[STATE].spio) {
23218c2ecf20Sopenharmony_ci			SETPORT(SXFRCTL0, CH1);
23228c2ecf20Sopenharmony_ci			SETPORT(DMACNTRL0, 0);
23238c2ecf20Sopenharmony_ci			if(CURRENT_SC)
23248c2ecf20Sopenharmony_ci				CURRENT_SC->SCp.phase &= ~spiordy;
23258c2ecf20Sopenharmony_ci		}
23268c2ecf20Sopenharmony_ci
23278c2ecf20Sopenharmony_ci		/*
23288c2ecf20Sopenharmony_ci		 * accept current dataphase phase
23298c2ecf20Sopenharmony_ci		 *
23308c2ecf20Sopenharmony_ci		 */
23318c2ecf20Sopenharmony_ci		if(dataphase) {
23328c2ecf20Sopenharmony_ci			SETPORT(SSTAT0, REQINIT);
23338c2ecf20Sopenharmony_ci			SETPORT(SCSISIG, GETPORT(SCSISIG) & P_MASK);
23348c2ecf20Sopenharmony_ci			SETPORT(SSTAT1, PHASECHG);
23358c2ecf20Sopenharmony_ci		}
23368c2ecf20Sopenharmony_ci
23378c2ecf20Sopenharmony_ci		/*
23388c2ecf20Sopenharmony_ci		 * enable SPIO mode if previous didn't use it
23398c2ecf20Sopenharmony_ci		 * and this one does
23408c2ecf20Sopenharmony_ci		 *
23418c2ecf20Sopenharmony_ci		 */
23428c2ecf20Sopenharmony_ci		if(!states[PREVSTATE].spio && states[STATE].spio) {
23438c2ecf20Sopenharmony_ci			SETPORT(DMACNTRL0, 0);
23448c2ecf20Sopenharmony_ci			SETPORT(SXFRCTL0, CH1|SPIOEN);
23458c2ecf20Sopenharmony_ci			if(CURRENT_SC)
23468c2ecf20Sopenharmony_ci				CURRENT_SC->SCp.phase |= spiordy;
23478c2ecf20Sopenharmony_ci		}
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci		/*
23508c2ecf20Sopenharmony_ci		 * initialize for new state
23518c2ecf20Sopenharmony_ci		 *
23528c2ecf20Sopenharmony_ci		 */
23538c2ecf20Sopenharmony_ci		if(PREVSTATE!=STATE && states[STATE].init)
23548c2ecf20Sopenharmony_ci			states[STATE].init(shpnt);
23558c2ecf20Sopenharmony_ci
23568c2ecf20Sopenharmony_ci		/*
23578c2ecf20Sopenharmony_ci		 * handle current state
23588c2ecf20Sopenharmony_ci		 *
23598c2ecf20Sopenharmony_ci		 */
23608c2ecf20Sopenharmony_ci		if(states[STATE].run)
23618c2ecf20Sopenharmony_ci			states[STATE].run(shpnt);
23628c2ecf20Sopenharmony_ci		else
23638c2ecf20Sopenharmony_ci			scmd_printk(KERN_ERR, CURRENT_SC,
23648c2ecf20Sopenharmony_ci				    "unexpected state (%x)\n", STATE);
23658c2ecf20Sopenharmony_ci
23668c2ecf20Sopenharmony_ci		/*
23678c2ecf20Sopenharmony_ci		 * setup controller to interrupt on
23688c2ecf20Sopenharmony_ci		 * the next expected condition and
23698c2ecf20Sopenharmony_ci		 * loop if it's already there
23708c2ecf20Sopenharmony_ci		 *
23718c2ecf20Sopenharmony_ci		 */
23728c2ecf20Sopenharmony_ci		DO_LOCK(flags);
23738c2ecf20Sopenharmony_ci		pending=setup_expected_interrupts(shpnt);
23748c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT)
23758c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->count[STATE]++;
23768c2ecf20Sopenharmony_ci		if(PREVSTATE!=STATE)
23778c2ecf20Sopenharmony_ci			HOSTDATA(shpnt)->count_trans[STATE]++;
23788c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->time[STATE] += jiffies-start;
23798c2ecf20Sopenharmony_ci#endif
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_ci	} while(pending);
23828c2ecf20Sopenharmony_ci
23838c2ecf20Sopenharmony_ci	/*
23848c2ecf20Sopenharmony_ci	 * enable interrupts and leave bottom-half
23858c2ecf20Sopenharmony_ci	 *
23868c2ecf20Sopenharmony_ci	 */
23878c2ecf20Sopenharmony_ci	HOSTDATA(shpnt)->in_intr--;
23888c2ecf20Sopenharmony_ci	SETBITS(DMACNTRL0, INTEN);
23898c2ecf20Sopenharmony_ci	DO_UNLOCK(flags);
23908c2ecf20Sopenharmony_ci}
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_ci
23938c2ecf20Sopenharmony_ci/*
23948c2ecf20Sopenharmony_ci * Dump the current driver status and panic
23958c2ecf20Sopenharmony_ci */
23968c2ecf20Sopenharmony_cistatic void aha152x_error(struct Scsi_Host *shpnt, char *msg)
23978c2ecf20Sopenharmony_ci{
23988c2ecf20Sopenharmony_ci	shost_printk(KERN_EMERG, shpnt, "%s\n", msg);
23998c2ecf20Sopenharmony_ci	show_queues(shpnt);
24008c2ecf20Sopenharmony_ci	panic("aha152x panic\n");
24018c2ecf20Sopenharmony_ci}
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci/*
24048c2ecf20Sopenharmony_ci * display enabled interrupts
24058c2ecf20Sopenharmony_ci */
24068c2ecf20Sopenharmony_cistatic void disp_enintr(struct Scsi_Host *shpnt)
24078c2ecf20Sopenharmony_ci{
24088c2ecf20Sopenharmony_ci	int s0, s1;
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_ci	s0 = GETPORT(SIMODE0);
24118c2ecf20Sopenharmony_ci	s1 = GETPORT(SIMODE1);
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_ci	shost_printk(KERN_DEBUG, shpnt,
24148c2ecf20Sopenharmony_ci		     "enabled interrupts (%s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n",
24158c2ecf20Sopenharmony_ci		     (s0 & ENSELDO) ? "ENSELDO " : "",
24168c2ecf20Sopenharmony_ci		     (s0 & ENSELDI) ? "ENSELDI " : "",
24178c2ecf20Sopenharmony_ci		     (s0 & ENSELINGO) ? "ENSELINGO " : "",
24188c2ecf20Sopenharmony_ci		     (s0 & ENSWRAP) ? "ENSWRAP " : "",
24198c2ecf20Sopenharmony_ci		     (s0 & ENSDONE) ? "ENSDONE " : "",
24208c2ecf20Sopenharmony_ci		     (s0 & ENSPIORDY) ? "ENSPIORDY " : "",
24218c2ecf20Sopenharmony_ci		     (s0 & ENDMADONE) ? "ENDMADONE " : "",
24228c2ecf20Sopenharmony_ci		     (s1 & ENSELTIMO) ? "ENSELTIMO " : "",
24238c2ecf20Sopenharmony_ci		     (s1 & ENATNTARG) ? "ENATNTARG " : "",
24248c2ecf20Sopenharmony_ci		     (s1 & ENPHASEMIS) ? "ENPHASEMIS " : "",
24258c2ecf20Sopenharmony_ci		     (s1 & ENBUSFREE) ? "ENBUSFREE " : "",
24268c2ecf20Sopenharmony_ci		     (s1 & ENSCSIPERR) ? "ENSCSIPERR " : "",
24278c2ecf20Sopenharmony_ci		     (s1 & ENPHASECHG) ? "ENPHASECHG " : "",
24288c2ecf20Sopenharmony_ci		     (s1 & ENREQINIT) ? "ENREQINIT " : "");
24298c2ecf20Sopenharmony_ci}
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_ci/*
24328c2ecf20Sopenharmony_ci * Show the command data of a command
24338c2ecf20Sopenharmony_ci */
24348c2ecf20Sopenharmony_cistatic void show_command(struct scsi_cmnd *ptr)
24358c2ecf20Sopenharmony_ci{
24368c2ecf20Sopenharmony_ci	scsi_print_command(ptr);
24378c2ecf20Sopenharmony_ci	scmd_printk(KERN_DEBUG, ptr,
24388c2ecf20Sopenharmony_ci		    "request_bufflen=%d; resid=%d; "
24398c2ecf20Sopenharmony_ci		    "phase |%s%s%s%s%s%s%s%s%s; next=0x%p",
24408c2ecf20Sopenharmony_ci		    scsi_bufflen(ptr), scsi_get_resid(ptr),
24418c2ecf20Sopenharmony_ci		    (ptr->SCp.phase & not_issued) ? "not issued|" : "",
24428c2ecf20Sopenharmony_ci		    (ptr->SCp.phase & selecting) ? "selecting|" : "",
24438c2ecf20Sopenharmony_ci		    (ptr->SCp.phase & identified) ? "identified|" : "",
24448c2ecf20Sopenharmony_ci		    (ptr->SCp.phase & disconnected) ? "disconnected|" : "",
24458c2ecf20Sopenharmony_ci		    (ptr->SCp.phase & completed) ? "completed|" : "",
24468c2ecf20Sopenharmony_ci		    (ptr->SCp.phase & spiordy) ? "spiordy|" : "",
24478c2ecf20Sopenharmony_ci		    (ptr->SCp.phase & syncneg) ? "syncneg|" : "",
24488c2ecf20Sopenharmony_ci		    (ptr->SCp.phase & aborted) ? "aborted|" : "",
24498c2ecf20Sopenharmony_ci		    (ptr->SCp.phase & resetted) ? "resetted|" : "",
24508c2ecf20Sopenharmony_ci		    (SCDATA(ptr)) ? SCNEXT(ptr) : NULL);
24518c2ecf20Sopenharmony_ci}
24528c2ecf20Sopenharmony_ci
24538c2ecf20Sopenharmony_ci/*
24548c2ecf20Sopenharmony_ci * Dump the queued data
24558c2ecf20Sopenharmony_ci */
24568c2ecf20Sopenharmony_cistatic void show_queues(struct Scsi_Host *shpnt)
24578c2ecf20Sopenharmony_ci{
24588c2ecf20Sopenharmony_ci	struct scsi_cmnd *ptr;
24598c2ecf20Sopenharmony_ci	unsigned long flags;
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_ci	DO_LOCK(flags);
24628c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "\nqueue status:\nissue_SC:\n");
24638c2ecf20Sopenharmony_ci	for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
24648c2ecf20Sopenharmony_ci		show_command(ptr);
24658c2ecf20Sopenharmony_ci	DO_UNLOCK(flags);
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "current_SC:\n");
24688c2ecf20Sopenharmony_ci	if (CURRENT_SC)
24698c2ecf20Sopenharmony_ci		show_command(CURRENT_SC);
24708c2ecf20Sopenharmony_ci	else
24718c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "none\n");
24728c2ecf20Sopenharmony_ci
24738c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "disconnected_SC:\n");
24748c2ecf20Sopenharmony_ci	for (ptr = DISCONNECTED_SC; ptr; ptr = SCDATA(ptr) ? SCNEXT(ptr) : NULL)
24758c2ecf20Sopenharmony_ci		show_command(ptr);
24768c2ecf20Sopenharmony_ci
24778c2ecf20Sopenharmony_ci	disp_enintr(shpnt);
24788c2ecf20Sopenharmony_ci}
24798c2ecf20Sopenharmony_ci
24808c2ecf20Sopenharmony_cistatic void get_command(struct seq_file *m, struct scsi_cmnd * ptr)
24818c2ecf20Sopenharmony_ci{
24828c2ecf20Sopenharmony_ci	int i;
24838c2ecf20Sopenharmony_ci
24848c2ecf20Sopenharmony_ci	seq_printf(m, "%p: target=%d; lun=%d; cmnd=( ",
24858c2ecf20Sopenharmony_ci		ptr, ptr->device->id, (u8)ptr->device->lun);
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_ci	for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++)
24888c2ecf20Sopenharmony_ci		seq_printf(m, "0x%02x ", ptr->cmnd[i]);
24898c2ecf20Sopenharmony_ci
24908c2ecf20Sopenharmony_ci	seq_printf(m, "); resid=%d; residual=%d; buffers=%d; phase |",
24918c2ecf20Sopenharmony_ci		scsi_get_resid(ptr), ptr->SCp.this_residual,
24928c2ecf20Sopenharmony_ci		sg_nents(ptr->SCp.buffer) - 1);
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci	if (ptr->SCp.phase & not_issued)
24958c2ecf20Sopenharmony_ci		seq_puts(m, "not issued|");
24968c2ecf20Sopenharmony_ci	if (ptr->SCp.phase & selecting)
24978c2ecf20Sopenharmony_ci		seq_puts(m, "selecting|");
24988c2ecf20Sopenharmony_ci	if (ptr->SCp.phase & disconnected)
24998c2ecf20Sopenharmony_ci		seq_puts(m, "disconnected|");
25008c2ecf20Sopenharmony_ci	if (ptr->SCp.phase & aborted)
25018c2ecf20Sopenharmony_ci		seq_puts(m, "aborted|");
25028c2ecf20Sopenharmony_ci	if (ptr->SCp.phase & identified)
25038c2ecf20Sopenharmony_ci		seq_puts(m, "identified|");
25048c2ecf20Sopenharmony_ci	if (ptr->SCp.phase & completed)
25058c2ecf20Sopenharmony_ci		seq_puts(m, "completed|");
25068c2ecf20Sopenharmony_ci	if (ptr->SCp.phase & spiordy)
25078c2ecf20Sopenharmony_ci		seq_puts(m, "spiordy|");
25088c2ecf20Sopenharmony_ci	if (ptr->SCp.phase & syncneg)
25098c2ecf20Sopenharmony_ci		seq_puts(m, "syncneg|");
25108c2ecf20Sopenharmony_ci	seq_printf(m, "; next=0x%p\n", SCNEXT(ptr));
25118c2ecf20Sopenharmony_ci}
25128c2ecf20Sopenharmony_ci
25138c2ecf20Sopenharmony_cistatic void get_ports(struct seq_file *m, struct Scsi_Host *shpnt)
25148c2ecf20Sopenharmony_ci{
25158c2ecf20Sopenharmony_ci	int s;
25168c2ecf20Sopenharmony_ci
25178c2ecf20Sopenharmony_ci	seq_printf(m, "\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name);
25188c2ecf20Sopenharmony_ci
25198c2ecf20Sopenharmony_ci	s = GETPORT(SCSISEQ);
25208c2ecf20Sopenharmony_ci	seq_puts(m, "SCSISEQ( ");
25218c2ecf20Sopenharmony_ci	if (s & TEMODEO)
25228c2ecf20Sopenharmony_ci		seq_puts(m, "TARGET MODE ");
25238c2ecf20Sopenharmony_ci	if (s & ENSELO)
25248c2ecf20Sopenharmony_ci		seq_puts(m, "SELO ");
25258c2ecf20Sopenharmony_ci	if (s & ENSELI)
25268c2ecf20Sopenharmony_ci		seq_puts(m, "SELI ");
25278c2ecf20Sopenharmony_ci	if (s & ENRESELI)
25288c2ecf20Sopenharmony_ci		seq_puts(m, "RESELI ");
25298c2ecf20Sopenharmony_ci	if (s & ENAUTOATNO)
25308c2ecf20Sopenharmony_ci		seq_puts(m, "AUTOATNO ");
25318c2ecf20Sopenharmony_ci	if (s & ENAUTOATNI)
25328c2ecf20Sopenharmony_ci		seq_puts(m, "AUTOATNI ");
25338c2ecf20Sopenharmony_ci	if (s & ENAUTOATNP)
25348c2ecf20Sopenharmony_ci		seq_puts(m, "AUTOATNP ");
25358c2ecf20Sopenharmony_ci	if (s & SCSIRSTO)
25368c2ecf20Sopenharmony_ci		seq_puts(m, "SCSIRSTO ");
25378c2ecf20Sopenharmony_ci	seq_puts(m, ");");
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_ci	seq_puts(m, " SCSISIG(");
25408c2ecf20Sopenharmony_ci	s = GETPORT(SCSISIG);
25418c2ecf20Sopenharmony_ci	switch (s & P_MASK) {
25428c2ecf20Sopenharmony_ci	case P_DATAO:
25438c2ecf20Sopenharmony_ci		seq_puts(m, "DATA OUT");
25448c2ecf20Sopenharmony_ci		break;
25458c2ecf20Sopenharmony_ci	case P_DATAI:
25468c2ecf20Sopenharmony_ci		seq_puts(m, "DATA IN");
25478c2ecf20Sopenharmony_ci		break;
25488c2ecf20Sopenharmony_ci	case P_CMD:
25498c2ecf20Sopenharmony_ci		seq_puts(m, "COMMAND");
25508c2ecf20Sopenharmony_ci		break;
25518c2ecf20Sopenharmony_ci	case P_STATUS:
25528c2ecf20Sopenharmony_ci		seq_puts(m, "STATUS");
25538c2ecf20Sopenharmony_ci		break;
25548c2ecf20Sopenharmony_ci	case P_MSGO:
25558c2ecf20Sopenharmony_ci		seq_puts(m, "MESSAGE OUT");
25568c2ecf20Sopenharmony_ci		break;
25578c2ecf20Sopenharmony_ci	case P_MSGI:
25588c2ecf20Sopenharmony_ci		seq_puts(m, "MESSAGE IN");
25598c2ecf20Sopenharmony_ci		break;
25608c2ecf20Sopenharmony_ci	default:
25618c2ecf20Sopenharmony_ci		seq_puts(m, "*invalid*");
25628c2ecf20Sopenharmony_ci		break;
25638c2ecf20Sopenharmony_ci	}
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_ci	seq_puts(m, "); ");
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_ci	seq_printf(m, "INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
25688c2ecf20Sopenharmony_ci
25698c2ecf20Sopenharmony_ci	seq_puts(m, "SSTAT( ");
25708c2ecf20Sopenharmony_ci	s = GETPORT(SSTAT0);
25718c2ecf20Sopenharmony_ci	if (s & TARGET)
25728c2ecf20Sopenharmony_ci		seq_puts(m, "TARGET ");
25738c2ecf20Sopenharmony_ci	if (s & SELDO)
25748c2ecf20Sopenharmony_ci		seq_puts(m, "SELDO ");
25758c2ecf20Sopenharmony_ci	if (s & SELDI)
25768c2ecf20Sopenharmony_ci		seq_puts(m, "SELDI ");
25778c2ecf20Sopenharmony_ci	if (s & SELINGO)
25788c2ecf20Sopenharmony_ci		seq_puts(m, "SELINGO ");
25798c2ecf20Sopenharmony_ci	if (s & SWRAP)
25808c2ecf20Sopenharmony_ci		seq_puts(m, "SWRAP ");
25818c2ecf20Sopenharmony_ci	if (s & SDONE)
25828c2ecf20Sopenharmony_ci		seq_puts(m, "SDONE ");
25838c2ecf20Sopenharmony_ci	if (s & SPIORDY)
25848c2ecf20Sopenharmony_ci		seq_puts(m, "SPIORDY ");
25858c2ecf20Sopenharmony_ci	if (s & DMADONE)
25868c2ecf20Sopenharmony_ci		seq_puts(m, "DMADONE ");
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ci	s = GETPORT(SSTAT1);
25898c2ecf20Sopenharmony_ci	if (s & SELTO)
25908c2ecf20Sopenharmony_ci		seq_puts(m, "SELTO ");
25918c2ecf20Sopenharmony_ci	if (s & ATNTARG)
25928c2ecf20Sopenharmony_ci		seq_puts(m, "ATNTARG ");
25938c2ecf20Sopenharmony_ci	if (s & SCSIRSTI)
25948c2ecf20Sopenharmony_ci		seq_puts(m, "SCSIRSTI ");
25958c2ecf20Sopenharmony_ci	if (s & PHASEMIS)
25968c2ecf20Sopenharmony_ci		seq_puts(m, "PHASEMIS ");
25978c2ecf20Sopenharmony_ci	if (s & BUSFREE)
25988c2ecf20Sopenharmony_ci		seq_puts(m, "BUSFREE ");
25998c2ecf20Sopenharmony_ci	if (s & SCSIPERR)
26008c2ecf20Sopenharmony_ci		seq_puts(m, "SCSIPERR ");
26018c2ecf20Sopenharmony_ci	if (s & PHASECHG)
26028c2ecf20Sopenharmony_ci		seq_puts(m, "PHASECHG ");
26038c2ecf20Sopenharmony_ci	if (s & REQINIT)
26048c2ecf20Sopenharmony_ci		seq_puts(m, "REQINIT ");
26058c2ecf20Sopenharmony_ci	seq_puts(m, "); ");
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_ci
26088c2ecf20Sopenharmony_ci	seq_puts(m, "SSTAT( ");
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ci	s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ci	if (s & TARGET)
26138c2ecf20Sopenharmony_ci		seq_puts(m, "TARGET ");
26148c2ecf20Sopenharmony_ci	if (s & SELDO)
26158c2ecf20Sopenharmony_ci		seq_puts(m, "SELDO ");
26168c2ecf20Sopenharmony_ci	if (s & SELDI)
26178c2ecf20Sopenharmony_ci		seq_puts(m, "SELDI ");
26188c2ecf20Sopenharmony_ci	if (s & SELINGO)
26198c2ecf20Sopenharmony_ci		seq_puts(m, "SELINGO ");
26208c2ecf20Sopenharmony_ci	if (s & SWRAP)
26218c2ecf20Sopenharmony_ci		seq_puts(m, "SWRAP ");
26228c2ecf20Sopenharmony_ci	if (s & SDONE)
26238c2ecf20Sopenharmony_ci		seq_puts(m, "SDONE ");
26248c2ecf20Sopenharmony_ci	if (s & SPIORDY)
26258c2ecf20Sopenharmony_ci		seq_puts(m, "SPIORDY ");
26268c2ecf20Sopenharmony_ci	if (s & DMADONE)
26278c2ecf20Sopenharmony_ci		seq_puts(m, "DMADONE ");
26288c2ecf20Sopenharmony_ci
26298c2ecf20Sopenharmony_ci	s = GETPORT(SSTAT1) & GETPORT(SIMODE1);
26308c2ecf20Sopenharmony_ci
26318c2ecf20Sopenharmony_ci	if (s & SELTO)
26328c2ecf20Sopenharmony_ci		seq_puts(m, "SELTO ");
26338c2ecf20Sopenharmony_ci	if (s & ATNTARG)
26348c2ecf20Sopenharmony_ci		seq_puts(m, "ATNTARG ");
26358c2ecf20Sopenharmony_ci	if (s & SCSIRSTI)
26368c2ecf20Sopenharmony_ci		seq_puts(m, "SCSIRSTI ");
26378c2ecf20Sopenharmony_ci	if (s & PHASEMIS)
26388c2ecf20Sopenharmony_ci		seq_puts(m, "PHASEMIS ");
26398c2ecf20Sopenharmony_ci	if (s & BUSFREE)
26408c2ecf20Sopenharmony_ci		seq_puts(m, "BUSFREE ");
26418c2ecf20Sopenharmony_ci	if (s & SCSIPERR)
26428c2ecf20Sopenharmony_ci		seq_puts(m, "SCSIPERR ");
26438c2ecf20Sopenharmony_ci	if (s & PHASECHG)
26448c2ecf20Sopenharmony_ci		seq_puts(m, "PHASECHG ");
26458c2ecf20Sopenharmony_ci	if (s & REQINIT)
26468c2ecf20Sopenharmony_ci		seq_puts(m, "REQINIT ");
26478c2ecf20Sopenharmony_ci	seq_puts(m, "); ");
26488c2ecf20Sopenharmony_ci
26498c2ecf20Sopenharmony_ci	seq_puts(m, "SXFRCTL0( ");
26508c2ecf20Sopenharmony_ci
26518c2ecf20Sopenharmony_ci	s = GETPORT(SXFRCTL0);
26528c2ecf20Sopenharmony_ci	if (s & SCSIEN)
26538c2ecf20Sopenharmony_ci		seq_puts(m, "SCSIEN ");
26548c2ecf20Sopenharmony_ci	if (s & DMAEN)
26558c2ecf20Sopenharmony_ci		seq_puts(m, "DMAEN ");
26568c2ecf20Sopenharmony_ci	if (s & CH1)
26578c2ecf20Sopenharmony_ci		seq_puts(m, "CH1 ");
26588c2ecf20Sopenharmony_ci	if (s & CLRSTCNT)
26598c2ecf20Sopenharmony_ci		seq_puts(m, "CLRSTCNT ");
26608c2ecf20Sopenharmony_ci	if (s & SPIOEN)
26618c2ecf20Sopenharmony_ci		seq_puts(m, "SPIOEN ");
26628c2ecf20Sopenharmony_ci	if (s & CLRCH1)
26638c2ecf20Sopenharmony_ci		seq_puts(m, "CLRCH1 ");
26648c2ecf20Sopenharmony_ci	seq_puts(m, "); ");
26658c2ecf20Sopenharmony_ci
26668c2ecf20Sopenharmony_ci	seq_puts(m, "SIGNAL( ");
26678c2ecf20Sopenharmony_ci
26688c2ecf20Sopenharmony_ci	s = GETPORT(SCSISIG);
26698c2ecf20Sopenharmony_ci	if (s & SIG_ATNI)
26708c2ecf20Sopenharmony_ci		seq_puts(m, "ATNI ");
26718c2ecf20Sopenharmony_ci	if (s & SIG_SELI)
26728c2ecf20Sopenharmony_ci		seq_puts(m, "SELI ");
26738c2ecf20Sopenharmony_ci	if (s & SIG_BSYI)
26748c2ecf20Sopenharmony_ci		seq_puts(m, "BSYI ");
26758c2ecf20Sopenharmony_ci	if (s & SIG_REQI)
26768c2ecf20Sopenharmony_ci		seq_puts(m, "REQI ");
26778c2ecf20Sopenharmony_ci	if (s & SIG_ACKI)
26788c2ecf20Sopenharmony_ci		seq_puts(m, "ACKI ");
26798c2ecf20Sopenharmony_ci	seq_puts(m, "); ");
26808c2ecf20Sopenharmony_ci
26818c2ecf20Sopenharmony_ci	seq_printf(m, "SELID(%02x), ", GETPORT(SELID));
26828c2ecf20Sopenharmony_ci
26838c2ecf20Sopenharmony_ci	seq_printf(m, "STCNT(%d), ", GETSTCNT());
26848c2ecf20Sopenharmony_ci
26858c2ecf20Sopenharmony_ci	seq_puts(m, "SSTAT2( ");
26868c2ecf20Sopenharmony_ci
26878c2ecf20Sopenharmony_ci	s = GETPORT(SSTAT2);
26888c2ecf20Sopenharmony_ci	if (s & SOFFSET)
26898c2ecf20Sopenharmony_ci		seq_puts(m, "SOFFSET ");
26908c2ecf20Sopenharmony_ci	if (s & SEMPTY)
26918c2ecf20Sopenharmony_ci		seq_puts(m, "SEMPTY ");
26928c2ecf20Sopenharmony_ci	if (s & SFULL)
26938c2ecf20Sopenharmony_ci		seq_puts(m, "SFULL ");
26948c2ecf20Sopenharmony_ci	seq_printf(m, "); SFCNT (%d); ", s & (SFULL | SFCNT));
26958c2ecf20Sopenharmony_ci
26968c2ecf20Sopenharmony_ci	s = GETPORT(SSTAT3);
26978c2ecf20Sopenharmony_ci	seq_printf(m, "SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
26988c2ecf20Sopenharmony_ci
26998c2ecf20Sopenharmony_ci	seq_puts(m, "SSTAT4( ");
27008c2ecf20Sopenharmony_ci	s = GETPORT(SSTAT4);
27018c2ecf20Sopenharmony_ci	if (s & SYNCERR)
27028c2ecf20Sopenharmony_ci		seq_puts(m, "SYNCERR ");
27038c2ecf20Sopenharmony_ci	if (s & FWERR)
27048c2ecf20Sopenharmony_ci		seq_puts(m, "FWERR ");
27058c2ecf20Sopenharmony_ci	if (s & FRERR)
27068c2ecf20Sopenharmony_ci		seq_puts(m, "FRERR ");
27078c2ecf20Sopenharmony_ci	seq_puts(m, "); ");
27088c2ecf20Sopenharmony_ci
27098c2ecf20Sopenharmony_ci	seq_puts(m, "DMACNTRL0( ");
27108c2ecf20Sopenharmony_ci	s = GETPORT(DMACNTRL0);
27118c2ecf20Sopenharmony_ci	seq_printf(m, "%s ", s & _8BIT ? "8BIT" : "16BIT");
27128c2ecf20Sopenharmony_ci	seq_printf(m, "%s ", s & DMA ? "DMA" : "PIO");
27138c2ecf20Sopenharmony_ci	seq_printf(m, "%s ", s & WRITE_READ ? "WRITE" : "READ");
27148c2ecf20Sopenharmony_ci	if (s & ENDMA)
27158c2ecf20Sopenharmony_ci		seq_puts(m, "ENDMA ");
27168c2ecf20Sopenharmony_ci	if (s & INTEN)
27178c2ecf20Sopenharmony_ci		seq_puts(m, "INTEN ");
27188c2ecf20Sopenharmony_ci	if (s & RSTFIFO)
27198c2ecf20Sopenharmony_ci		seq_puts(m, "RSTFIFO ");
27208c2ecf20Sopenharmony_ci	if (s & SWINT)
27218c2ecf20Sopenharmony_ci		seq_puts(m, "SWINT ");
27228c2ecf20Sopenharmony_ci	seq_puts(m, "); ");
27238c2ecf20Sopenharmony_ci
27248c2ecf20Sopenharmony_ci	seq_puts(m, "DMASTAT( ");
27258c2ecf20Sopenharmony_ci	s = GETPORT(DMASTAT);
27268c2ecf20Sopenharmony_ci	if (s & ATDONE)
27278c2ecf20Sopenharmony_ci		seq_puts(m, "ATDONE ");
27288c2ecf20Sopenharmony_ci	if (s & WORDRDY)
27298c2ecf20Sopenharmony_ci		seq_puts(m, "WORDRDY ");
27308c2ecf20Sopenharmony_ci	if (s & DFIFOFULL)
27318c2ecf20Sopenharmony_ci		seq_puts(m, "DFIFOFULL ");
27328c2ecf20Sopenharmony_ci	if (s & DFIFOEMP)
27338c2ecf20Sopenharmony_ci		seq_puts(m, "DFIFOEMP ");
27348c2ecf20Sopenharmony_ci	seq_puts(m, ")\n");
27358c2ecf20Sopenharmony_ci
27368c2ecf20Sopenharmony_ci	seq_puts(m, "enabled interrupts( ");
27378c2ecf20Sopenharmony_ci
27388c2ecf20Sopenharmony_ci	s = GETPORT(SIMODE0);
27398c2ecf20Sopenharmony_ci	if (s & ENSELDO)
27408c2ecf20Sopenharmony_ci		seq_puts(m, "ENSELDO ");
27418c2ecf20Sopenharmony_ci	if (s & ENSELDI)
27428c2ecf20Sopenharmony_ci		seq_puts(m, "ENSELDI ");
27438c2ecf20Sopenharmony_ci	if (s & ENSELINGO)
27448c2ecf20Sopenharmony_ci		seq_puts(m, "ENSELINGO ");
27458c2ecf20Sopenharmony_ci	if (s & ENSWRAP)
27468c2ecf20Sopenharmony_ci		seq_puts(m, "ENSWRAP ");
27478c2ecf20Sopenharmony_ci	if (s & ENSDONE)
27488c2ecf20Sopenharmony_ci		seq_puts(m, "ENSDONE ");
27498c2ecf20Sopenharmony_ci	if (s & ENSPIORDY)
27508c2ecf20Sopenharmony_ci		seq_puts(m, "ENSPIORDY ");
27518c2ecf20Sopenharmony_ci	if (s & ENDMADONE)
27528c2ecf20Sopenharmony_ci		seq_puts(m, "ENDMADONE ");
27538c2ecf20Sopenharmony_ci
27548c2ecf20Sopenharmony_ci	s = GETPORT(SIMODE1);
27558c2ecf20Sopenharmony_ci	if (s & ENSELTIMO)
27568c2ecf20Sopenharmony_ci		seq_puts(m, "ENSELTIMO ");
27578c2ecf20Sopenharmony_ci	if (s & ENATNTARG)
27588c2ecf20Sopenharmony_ci		seq_puts(m, "ENATNTARG ");
27598c2ecf20Sopenharmony_ci	if (s & ENPHASEMIS)
27608c2ecf20Sopenharmony_ci		seq_puts(m, "ENPHASEMIS ");
27618c2ecf20Sopenharmony_ci	if (s & ENBUSFREE)
27628c2ecf20Sopenharmony_ci		seq_puts(m, "ENBUSFREE ");
27638c2ecf20Sopenharmony_ci	if (s & ENSCSIPERR)
27648c2ecf20Sopenharmony_ci		seq_puts(m, "ENSCSIPERR ");
27658c2ecf20Sopenharmony_ci	if (s & ENPHASECHG)
27668c2ecf20Sopenharmony_ci		seq_puts(m, "ENPHASECHG ");
27678c2ecf20Sopenharmony_ci	if (s & ENREQINIT)
27688c2ecf20Sopenharmony_ci		seq_puts(m, "ENREQINIT ");
27698c2ecf20Sopenharmony_ci	seq_puts(m, ")\n");
27708c2ecf20Sopenharmony_ci}
27718c2ecf20Sopenharmony_ci
27728c2ecf20Sopenharmony_cistatic int aha152x_set_info(struct Scsi_Host *shpnt, char *buffer, int length)
27738c2ecf20Sopenharmony_ci{
27748c2ecf20Sopenharmony_ci	if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0)
27758c2ecf20Sopenharmony_ci		return -EINVAL;
27768c2ecf20Sopenharmony_ci
27778c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT)
27788c2ecf20Sopenharmony_ci	if(length>13 && strncmp("reset", buffer+8, 5)==0) {
27798c2ecf20Sopenharmony_ci		int i;
27808c2ecf20Sopenharmony_ci
27818c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->total_commands=0;
27828c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->disconnections=0;
27838c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_any_action=0;
27848c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_old_command=0;
27858c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_new_command=0;
27868c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_done_command=0;
27878c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->busfree_with_check_condition=0;
27888c2ecf20Sopenharmony_ci		for (i = idle; i<maxstate; i++) {
27898c2ecf20Sopenharmony_ci			HOSTDATA(shpnt)->count[i]=0;
27908c2ecf20Sopenharmony_ci			HOSTDATA(shpnt)->count_trans[i]=0;
27918c2ecf20Sopenharmony_ci			HOSTDATA(shpnt)->time[i]=0;
27928c2ecf20Sopenharmony_ci		}
27938c2ecf20Sopenharmony_ci
27948c2ecf20Sopenharmony_ci		shost_printk(KERN_INFO, shpnt, "aha152x: stats reset.\n");
27958c2ecf20Sopenharmony_ci
27968c2ecf20Sopenharmony_ci	} else
27978c2ecf20Sopenharmony_ci#endif
27988c2ecf20Sopenharmony_ci	{
27998c2ecf20Sopenharmony_ci		return -EINVAL;
28008c2ecf20Sopenharmony_ci	}
28018c2ecf20Sopenharmony_ci
28028c2ecf20Sopenharmony_ci
28038c2ecf20Sopenharmony_ci	return length;
28048c2ecf20Sopenharmony_ci}
28058c2ecf20Sopenharmony_ci
28068c2ecf20Sopenharmony_cistatic int aha152x_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
28078c2ecf20Sopenharmony_ci{
28088c2ecf20Sopenharmony_ci	int i;
28098c2ecf20Sopenharmony_ci	struct scsi_cmnd *ptr;
28108c2ecf20Sopenharmony_ci	unsigned long flags;
28118c2ecf20Sopenharmony_ci
28128c2ecf20Sopenharmony_ci	seq_puts(m, AHA152X_REVID "\n");
28138c2ecf20Sopenharmony_ci
28148c2ecf20Sopenharmony_ci	seq_printf(m, "ioports 0x%04lx to 0x%04lx\n",
28158c2ecf20Sopenharmony_ci		shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1);
28168c2ecf20Sopenharmony_ci	seq_printf(m, "interrupt 0x%02x\n", shpnt->irq);
28178c2ecf20Sopenharmony_ci	seq_printf(m, "disconnection/reconnection %s\n",
28188c2ecf20Sopenharmony_ci		RECONNECT ? "enabled" : "disabled");
28198c2ecf20Sopenharmony_ci	seq_printf(m, "parity checking %s\n",
28208c2ecf20Sopenharmony_ci		PARITY ? "enabled" : "disabled");
28218c2ecf20Sopenharmony_ci	seq_printf(m, "synchronous transfers %s\n",
28228c2ecf20Sopenharmony_ci		SYNCHRONOUS ? "enabled" : "disabled");
28238c2ecf20Sopenharmony_ci	seq_printf(m, "%d commands currently queued\n", HOSTDATA(shpnt)->commands);
28248c2ecf20Sopenharmony_ci
28258c2ecf20Sopenharmony_ci	if(SYNCHRONOUS) {
28268c2ecf20Sopenharmony_ci		seq_puts(m, "synchronously operating targets (tick=50 ns):\n");
28278c2ecf20Sopenharmony_ci		for (i = 0; i < 8; i++)
28288c2ecf20Sopenharmony_ci			if (HOSTDATA(shpnt)->syncrate[i] & 0x7f)
28298c2ecf20Sopenharmony_ci				seq_printf(m, "target %d: period %dT/%dns; req/ack offset %d\n",
28308c2ecf20Sopenharmony_ci					i,
28318c2ecf20Sopenharmony_ci					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2),
28328c2ecf20Sopenharmony_ci					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50,
28338c2ecf20Sopenharmony_ci				    HOSTDATA(shpnt)->syncrate[i] & 0x0f);
28348c2ecf20Sopenharmony_ci	}
28358c2ecf20Sopenharmony_ci	seq_puts(m, "\nqueue status:\n");
28368c2ecf20Sopenharmony_ci	DO_LOCK(flags);
28378c2ecf20Sopenharmony_ci	if (ISSUE_SC) {
28388c2ecf20Sopenharmony_ci		seq_puts(m, "not yet issued commands:\n");
28398c2ecf20Sopenharmony_ci		for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
28408c2ecf20Sopenharmony_ci			get_command(m, ptr);
28418c2ecf20Sopenharmony_ci	} else
28428c2ecf20Sopenharmony_ci		seq_puts(m, "no not yet issued commands\n");
28438c2ecf20Sopenharmony_ci	DO_UNLOCK(flags);
28448c2ecf20Sopenharmony_ci
28458c2ecf20Sopenharmony_ci	if (CURRENT_SC) {
28468c2ecf20Sopenharmony_ci		seq_puts(m, "current command:\n");
28478c2ecf20Sopenharmony_ci		get_command(m, CURRENT_SC);
28488c2ecf20Sopenharmony_ci	} else
28498c2ecf20Sopenharmony_ci		seq_puts(m, "no current command\n");
28508c2ecf20Sopenharmony_ci
28518c2ecf20Sopenharmony_ci	if (DISCONNECTED_SC) {
28528c2ecf20Sopenharmony_ci		seq_puts(m, "disconnected commands:\n");
28538c2ecf20Sopenharmony_ci		for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr))
28548c2ecf20Sopenharmony_ci			get_command(m, ptr);
28558c2ecf20Sopenharmony_ci	} else
28568c2ecf20Sopenharmony_ci		seq_puts(m, "no disconnected commands\n");
28578c2ecf20Sopenharmony_ci
28588c2ecf20Sopenharmony_ci	get_ports(m, shpnt);
28598c2ecf20Sopenharmony_ci
28608c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT)
28618c2ecf20Sopenharmony_ci	seq_printf(m, "statistics:\n"
28628c2ecf20Sopenharmony_ci		"total commands:               %d\n"
28638c2ecf20Sopenharmony_ci		"disconnections:               %d\n"
28648c2ecf20Sopenharmony_ci		"busfree with check condition: %d\n"
28658c2ecf20Sopenharmony_ci		"busfree without old command:  %d\n"
28668c2ecf20Sopenharmony_ci		"busfree without new command:  %d\n"
28678c2ecf20Sopenharmony_ci		"busfree without done command: %d\n"
28688c2ecf20Sopenharmony_ci		"busfree without any action:   %d\n"
28698c2ecf20Sopenharmony_ci		"state      "
28708c2ecf20Sopenharmony_ci		"transitions  "
28718c2ecf20Sopenharmony_ci		"count        "
28728c2ecf20Sopenharmony_ci		"time\n",
28738c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->total_commands,
28748c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->disconnections,
28758c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->busfree_with_check_condition,
28768c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_old_command,
28778c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_new_command,
28788c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_done_command,
28798c2ecf20Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_any_action);
28808c2ecf20Sopenharmony_ci	for(i=0; i<maxstate; i++) {
28818c2ecf20Sopenharmony_ci		seq_printf(m, "%-10s %-12d %-12d %-12ld\n",
28828c2ecf20Sopenharmony_ci			states[i].name,
28838c2ecf20Sopenharmony_ci			HOSTDATA(shpnt)->count_trans[i],
28848c2ecf20Sopenharmony_ci			HOSTDATA(shpnt)->count[i],
28858c2ecf20Sopenharmony_ci			HOSTDATA(shpnt)->time[i]);
28868c2ecf20Sopenharmony_ci	}
28878c2ecf20Sopenharmony_ci#endif
28888c2ecf20Sopenharmony_ci	return 0;
28898c2ecf20Sopenharmony_ci}
28908c2ecf20Sopenharmony_ci
28918c2ecf20Sopenharmony_cistatic int aha152x_adjust_queue(struct scsi_device *device)
28928c2ecf20Sopenharmony_ci{
28938c2ecf20Sopenharmony_ci	blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH);
28948c2ecf20Sopenharmony_ci	return 0;
28958c2ecf20Sopenharmony_ci}
28968c2ecf20Sopenharmony_ci
28978c2ecf20Sopenharmony_cistatic struct scsi_host_template aha152x_driver_template = {
28988c2ecf20Sopenharmony_ci	.module				= THIS_MODULE,
28998c2ecf20Sopenharmony_ci	.name				= AHA152X_REVID,
29008c2ecf20Sopenharmony_ci	.proc_name			= "aha152x",
29018c2ecf20Sopenharmony_ci	.show_info			= aha152x_show_info,
29028c2ecf20Sopenharmony_ci	.write_info			= aha152x_set_info,
29038c2ecf20Sopenharmony_ci	.queuecommand			= aha152x_queue,
29048c2ecf20Sopenharmony_ci	.eh_abort_handler		= aha152x_abort,
29058c2ecf20Sopenharmony_ci	.eh_device_reset_handler	= aha152x_device_reset,
29068c2ecf20Sopenharmony_ci	.eh_bus_reset_handler		= aha152x_bus_reset,
29078c2ecf20Sopenharmony_ci	.bios_param			= aha152x_biosparam,
29088c2ecf20Sopenharmony_ci	.can_queue			= 1,
29098c2ecf20Sopenharmony_ci	.this_id			= 7,
29108c2ecf20Sopenharmony_ci	.sg_tablesize			= SG_ALL,
29118c2ecf20Sopenharmony_ci	.dma_boundary			= PAGE_SIZE - 1,
29128c2ecf20Sopenharmony_ci	.slave_alloc			= aha152x_adjust_queue,
29138c2ecf20Sopenharmony_ci};
29148c2ecf20Sopenharmony_ci
29158c2ecf20Sopenharmony_ci#if !defined(AHA152X_PCMCIA)
29168c2ecf20Sopenharmony_cistatic int setup_count;
29178c2ecf20Sopenharmony_cistatic struct aha152x_setup setup[2];
29188c2ecf20Sopenharmony_ci
29198c2ecf20Sopenharmony_ci/* possible i/o addresses for the AIC-6260; default first */
29208c2ecf20Sopenharmony_cistatic unsigned short ports[] = { 0x340, 0x140 };
29218c2ecf20Sopenharmony_ci
29228c2ecf20Sopenharmony_ci#if !defined(SKIP_BIOSTEST)
29238c2ecf20Sopenharmony_ci/* possible locations for the Adaptec BIOS; defaults first */
29248c2ecf20Sopenharmony_cistatic unsigned int addresses[] =
29258c2ecf20Sopenharmony_ci{
29268c2ecf20Sopenharmony_ci	0xdc000,		/* default first */
29278c2ecf20Sopenharmony_ci	0xc8000,
29288c2ecf20Sopenharmony_ci	0xcc000,
29298c2ecf20Sopenharmony_ci	0xd0000,
29308c2ecf20Sopenharmony_ci	0xd4000,
29318c2ecf20Sopenharmony_ci	0xd8000,
29328c2ecf20Sopenharmony_ci	0xe0000,
29338c2ecf20Sopenharmony_ci	0xeb800,		/* VTech Platinum SMP */
29348c2ecf20Sopenharmony_ci	0xf0000,
29358c2ecf20Sopenharmony_ci};
29368c2ecf20Sopenharmony_ci
29378c2ecf20Sopenharmony_ci/* signatures for various AIC-6[23]60 based controllers.
29388c2ecf20Sopenharmony_ci   The point in detecting signatures is to avoid useless and maybe
29398c2ecf20Sopenharmony_ci   harmful probes on ports. I'm not sure that all listed boards pass
29408c2ecf20Sopenharmony_ci   auto-configuration. For those which fail the BIOS signature is
29418c2ecf20Sopenharmony_ci   obsolete, because user intervention to supply the configuration is
29428c2ecf20Sopenharmony_ci   needed anyway.  May be an information whether or not the BIOS supports
29438c2ecf20Sopenharmony_ci   extended translation could be also useful here. */
29448c2ecf20Sopenharmony_cistatic struct signature {
29458c2ecf20Sopenharmony_ci	unsigned char *signature;
29468c2ecf20Sopenharmony_ci	int sig_offset;
29478c2ecf20Sopenharmony_ci	int sig_length;
29488c2ecf20Sopenharmony_ci} signatures[] =
29498c2ecf20Sopenharmony_ci{
29508c2ecf20Sopenharmony_ci	{ "Adaptec AHA-1520 BIOS",	0x102e, 21 },
29518c2ecf20Sopenharmony_ci		/* Adaptec 152x */
29528c2ecf20Sopenharmony_ci	{ "Adaptec AHA-1520B",		0x000b, 17 },
29538c2ecf20Sopenharmony_ci		/* Adaptec 152x rev B */
29548c2ecf20Sopenharmony_ci	{ "Adaptec AHA-1520B",		0x0026, 17 },
29558c2ecf20Sopenharmony_ci		/* Iomega Jaz Jet ISA (AIC6370Q) */
29568c2ecf20Sopenharmony_ci	{ "Adaptec ASW-B626 BIOS",	0x1029, 21 },
29578c2ecf20Sopenharmony_ci		/* on-board controller */
29588c2ecf20Sopenharmony_ci	{ "Adaptec BIOS: ASW-B626",	0x000f, 22 },
29598c2ecf20Sopenharmony_ci		/* on-board controller */
29608c2ecf20Sopenharmony_ci	{ "Adaptec ASW-B626 S2",	0x2e6c, 19 },
29618c2ecf20Sopenharmony_ci		/* on-board controller */
29628c2ecf20Sopenharmony_ci	{ "Adaptec BIOS:AIC-6360",	0x000c, 21 },
29638c2ecf20Sopenharmony_ci		/* on-board controller */
29648c2ecf20Sopenharmony_ci	{ "ScsiPro SP-360 BIOS",	0x2873, 19 },
29658c2ecf20Sopenharmony_ci		/* ScsiPro-Controller  */
29668c2ecf20Sopenharmony_ci	{ "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 },
29678c2ecf20Sopenharmony_ci		/* Gigabyte Local-Bus-SCSI */
29688c2ecf20Sopenharmony_ci	{ "Adaptec BIOS:AVA-282X",	0x000c, 21 },
29698c2ecf20Sopenharmony_ci		/* Adaptec 282x */
29708c2ecf20Sopenharmony_ci	{ "Adaptec IBM Dock II SCSI",   0x2edd, 24 },
29718c2ecf20Sopenharmony_ci		/* IBM Thinkpad Dock II */
29728c2ecf20Sopenharmony_ci	{ "Adaptec BIOS:AHA-1532P",     0x001c, 22 },
29738c2ecf20Sopenharmony_ci		/* IBM Thinkpad Dock II SCSI */
29748c2ecf20Sopenharmony_ci	{ "DTC3520A Host Adapter BIOS", 0x318a, 26 },
29758c2ecf20Sopenharmony_ci		/* DTC 3520A ISA SCSI */
29768c2ecf20Sopenharmony_ci};
29778c2ecf20Sopenharmony_ci#endif /* !SKIP_BIOSTEST */
29788c2ecf20Sopenharmony_ci
29798c2ecf20Sopenharmony_ci/*
29808c2ecf20Sopenharmony_ci * Test, if port_base is valid.
29818c2ecf20Sopenharmony_ci *
29828c2ecf20Sopenharmony_ci */
29838c2ecf20Sopenharmony_cistatic int aha152x_porttest(int io_port)
29848c2ecf20Sopenharmony_ci{
29858c2ecf20Sopenharmony_ci	int i;
29868c2ecf20Sopenharmony_ci
29878c2ecf20Sopenharmony_ci	SETPORT(io_port + O_DMACNTRL1, 0);	/* reset stack pointer */
29888c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++)
29898c2ecf20Sopenharmony_ci		SETPORT(io_port + O_STACK, i);
29908c2ecf20Sopenharmony_ci
29918c2ecf20Sopenharmony_ci	SETPORT(io_port + O_DMACNTRL1, 0);	/* reset stack pointer */
29928c2ecf20Sopenharmony_ci	for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++)
29938c2ecf20Sopenharmony_ci		;
29948c2ecf20Sopenharmony_ci
29958c2ecf20Sopenharmony_ci	return (i == 16);
29968c2ecf20Sopenharmony_ci}
29978c2ecf20Sopenharmony_ci
29988c2ecf20Sopenharmony_cistatic int tc1550_porttest(int io_port)
29998c2ecf20Sopenharmony_ci{
30008c2ecf20Sopenharmony_ci	int i;
30018c2ecf20Sopenharmony_ci
30028c2ecf20Sopenharmony_ci	SETPORT(io_port + O_TC_DMACNTRL1, 0);	/* reset stack pointer */
30038c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++)
30048c2ecf20Sopenharmony_ci		SETPORT(io_port + O_STACK, i);
30058c2ecf20Sopenharmony_ci
30068c2ecf20Sopenharmony_ci	SETPORT(io_port + O_TC_DMACNTRL1, 0);	/* reset stack pointer */
30078c2ecf20Sopenharmony_ci	for (i = 0; i < 16 && GETPORT(io_port + O_TC_STACK) == i; i++)
30088c2ecf20Sopenharmony_ci		;
30098c2ecf20Sopenharmony_ci
30108c2ecf20Sopenharmony_ci	return (i == 16);
30118c2ecf20Sopenharmony_ci}
30128c2ecf20Sopenharmony_ci
30138c2ecf20Sopenharmony_ci
30148c2ecf20Sopenharmony_cistatic int checksetup(struct aha152x_setup *setup)
30158c2ecf20Sopenharmony_ci{
30168c2ecf20Sopenharmony_ci	int i;
30178c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ports) && (setup->io_port != ports[i]); i++)
30188c2ecf20Sopenharmony_ci		;
30198c2ecf20Sopenharmony_ci
30208c2ecf20Sopenharmony_ci	if (i == ARRAY_SIZE(ports))
30218c2ecf20Sopenharmony_ci		return 0;
30228c2ecf20Sopenharmony_ci
30238c2ecf20Sopenharmony_ci	if (!request_region(setup->io_port, IO_RANGE, "aha152x")) {
30248c2ecf20Sopenharmony_ci		printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup->io_port);
30258c2ecf20Sopenharmony_ci		return 0;
30268c2ecf20Sopenharmony_ci	}
30278c2ecf20Sopenharmony_ci
30288c2ecf20Sopenharmony_ci	if( aha152x_porttest(setup->io_port) ) {
30298c2ecf20Sopenharmony_ci		setup->tc1550=0;
30308c2ecf20Sopenharmony_ci	} else if( tc1550_porttest(setup->io_port) ) {
30318c2ecf20Sopenharmony_ci		setup->tc1550=1;
30328c2ecf20Sopenharmony_ci	} else {
30338c2ecf20Sopenharmony_ci		release_region(setup->io_port, IO_RANGE);
30348c2ecf20Sopenharmony_ci		return 0;
30358c2ecf20Sopenharmony_ci	}
30368c2ecf20Sopenharmony_ci
30378c2ecf20Sopenharmony_ci	release_region(setup->io_port, IO_RANGE);
30388c2ecf20Sopenharmony_ci
30398c2ecf20Sopenharmony_ci	if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX))
30408c2ecf20Sopenharmony_ci		return 0;
30418c2ecf20Sopenharmony_ci
30428c2ecf20Sopenharmony_ci	if ((setup->scsiid < 0) || (setup->scsiid > 7))
30438c2ecf20Sopenharmony_ci		return 0;
30448c2ecf20Sopenharmony_ci
30458c2ecf20Sopenharmony_ci	if ((setup->reconnect < 0) || (setup->reconnect > 1))
30468c2ecf20Sopenharmony_ci		return 0;
30478c2ecf20Sopenharmony_ci
30488c2ecf20Sopenharmony_ci	if ((setup->parity < 0) || (setup->parity > 1))
30498c2ecf20Sopenharmony_ci		return 0;
30508c2ecf20Sopenharmony_ci
30518c2ecf20Sopenharmony_ci	if ((setup->synchronous < 0) || (setup->synchronous > 1))
30528c2ecf20Sopenharmony_ci		return 0;
30538c2ecf20Sopenharmony_ci
30548c2ecf20Sopenharmony_ci	if ((setup->ext_trans < 0) || (setup->ext_trans > 1))
30558c2ecf20Sopenharmony_ci		return 0;
30568c2ecf20Sopenharmony_ci
30578c2ecf20Sopenharmony_ci
30588c2ecf20Sopenharmony_ci	return 1;
30598c2ecf20Sopenharmony_ci}
30608c2ecf20Sopenharmony_ci
30618c2ecf20Sopenharmony_ci
30628c2ecf20Sopenharmony_cistatic int __init aha152x_init(void)
30638c2ecf20Sopenharmony_ci{
30648c2ecf20Sopenharmony_ci	int i, j, ok;
30658c2ecf20Sopenharmony_ci#if defined(AUTOCONF)
30668c2ecf20Sopenharmony_ci	aha152x_config conf;
30678c2ecf20Sopenharmony_ci#endif
30688c2ecf20Sopenharmony_ci#ifdef __ISAPNP__
30698c2ecf20Sopenharmony_ci	struct pnp_dev *dev=NULL, *pnpdev[2] = {NULL, NULL};
30708c2ecf20Sopenharmony_ci#endif
30718c2ecf20Sopenharmony_ci
30728c2ecf20Sopenharmony_ci	if ( setup_count ) {
30738c2ecf20Sopenharmony_ci		printk(KERN_INFO "aha152x: processing commandline: ");
30748c2ecf20Sopenharmony_ci
30758c2ecf20Sopenharmony_ci		for (i = 0; i<setup_count; i++) {
30768c2ecf20Sopenharmony_ci			if (!checksetup(&setup[i])) {
30778c2ecf20Sopenharmony_ci				printk(KERN_ERR "\naha152x: %s\n", setup[i].conf);
30788c2ecf20Sopenharmony_ci				printk(KERN_ERR "aha152x: invalid line\n");
30798c2ecf20Sopenharmony_ci			}
30808c2ecf20Sopenharmony_ci		}
30818c2ecf20Sopenharmony_ci		printk("ok\n");
30828c2ecf20Sopenharmony_ci	}
30838c2ecf20Sopenharmony_ci
30848c2ecf20Sopenharmony_ci#if defined(SETUP0)
30858c2ecf20Sopenharmony_ci	if (setup_count < ARRAY_SIZE(setup)) {
30868c2ecf20Sopenharmony_ci		struct aha152x_setup override = SETUP0;
30878c2ecf20Sopenharmony_ci
30888c2ecf20Sopenharmony_ci		if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
30898c2ecf20Sopenharmony_ci			if (!checksetup(&override)) {
30908c2ecf20Sopenharmony_ci				printk(KERN_ERR "\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
30918c2ecf20Sopenharmony_ci				       override.io_port,
30928c2ecf20Sopenharmony_ci				       override.irq,
30938c2ecf20Sopenharmony_ci				       override.scsiid,
30948c2ecf20Sopenharmony_ci				       override.reconnect,
30958c2ecf20Sopenharmony_ci				       override.parity,
30968c2ecf20Sopenharmony_ci				       override.synchronous,
30978c2ecf20Sopenharmony_ci				       override.delay,
30988c2ecf20Sopenharmony_ci				       override.ext_trans);
30998c2ecf20Sopenharmony_ci			} else
31008c2ecf20Sopenharmony_ci				setup[setup_count++] = override;
31018c2ecf20Sopenharmony_ci		}
31028c2ecf20Sopenharmony_ci	}
31038c2ecf20Sopenharmony_ci#endif
31048c2ecf20Sopenharmony_ci
31058c2ecf20Sopenharmony_ci#if defined(SETUP1)
31068c2ecf20Sopenharmony_ci	if (setup_count < ARRAY_SIZE(setup)) {
31078c2ecf20Sopenharmony_ci		struct aha152x_setup override = SETUP1;
31088c2ecf20Sopenharmony_ci
31098c2ecf20Sopenharmony_ci		if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
31108c2ecf20Sopenharmony_ci			if (!checksetup(&override)) {
31118c2ecf20Sopenharmony_ci				printk(KERN_ERR "\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
31128c2ecf20Sopenharmony_ci				       override.io_port,
31138c2ecf20Sopenharmony_ci				       override.irq,
31148c2ecf20Sopenharmony_ci				       override.scsiid,
31158c2ecf20Sopenharmony_ci				       override.reconnect,
31168c2ecf20Sopenharmony_ci				       override.parity,
31178c2ecf20Sopenharmony_ci				       override.synchronous,
31188c2ecf20Sopenharmony_ci				       override.delay,
31198c2ecf20Sopenharmony_ci				       override.ext_trans);
31208c2ecf20Sopenharmony_ci			} else
31218c2ecf20Sopenharmony_ci				setup[setup_count++] = override;
31228c2ecf20Sopenharmony_ci		}
31238c2ecf20Sopenharmony_ci	}
31248c2ecf20Sopenharmony_ci#endif
31258c2ecf20Sopenharmony_ci
31268c2ecf20Sopenharmony_ci#if defined(MODULE)
31278c2ecf20Sopenharmony_ci	if (setup_count<ARRAY_SIZE(setup) && (aha152x[0]!=0 || io[0]!=0 || irq[0]!=0)) {
31288c2ecf20Sopenharmony_ci		if(aha152x[0]!=0) {
31298c2ecf20Sopenharmony_ci			setup[setup_count].conf        = "";
31308c2ecf20Sopenharmony_ci			setup[setup_count].io_port     = aha152x[0];
31318c2ecf20Sopenharmony_ci			setup[setup_count].irq         = aha152x[1];
31328c2ecf20Sopenharmony_ci			setup[setup_count].scsiid      = aha152x[2];
31338c2ecf20Sopenharmony_ci			setup[setup_count].reconnect   = aha152x[3];
31348c2ecf20Sopenharmony_ci			setup[setup_count].parity      = aha152x[4];
31358c2ecf20Sopenharmony_ci			setup[setup_count].synchronous = aha152x[5];
31368c2ecf20Sopenharmony_ci			setup[setup_count].delay       = aha152x[6];
31378c2ecf20Sopenharmony_ci			setup[setup_count].ext_trans   = aha152x[7];
31388c2ecf20Sopenharmony_ci		} else if (io[0] != 0 || irq[0] != 0) {
31398c2ecf20Sopenharmony_ci			if(io[0]!=0)  setup[setup_count].io_port = io[0];
31408c2ecf20Sopenharmony_ci			if(irq[0]!=0) setup[setup_count].irq     = irq[0];
31418c2ecf20Sopenharmony_ci
31428c2ecf20Sopenharmony_ci			setup[setup_count].scsiid      = scsiid[0];
31438c2ecf20Sopenharmony_ci			setup[setup_count].reconnect   = reconnect[0];
31448c2ecf20Sopenharmony_ci			setup[setup_count].parity      = parity[0];
31458c2ecf20Sopenharmony_ci			setup[setup_count].synchronous = sync[0];
31468c2ecf20Sopenharmony_ci			setup[setup_count].delay       = delay[0];
31478c2ecf20Sopenharmony_ci			setup[setup_count].ext_trans   = exttrans[0];
31488c2ecf20Sopenharmony_ci		}
31498c2ecf20Sopenharmony_ci
31508c2ecf20Sopenharmony_ci		if (checksetup(&setup[setup_count]))
31518c2ecf20Sopenharmony_ci			setup_count++;
31528c2ecf20Sopenharmony_ci		else
31538c2ecf20Sopenharmony_ci			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",
31548c2ecf20Sopenharmony_ci			       setup[setup_count].io_port,
31558c2ecf20Sopenharmony_ci			       setup[setup_count].irq,
31568c2ecf20Sopenharmony_ci			       setup[setup_count].scsiid,
31578c2ecf20Sopenharmony_ci			       setup[setup_count].reconnect,
31588c2ecf20Sopenharmony_ci			       setup[setup_count].parity,
31598c2ecf20Sopenharmony_ci			       setup[setup_count].synchronous,
31608c2ecf20Sopenharmony_ci			       setup[setup_count].delay,
31618c2ecf20Sopenharmony_ci			       setup[setup_count].ext_trans);
31628c2ecf20Sopenharmony_ci	}
31638c2ecf20Sopenharmony_ci
31648c2ecf20Sopenharmony_ci	if (setup_count<ARRAY_SIZE(setup) && (aha152x1[0]!=0 || io[1]!=0 || irq[1]!=0)) {
31658c2ecf20Sopenharmony_ci		if(aha152x1[0]!=0) {
31668c2ecf20Sopenharmony_ci			setup[setup_count].conf        = "";
31678c2ecf20Sopenharmony_ci			setup[setup_count].io_port     = aha152x1[0];
31688c2ecf20Sopenharmony_ci			setup[setup_count].irq         = aha152x1[1];
31698c2ecf20Sopenharmony_ci			setup[setup_count].scsiid      = aha152x1[2];
31708c2ecf20Sopenharmony_ci			setup[setup_count].reconnect   = aha152x1[3];
31718c2ecf20Sopenharmony_ci			setup[setup_count].parity      = aha152x1[4];
31728c2ecf20Sopenharmony_ci			setup[setup_count].synchronous = aha152x1[5];
31738c2ecf20Sopenharmony_ci			setup[setup_count].delay       = aha152x1[6];
31748c2ecf20Sopenharmony_ci			setup[setup_count].ext_trans   = aha152x1[7];
31758c2ecf20Sopenharmony_ci		} else if (io[1] != 0 || irq[1] != 0) {
31768c2ecf20Sopenharmony_ci			if(io[1]!=0)  setup[setup_count].io_port = io[1];
31778c2ecf20Sopenharmony_ci			if(irq[1]!=0) setup[setup_count].irq     = irq[1];
31788c2ecf20Sopenharmony_ci
31798c2ecf20Sopenharmony_ci			setup[setup_count].scsiid      = scsiid[1];
31808c2ecf20Sopenharmony_ci			setup[setup_count].reconnect   = reconnect[1];
31818c2ecf20Sopenharmony_ci			setup[setup_count].parity      = parity[1];
31828c2ecf20Sopenharmony_ci			setup[setup_count].synchronous = sync[1];
31838c2ecf20Sopenharmony_ci			setup[setup_count].delay       = delay[1];
31848c2ecf20Sopenharmony_ci			setup[setup_count].ext_trans   = exttrans[1];
31858c2ecf20Sopenharmony_ci		}
31868c2ecf20Sopenharmony_ci		if (checksetup(&setup[setup_count]))
31878c2ecf20Sopenharmony_ci			setup_count++;
31888c2ecf20Sopenharmony_ci		else
31898c2ecf20Sopenharmony_ci			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",
31908c2ecf20Sopenharmony_ci			       setup[setup_count].io_port,
31918c2ecf20Sopenharmony_ci			       setup[setup_count].irq,
31928c2ecf20Sopenharmony_ci			       setup[setup_count].scsiid,
31938c2ecf20Sopenharmony_ci			       setup[setup_count].reconnect,
31948c2ecf20Sopenharmony_ci			       setup[setup_count].parity,
31958c2ecf20Sopenharmony_ci			       setup[setup_count].synchronous,
31968c2ecf20Sopenharmony_ci			       setup[setup_count].delay,
31978c2ecf20Sopenharmony_ci			       setup[setup_count].ext_trans);
31988c2ecf20Sopenharmony_ci	}
31998c2ecf20Sopenharmony_ci#endif
32008c2ecf20Sopenharmony_ci
32018c2ecf20Sopenharmony_ci#ifdef __ISAPNP__
32028c2ecf20Sopenharmony_ci	for(i=0; setup_count<ARRAY_SIZE(setup) && id_table[i].vendor; i++) {
32038c2ecf20Sopenharmony_ci		while ( setup_count<ARRAY_SIZE(setup) &&
32048c2ecf20Sopenharmony_ci			(dev=pnp_find_dev(NULL, id_table[i].vendor, id_table[i].function, dev)) ) {
32058c2ecf20Sopenharmony_ci			if (pnp_device_attach(dev) < 0)
32068c2ecf20Sopenharmony_ci				continue;
32078c2ecf20Sopenharmony_ci
32088c2ecf20Sopenharmony_ci			if (pnp_activate_dev(dev) < 0) {
32098c2ecf20Sopenharmony_ci				pnp_device_detach(dev);
32108c2ecf20Sopenharmony_ci				continue;
32118c2ecf20Sopenharmony_ci			}
32128c2ecf20Sopenharmony_ci
32138c2ecf20Sopenharmony_ci			if (!pnp_port_valid(dev, 0)) {
32148c2ecf20Sopenharmony_ci				pnp_device_detach(dev);
32158c2ecf20Sopenharmony_ci				continue;
32168c2ecf20Sopenharmony_ci			}
32178c2ecf20Sopenharmony_ci
32188c2ecf20Sopenharmony_ci			if (setup_count==1 && pnp_port_start(dev, 0)==setup[0].io_port) {
32198c2ecf20Sopenharmony_ci				pnp_device_detach(dev);
32208c2ecf20Sopenharmony_ci				continue;
32218c2ecf20Sopenharmony_ci			}
32228c2ecf20Sopenharmony_ci
32238c2ecf20Sopenharmony_ci			setup[setup_count].io_port     = pnp_port_start(dev, 0);
32248c2ecf20Sopenharmony_ci			setup[setup_count].irq         = pnp_irq(dev, 0);
32258c2ecf20Sopenharmony_ci			setup[setup_count].scsiid      = 7;
32268c2ecf20Sopenharmony_ci			setup[setup_count].reconnect   = 1;
32278c2ecf20Sopenharmony_ci			setup[setup_count].parity      = 1;
32288c2ecf20Sopenharmony_ci			setup[setup_count].synchronous = 1;
32298c2ecf20Sopenharmony_ci			setup[setup_count].delay       = DELAY_DEFAULT;
32308c2ecf20Sopenharmony_ci			setup[setup_count].ext_trans   = 0;
32318c2ecf20Sopenharmony_ci#if defined(__ISAPNP__)
32328c2ecf20Sopenharmony_ci			pnpdev[setup_count]            = dev;
32338c2ecf20Sopenharmony_ci#endif
32348c2ecf20Sopenharmony_ci			printk (KERN_INFO
32358c2ecf20Sopenharmony_ci				"aha152x: found ISAPnP adapter at io=0x%03x, irq=%d\n",
32368c2ecf20Sopenharmony_ci				setup[setup_count].io_port, setup[setup_count].irq);
32378c2ecf20Sopenharmony_ci			setup_count++;
32388c2ecf20Sopenharmony_ci		}
32398c2ecf20Sopenharmony_ci	}
32408c2ecf20Sopenharmony_ci#endif
32418c2ecf20Sopenharmony_ci
32428c2ecf20Sopenharmony_ci#if defined(AUTOCONF)
32438c2ecf20Sopenharmony_ci	if (setup_count<ARRAY_SIZE(setup)) {
32448c2ecf20Sopenharmony_ci#if !defined(SKIP_BIOSTEST)
32458c2ecf20Sopenharmony_ci		ok = 0;
32468c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(addresses) && !ok; i++) {
32478c2ecf20Sopenharmony_ci			void __iomem *p = ioremap(addresses[i], 0x4000);
32488c2ecf20Sopenharmony_ci			if (!p)
32498c2ecf20Sopenharmony_ci				continue;
32508c2ecf20Sopenharmony_ci			for (j = 0; j<ARRAY_SIZE(signatures) && !ok; j++)
32518c2ecf20Sopenharmony_ci				ok = check_signature(p + signatures[j].sig_offset,
32528c2ecf20Sopenharmony_ci								signatures[j].signature, signatures[j].sig_length);
32538c2ecf20Sopenharmony_ci			iounmap(p);
32548c2ecf20Sopenharmony_ci		}
32558c2ecf20Sopenharmony_ci		if (!ok && setup_count == 0)
32568c2ecf20Sopenharmony_ci			return -ENODEV;
32578c2ecf20Sopenharmony_ci
32588c2ecf20Sopenharmony_ci		printk(KERN_INFO "aha152x: BIOS test: passed, ");
32598c2ecf20Sopenharmony_ci#else
32608c2ecf20Sopenharmony_ci		printk(KERN_INFO "aha152x: ");
32618c2ecf20Sopenharmony_ci#endif				/* !SKIP_BIOSTEST */
32628c2ecf20Sopenharmony_ci
32638c2ecf20Sopenharmony_ci		ok = 0;
32648c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(ports) && setup_count < 2; i++) {
32658c2ecf20Sopenharmony_ci			if ((setup_count == 1) && (setup[0].io_port == ports[i]))
32668c2ecf20Sopenharmony_ci				continue;
32678c2ecf20Sopenharmony_ci
32688c2ecf20Sopenharmony_ci			if (!request_region(ports[i], IO_RANGE, "aha152x")) {
32698c2ecf20Sopenharmony_ci				printk(KERN_ERR "aha152x: io port 0x%x busy.\n", ports[i]);
32708c2ecf20Sopenharmony_ci				continue;
32718c2ecf20Sopenharmony_ci			}
32728c2ecf20Sopenharmony_ci
32738c2ecf20Sopenharmony_ci			if (aha152x_porttest(ports[i])) {
32748c2ecf20Sopenharmony_ci				setup[setup_count].tc1550  = 0;
32758c2ecf20Sopenharmony_ci
32768c2ecf20Sopenharmony_ci				conf.cf_port =
32778c2ecf20Sopenharmony_ci				    (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB);
32788c2ecf20Sopenharmony_ci			} else if (tc1550_porttest(ports[i])) {
32798c2ecf20Sopenharmony_ci				setup[setup_count].tc1550  = 1;
32808c2ecf20Sopenharmony_ci
32818c2ecf20Sopenharmony_ci				conf.cf_port =
32828c2ecf20Sopenharmony_ci				    (GETPORT(ports[i] + O_TC_PORTA) << 8) + GETPORT(ports[i] + O_TC_PORTB);
32838c2ecf20Sopenharmony_ci			} else {
32848c2ecf20Sopenharmony_ci				release_region(ports[i], IO_RANGE);
32858c2ecf20Sopenharmony_ci				continue;
32868c2ecf20Sopenharmony_ci			}
32878c2ecf20Sopenharmony_ci
32888c2ecf20Sopenharmony_ci			release_region(ports[i], IO_RANGE);
32898c2ecf20Sopenharmony_ci
32908c2ecf20Sopenharmony_ci			ok++;
32918c2ecf20Sopenharmony_ci			setup[setup_count].io_port = ports[i];
32928c2ecf20Sopenharmony_ci			setup[setup_count].irq = IRQ_MIN + conf.cf_irq;
32938c2ecf20Sopenharmony_ci			setup[setup_count].scsiid = conf.cf_id;
32948c2ecf20Sopenharmony_ci			setup[setup_count].reconnect = conf.cf_tardisc;
32958c2ecf20Sopenharmony_ci			setup[setup_count].parity = !conf.cf_parity;
32968c2ecf20Sopenharmony_ci			setup[setup_count].synchronous = conf.cf_syncneg;
32978c2ecf20Sopenharmony_ci			setup[setup_count].delay = DELAY_DEFAULT;
32988c2ecf20Sopenharmony_ci			setup[setup_count].ext_trans = 0;
32998c2ecf20Sopenharmony_ci			setup_count++;
33008c2ecf20Sopenharmony_ci
33018c2ecf20Sopenharmony_ci		}
33028c2ecf20Sopenharmony_ci
33038c2ecf20Sopenharmony_ci		if (ok)
33048c2ecf20Sopenharmony_ci			printk("auto configuration: ok, ");
33058c2ecf20Sopenharmony_ci	}
33068c2ecf20Sopenharmony_ci#endif
33078c2ecf20Sopenharmony_ci
33088c2ecf20Sopenharmony_ci	printk("%d controller(s) configured\n", setup_count);
33098c2ecf20Sopenharmony_ci
33108c2ecf20Sopenharmony_ci	for (i=0; i<setup_count; i++) {
33118c2ecf20Sopenharmony_ci		if ( request_region(setup[i].io_port, IO_RANGE, "aha152x") ) {
33128c2ecf20Sopenharmony_ci			struct Scsi_Host *shpnt = aha152x_probe_one(&setup[i]);
33138c2ecf20Sopenharmony_ci
33148c2ecf20Sopenharmony_ci			if( !shpnt ) {
33158c2ecf20Sopenharmony_ci				release_region(setup[i].io_port, IO_RANGE);
33168c2ecf20Sopenharmony_ci#if defined(__ISAPNP__)
33178c2ecf20Sopenharmony_ci			} else if( pnpdev[i] ) {
33188c2ecf20Sopenharmony_ci				HOSTDATA(shpnt)->pnpdev=pnpdev[i];
33198c2ecf20Sopenharmony_ci				pnpdev[i]=NULL;
33208c2ecf20Sopenharmony_ci#endif
33218c2ecf20Sopenharmony_ci			}
33228c2ecf20Sopenharmony_ci		} else {
33238c2ecf20Sopenharmony_ci			printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup[i].io_port);
33248c2ecf20Sopenharmony_ci		}
33258c2ecf20Sopenharmony_ci
33268c2ecf20Sopenharmony_ci#if defined(__ISAPNP__)
33278c2ecf20Sopenharmony_ci		if( pnpdev[i] )
33288c2ecf20Sopenharmony_ci			pnp_device_detach(pnpdev[i]);
33298c2ecf20Sopenharmony_ci#endif
33308c2ecf20Sopenharmony_ci	}
33318c2ecf20Sopenharmony_ci
33328c2ecf20Sopenharmony_ci	return 0;
33338c2ecf20Sopenharmony_ci}
33348c2ecf20Sopenharmony_ci
33358c2ecf20Sopenharmony_cistatic void __exit aha152x_exit(void)
33368c2ecf20Sopenharmony_ci{
33378c2ecf20Sopenharmony_ci	struct aha152x_hostdata *hd, *tmp;
33388c2ecf20Sopenharmony_ci
33398c2ecf20Sopenharmony_ci	list_for_each_entry_safe(hd, tmp, &aha152x_host_list, host_list) {
33408c2ecf20Sopenharmony_ci		struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
33418c2ecf20Sopenharmony_ci
33428c2ecf20Sopenharmony_ci		aha152x_release(shost);
33438c2ecf20Sopenharmony_ci	}
33448c2ecf20Sopenharmony_ci}
33458c2ecf20Sopenharmony_ci
33468c2ecf20Sopenharmony_cimodule_init(aha152x_init);
33478c2ecf20Sopenharmony_cimodule_exit(aha152x_exit);
33488c2ecf20Sopenharmony_ci
33498c2ecf20Sopenharmony_ci#if !defined(MODULE)
33508c2ecf20Sopenharmony_cistatic int __init aha152x_setup(char *str)
33518c2ecf20Sopenharmony_ci{
33528c2ecf20Sopenharmony_ci	int ints[10];
33538c2ecf20Sopenharmony_ci
33548c2ecf20Sopenharmony_ci	get_options(str, ARRAY_SIZE(ints), ints);
33558c2ecf20Sopenharmony_ci
33568c2ecf20Sopenharmony_ci	if(setup_count>=ARRAY_SIZE(setup)) {
33578c2ecf20Sopenharmony_ci		printk(KERN_ERR "aha152x: you can only configure up to two controllers\n");
33588c2ecf20Sopenharmony_ci		return 1;
33598c2ecf20Sopenharmony_ci	}
33608c2ecf20Sopenharmony_ci
33618c2ecf20Sopenharmony_ci	setup[setup_count].conf        = str;
33628c2ecf20Sopenharmony_ci	setup[setup_count].io_port     = ints[0] >= 1 ? ints[1] : 0x340;
33638c2ecf20Sopenharmony_ci	setup[setup_count].irq         = ints[0] >= 2 ? ints[2] : 11;
33648c2ecf20Sopenharmony_ci	setup[setup_count].scsiid      = ints[0] >= 3 ? ints[3] : 7;
33658c2ecf20Sopenharmony_ci	setup[setup_count].reconnect   = ints[0] >= 4 ? ints[4] : 1;
33668c2ecf20Sopenharmony_ci	setup[setup_count].parity      = ints[0] >= 5 ? ints[5] : 1;
33678c2ecf20Sopenharmony_ci	setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 1;
33688c2ecf20Sopenharmony_ci	setup[setup_count].delay       = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT;
33698c2ecf20Sopenharmony_ci	setup[setup_count].ext_trans   = ints[0] >= 8 ? ints[8] : 0;
33708c2ecf20Sopenharmony_ci	if (ints[0] > 8)
33718c2ecf20Sopenharmony_ci		printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
33728c2ecf20Sopenharmony_ci		       "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n");
33738c2ecf20Sopenharmony_ci	else
33748c2ecf20Sopenharmony_ci		setup_count++;
33758c2ecf20Sopenharmony_ci
33768c2ecf20Sopenharmony_ci	return 1;
33778c2ecf20Sopenharmony_ci}
33788c2ecf20Sopenharmony_ci__setup("aha152x=", aha152x_setup);
33798c2ecf20Sopenharmony_ci#endif
33808c2ecf20Sopenharmony_ci
33818c2ecf20Sopenharmony_ci#endif /* !AHA152X_PCMCIA */
3382