162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* aha152x.c -- Adaptec AHA-152x driver
362306a36Sopenharmony_ci * Author: Jürgen E. Fischer, fischer@norbit.de
462306a36Sopenharmony_ci * Copyright 1993-2004 Jürgen E. Fischer
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * $Id: aha152x.c,v 2.7 2004/01/24 11:42:59 fischer Exp $
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * $Log: aha152x.c,v $
962306a36Sopenharmony_ci * Revision 2.7  2004/01/24 11:42:59  fischer
1062306a36Sopenharmony_ci * - gather code that is not used by PCMCIA at the end
1162306a36Sopenharmony_ci * - move request_region for !PCMCIA case to detection
1262306a36Sopenharmony_ci * - migration to new scsi host api (remove legacy code)
1362306a36Sopenharmony_ci * - free host scribble before scsi_done
1462306a36Sopenharmony_ci * - fix error handling
1562306a36Sopenharmony_ci * - one isapnp device added to id_table
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * Revision 2.6  2003/10/30 20:52:47  fischer
1862306a36Sopenharmony_ci * - interfaces changes for kernel 2.6
1962306a36Sopenharmony_ci * - aha152x_probe_one introduced for pcmcia stub
2062306a36Sopenharmony_ci * - fixed pnpdev handling
2162306a36Sopenharmony_ci * - instead of allocation a new one, reuse command for request sense after check condition and reset
2262306a36Sopenharmony_ci * - fixes race in is_complete
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * Revision 2.5  2002/04/14 11:24:53  fischer
2562306a36Sopenharmony_ci * - isapnp support
2662306a36Sopenharmony_ci * - abort fixed
2762306a36Sopenharmony_ci * - 2.5 support
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * Revision 2.4  2000/12/16 12:53:56  fischer
3062306a36Sopenharmony_ci * - allow REQUEST SENSE to be queued
3162306a36Sopenharmony_ci * - handle shared PCI interrupts
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * Revision 2.3  2000/11/04 16:40:26  fischer
3462306a36Sopenharmony_ci * - handle data overruns
3562306a36Sopenharmony_ci * - extend timeout for data phases
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci * Revision 2.2  2000/08/08 19:54:53  fischer
3862306a36Sopenharmony_ci * - minor changes
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * Revision 2.1  2000/05/17 16:23:17  fischer
4162306a36Sopenharmony_ci * - signature update
4262306a36Sopenharmony_ci * - fix for data out w/o scatter gather
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * Revision 2.0  1999/12/25 15:07:32  fischer
4562306a36Sopenharmony_ci * - interrupt routine completly reworked
4662306a36Sopenharmony_ci * - basic support for new eh code
4762306a36Sopenharmony_ci *
4862306a36Sopenharmony_ci * Revision 1.21  1999/11/10 23:46:36  fischer
4962306a36Sopenharmony_ci * - default to synchronous operation
5062306a36Sopenharmony_ci * - synchronous negotiation fixed
5162306a36Sopenharmony_ci * - added timeout to loops
5262306a36Sopenharmony_ci * - debugging output can be controlled through procfs
5362306a36Sopenharmony_ci *
5462306a36Sopenharmony_ci * Revision 1.20  1999/11/07 18:37:31  fischer
5562306a36Sopenharmony_ci * - synchronous operation works
5662306a36Sopenharmony_ci * - resid support for sg driver
5762306a36Sopenharmony_ci *
5862306a36Sopenharmony_ci * Revision 1.19  1999/11/02 22:39:59  fischer
5962306a36Sopenharmony_ci * - moved leading comments to README.aha152x
6062306a36Sopenharmony_ci * - new additional module parameters
6162306a36Sopenharmony_ci * - updates for 2.3
6262306a36Sopenharmony_ci * - support for the Tripace TC1550 controller
6362306a36Sopenharmony_ci * - interrupt handling changed
6462306a36Sopenharmony_ci *
6562306a36Sopenharmony_ci * Revision 1.18  1996/09/07 20:10:40  fischer
6662306a36Sopenharmony_ci * - fixed can_queue handling (multiple outstanding commands working again)
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci * Revision 1.17  1996/08/17 16:05:14  fischer
6962306a36Sopenharmony_ci * - biosparam improved
7062306a36Sopenharmony_ci * - interrupt verification
7162306a36Sopenharmony_ci * - updated documentation
7262306a36Sopenharmony_ci * - cleanups
7362306a36Sopenharmony_ci *
7462306a36Sopenharmony_ci * Revision 1.16  1996/06/09 00:04:56  root
7562306a36Sopenharmony_ci * - added configuration symbols for insmod (aha152x/aha152x1)
7662306a36Sopenharmony_ci *
7762306a36Sopenharmony_ci * Revision 1.15  1996/04/30 14:52:06  fischer
7862306a36Sopenharmony_ci * - proc info fixed
7962306a36Sopenharmony_ci * - support for extended translation for >1GB disks
8062306a36Sopenharmony_ci *
8162306a36Sopenharmony_ci * Revision 1.14  1996/01/17  15:11:20  fischer
8262306a36Sopenharmony_ci * - fixed lockup in MESSAGE IN phase after reconnection
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * Revision 1.13  1996/01/09  02:15:53  fischer
8562306a36Sopenharmony_ci * - some cleanups
8662306a36Sopenharmony_ci * - moved request_irq behind controller initialization
8762306a36Sopenharmony_ci *   (to avoid spurious interrupts)
8862306a36Sopenharmony_ci *
8962306a36Sopenharmony_ci * Revision 1.12  1995/12/16  12:26:07  fischer
9062306a36Sopenharmony_ci * - barrier()s added
9162306a36Sopenharmony_ci * - configurable RESET delay added
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci * Revision 1.11  1995/12/06  21:18:35  fischer
9462306a36Sopenharmony_ci * - some minor updates
9562306a36Sopenharmony_ci *
9662306a36Sopenharmony_ci * Revision 1.10  1995/07/22  19:18:45  fischer
9762306a36Sopenharmony_ci * - support for 2 controllers
9862306a36Sopenharmony_ci * - started synchronous data transfers (not working yet)
9962306a36Sopenharmony_ci *
10062306a36Sopenharmony_ci * Revision 1.9  1995/03/18  09:20:24  root
10162306a36Sopenharmony_ci * - patches for PCMCIA and modules
10262306a36Sopenharmony_ci *
10362306a36Sopenharmony_ci * Revision 1.8  1995/01/21  22:07:19  root
10462306a36Sopenharmony_ci * - snarf_region => request_region
10562306a36Sopenharmony_ci * - aha152x_intr interface change
10662306a36Sopenharmony_ci *
10762306a36Sopenharmony_ci * Revision 1.7  1995/01/02  23:19:36  root
10862306a36Sopenharmony_ci * - updated COMMAND_SIZE to cmd_len
10962306a36Sopenharmony_ci * - changed sti() to restore_flags()
11062306a36Sopenharmony_ci * - fixed some #ifdef which generated warnings
11162306a36Sopenharmony_ci *
11262306a36Sopenharmony_ci * Revision 1.6  1994/11/24  20:35:27  root
11362306a36Sopenharmony_ci * - problem with odd number of bytes in fifo fixed
11462306a36Sopenharmony_ci *
11562306a36Sopenharmony_ci * Revision 1.5  1994/10/30  14:39:56  root
11662306a36Sopenharmony_ci * - abort code fixed
11762306a36Sopenharmony_ci * - debugging improved
11862306a36Sopenharmony_ci *
11962306a36Sopenharmony_ci * Revision 1.4  1994/09/12  11:33:01  root
12062306a36Sopenharmony_ci * - irqaction to request_irq
12162306a36Sopenharmony_ci * - abortion updated
12262306a36Sopenharmony_ci *
12362306a36Sopenharmony_ci * Revision 1.3  1994/08/04  13:53:05  root
12462306a36Sopenharmony_ci * - updates for mid-level-driver changes
12562306a36Sopenharmony_ci * - accept unexpected BUSFREE phase as error condition
12662306a36Sopenharmony_ci * - parity check now configurable
12762306a36Sopenharmony_ci *
12862306a36Sopenharmony_ci * Revision 1.2  1994/07/03  12:56:36  root
12962306a36Sopenharmony_ci * - cleaned up debugging code
13062306a36Sopenharmony_ci * - more tweaking on reset delays
13162306a36Sopenharmony_ci * - updated abort/reset code (pretty untested...)
13262306a36Sopenharmony_ci *
13362306a36Sopenharmony_ci * Revision 1.1  1994/05/28  21:18:49  root
13462306a36Sopenharmony_ci * - update for mid-level interface change (abort-reset)
13562306a36Sopenharmony_ci * - delays after resets adjusted for some slow devices
13662306a36Sopenharmony_ci *
13762306a36Sopenharmony_ci * Revision 1.0  1994/03/25  12:52:00  root
13862306a36Sopenharmony_ci * - Fixed "more data than expected" problem
13962306a36Sopenharmony_ci * - added new BIOS signatures
14062306a36Sopenharmony_ci *
14162306a36Sopenharmony_ci * Revision 0.102  1994/01/31  20:44:12  root
14262306a36Sopenharmony_ci * - minor changes in insw/outsw handling
14362306a36Sopenharmony_ci *
14462306a36Sopenharmony_ci * Revision 0.101  1993/12/13  01:16:27  root
14562306a36Sopenharmony_ci * - fixed STATUS phase (non-GOOD stati were dropped sometimes;
14662306a36Sopenharmony_ci *   fixes problems with CD-ROM sector size detection & media change)
14762306a36Sopenharmony_ci *
14862306a36Sopenharmony_ci * Revision 0.100  1993/12/10  16:58:47  root
14962306a36Sopenharmony_ci * - fix for unsuccessful selections in case of non-continuous id assignments
15062306a36Sopenharmony_ci *   on the scsi bus.
15162306a36Sopenharmony_ci *
15262306a36Sopenharmony_ci * Revision 0.99  1993/10/24  16:19:59  root
15362306a36Sopenharmony_ci * - fixed DATA IN (rare read errors gone)
15462306a36Sopenharmony_ci *
15562306a36Sopenharmony_ci * Revision 0.98  1993/10/17  12:54:44  root
15662306a36Sopenharmony_ci * - fixed some recent fixes (shame on me)
15762306a36Sopenharmony_ci * - moved initialization of scratch area to aha152x_queue
15862306a36Sopenharmony_ci *
15962306a36Sopenharmony_ci * Revision 0.97  1993/10/09  18:53:53  root
16062306a36Sopenharmony_ci * - DATA IN fixed. Rarely left data in the fifo.
16162306a36Sopenharmony_ci *
16262306a36Sopenharmony_ci * Revision 0.96  1993/10/03  00:53:59  root
16362306a36Sopenharmony_ci * - minor changes on DATA IN
16462306a36Sopenharmony_ci *
16562306a36Sopenharmony_ci * Revision 0.95  1993/09/24  10:36:01  root
16662306a36Sopenharmony_ci * - change handling of MSGI after reselection
16762306a36Sopenharmony_ci * - fixed sti/cli
16862306a36Sopenharmony_ci * - minor changes
16962306a36Sopenharmony_ci *
17062306a36Sopenharmony_ci * Revision 0.94  1993/09/18  14:08:22  root
17162306a36Sopenharmony_ci * - fixed bug in multiple outstanding command code
17262306a36Sopenharmony_ci * - changed detection
17362306a36Sopenharmony_ci * - support for kernel command line configuration
17462306a36Sopenharmony_ci * - reset corrected
17562306a36Sopenharmony_ci * - changed message handling
17662306a36Sopenharmony_ci *
17762306a36Sopenharmony_ci * Revision 0.93  1993/09/15  20:41:19  root
17862306a36Sopenharmony_ci * - fixed bugs with multiple outstanding commands
17962306a36Sopenharmony_ci *
18062306a36Sopenharmony_ci * Revision 0.92  1993/09/13  02:46:33  root
18162306a36Sopenharmony_ci * - multiple outstanding commands work (no problems with IBM drive)
18262306a36Sopenharmony_ci *
18362306a36Sopenharmony_ci * Revision 0.91  1993/09/12  20:51:46  root
18462306a36Sopenharmony_ci * added multiple outstanding commands
18562306a36Sopenharmony_ci * (some problem with this $%&? IBM device remain)
18662306a36Sopenharmony_ci *
18762306a36Sopenharmony_ci * Revision 0.9  1993/09/12  11:11:22  root
18862306a36Sopenharmony_ci * - corrected auto-configuration
18962306a36Sopenharmony_ci * - changed the auto-configuration (added some '#define's)
19062306a36Sopenharmony_ci * - added support for dis-/reconnection
19162306a36Sopenharmony_ci *
19262306a36Sopenharmony_ci * Revision 0.8  1993/09/06  23:09:39  root
19362306a36Sopenharmony_ci * - added support for the drive activity light
19462306a36Sopenharmony_ci * - minor changes
19562306a36Sopenharmony_ci *
19662306a36Sopenharmony_ci * Revision 0.7  1993/09/05  14:30:15  root
19762306a36Sopenharmony_ci * - improved phase detection
19862306a36Sopenharmony_ci * - now using the new snarf_region code of 0.99pl13
19962306a36Sopenharmony_ci *
20062306a36Sopenharmony_ci * Revision 0.6  1993/09/02  11:01:38  root
20162306a36Sopenharmony_ci * first public release; added some signatures and biosparam()
20262306a36Sopenharmony_ci *
20362306a36Sopenharmony_ci * Revision 0.5  1993/08/30  10:23:30  root
20462306a36Sopenharmony_ci * fixed timing problems with my IBM drive
20562306a36Sopenharmony_ci *
20662306a36Sopenharmony_ci * Revision 0.4  1993/08/29  14:06:52  root
20762306a36Sopenharmony_ci * fixed some problems with timeouts due incomplete commands
20862306a36Sopenharmony_ci *
20962306a36Sopenharmony_ci * Revision 0.3  1993/08/28  15:55:03  root
21062306a36Sopenharmony_ci * writing data works too.  mounted and worked on a dos partition
21162306a36Sopenharmony_ci *
21262306a36Sopenharmony_ci * Revision 0.2  1993/08/27  22:42:07  root
21362306a36Sopenharmony_ci * reading data works.  Mounted a msdos partition.
21462306a36Sopenharmony_ci *
21562306a36Sopenharmony_ci * Revision 0.1  1993/08/25  13:38:30  root
21662306a36Sopenharmony_ci * first "damn thing doesn't work" version
21762306a36Sopenharmony_ci *
21862306a36Sopenharmony_ci * Revision 0.0  1993/08/14  19:54:25  root
21962306a36Sopenharmony_ci * empty function bodies; detect() works.
22062306a36Sopenharmony_ci *
22162306a36Sopenharmony_ci **************************************************************************
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci see Documentation/scsi/aha152x.rst for configuration details
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci **************************************************************************/
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci#include <linux/module.h>
22862306a36Sopenharmony_ci#include <asm/irq.h>
22962306a36Sopenharmony_ci#include <linux/io.h>
23062306a36Sopenharmony_ci#include <linux/blkdev.h>
23162306a36Sopenharmony_ci#include <linux/completion.h>
23262306a36Sopenharmony_ci#include <linux/errno.h>
23362306a36Sopenharmony_ci#include <linux/string.h>
23462306a36Sopenharmony_ci#include <linux/wait.h>
23562306a36Sopenharmony_ci#include <linux/ioport.h>
23662306a36Sopenharmony_ci#include <linux/delay.h>
23762306a36Sopenharmony_ci#include <linux/proc_fs.h>
23862306a36Sopenharmony_ci#include <linux/interrupt.h>
23962306a36Sopenharmony_ci#include <linux/init.h>
24062306a36Sopenharmony_ci#include <linux/kernel.h>
24162306a36Sopenharmony_ci#include <linux/isapnp.h>
24262306a36Sopenharmony_ci#include <linux/spinlock.h>
24362306a36Sopenharmony_ci#include <linux/workqueue.h>
24462306a36Sopenharmony_ci#include <linux/list.h>
24562306a36Sopenharmony_ci#include <linux/slab.h>
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci#include <scsi/scsi.h>
24862306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h>
24962306a36Sopenharmony_ci#include <scsi/scsi_dbg.h>
25062306a36Sopenharmony_ci#include <scsi/scsi_device.h>
25162306a36Sopenharmony_ci#include <scsi/scsi_eh.h>
25262306a36Sopenharmony_ci#include <scsi/scsi_host.h>
25362306a36Sopenharmony_ci#include <scsi/scsi_tcq.h>
25462306a36Sopenharmony_ci#include <scsi/scsi_transport_spi.h>
25562306a36Sopenharmony_ci#include <scsi/scsicam.h>
25662306a36Sopenharmony_ci#include "aha152x.h"
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic LIST_HEAD(aha152x_host_list);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/* DEFINES */
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci/* For PCMCIA cards, always use AUTOCONF */
26462306a36Sopenharmony_ci#if defined(AHA152X_PCMCIA) || defined(MODULE)
26562306a36Sopenharmony_ci#if !defined(AUTOCONF)
26662306a36Sopenharmony_ci#define AUTOCONF
26762306a36Sopenharmony_ci#endif
26862306a36Sopenharmony_ci#endif
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci#if !defined(AUTOCONF) && !defined(SETUP0)
27162306a36Sopenharmony_ci#error define AUTOCONF or SETUP0
27262306a36Sopenharmony_ci#endif
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci#define	DO_LOCK(flags)		spin_lock_irqsave(&QLOCK,flags)
27562306a36Sopenharmony_ci#define	DO_UNLOCK(flags)	spin_unlock_irqrestore(&QLOCK,flags)
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci#define LEAD		"(scsi%d:%d:%d) "
27862306a36Sopenharmony_ci#define INFO_LEAD	KERN_INFO	LEAD
27962306a36Sopenharmony_ci#define CMDINFO(cmd) \
28062306a36Sopenharmony_ci			(cmd) ? ((cmd)->device->host->host_no) : -1, \
28162306a36Sopenharmony_ci                        (cmd) ? ((cmd)->device->id & 0x0f) : -1, \
28262306a36Sopenharmony_ci			(cmd) ? ((u8)(cmd)->device->lun & 0x07) : -1
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic inline void
28562306a36Sopenharmony_ciCMD_INC_RESID(struct scsi_cmnd *cmd, int inc)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	scsi_set_resid(cmd, scsi_get_resid(cmd) + inc);
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci#define DELAY_DEFAULT 1000
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci#if defined(AHA152X_PCMCIA)
29362306a36Sopenharmony_ci#define IRQ_MIN 0
29462306a36Sopenharmony_ci#define IRQ_MAX 16
29562306a36Sopenharmony_ci#else
29662306a36Sopenharmony_ci#define IRQ_MIN 9
29762306a36Sopenharmony_ci#if defined(__PPC)
29862306a36Sopenharmony_ci#define IRQ_MAX (nr_irqs-1)
29962306a36Sopenharmony_ci#else
30062306a36Sopenharmony_ci#define IRQ_MAX 12
30162306a36Sopenharmony_ci#endif
30262306a36Sopenharmony_ci#endif
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cienum {
30562306a36Sopenharmony_ci	not_issued	= 0x0001,	/* command not yet issued */
30662306a36Sopenharmony_ci	selecting	= 0x0002,	/* target is being selected */
30762306a36Sopenharmony_ci	identified	= 0x0004,	/* IDENTIFY was sent */
30862306a36Sopenharmony_ci	disconnected	= 0x0008,	/* target disconnected */
30962306a36Sopenharmony_ci	completed	= 0x0010,	/* target sent COMMAND COMPLETE */
31062306a36Sopenharmony_ci	aborted		= 0x0020,	/* ABORT was sent */
31162306a36Sopenharmony_ci	resetted	= 0x0040,	/* BUS DEVICE RESET was sent */
31262306a36Sopenharmony_ci	spiordy		= 0x0080,	/* waiting for SPIORDY to raise */
31362306a36Sopenharmony_ci	syncneg		= 0x0100,	/* synchronous negotiation in progress */
31462306a36Sopenharmony_ci	aborting	= 0x0200,	/* ABORT is pending */
31562306a36Sopenharmony_ci	resetting	= 0x0400,	/* BUS DEVICE RESET is pending */
31662306a36Sopenharmony_ci	check_condition = 0x0800,	/* requesting sense after CHECK CONDITION */
31762306a36Sopenharmony_ci};
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistruct aha152x_cmd_priv {
32062306a36Sopenharmony_ci	char *ptr;
32162306a36Sopenharmony_ci	int this_residual;
32262306a36Sopenharmony_ci	struct scatterlist *buffer;
32362306a36Sopenharmony_ci	int status;
32462306a36Sopenharmony_ci	int message;
32562306a36Sopenharmony_ci	int sent_command;
32662306a36Sopenharmony_ci	int phase;
32762306a36Sopenharmony_ci};
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic struct aha152x_cmd_priv *aha152x_priv(struct scsi_cmnd *cmd)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	return scsi_cmd_priv(cmd);
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ciMODULE_AUTHOR("Jürgen Fischer");
33562306a36Sopenharmony_ciMODULE_DESCRIPTION(AHA152X_REVID);
33662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci#if !defined(AHA152X_PCMCIA)
33962306a36Sopenharmony_ci#if defined(MODULE)
34062306a36Sopenharmony_cistatic int io[] = {0, 0};
34162306a36Sopenharmony_cimodule_param_hw_array(io, int, ioport, NULL, 0);
34262306a36Sopenharmony_ciMODULE_PARM_DESC(io,"base io address of controller");
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic int irq[] = {0, 0};
34562306a36Sopenharmony_cimodule_param_hw_array(irq, int, irq, NULL, 0);
34662306a36Sopenharmony_ciMODULE_PARM_DESC(irq,"interrupt for controller");
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cistatic int scsiid[] = {7, 7};
34962306a36Sopenharmony_cimodule_param_array(scsiid, int, NULL, 0);
35062306a36Sopenharmony_ciMODULE_PARM_DESC(scsiid,"scsi id of controller");
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic int reconnect[] = {1, 1};
35362306a36Sopenharmony_cimodule_param_array(reconnect, int, NULL, 0);
35462306a36Sopenharmony_ciMODULE_PARM_DESC(reconnect,"allow targets to disconnect");
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic int parity[] = {1, 1};
35762306a36Sopenharmony_cimodule_param_array(parity, int, NULL, 0);
35862306a36Sopenharmony_ciMODULE_PARM_DESC(parity,"use scsi parity");
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic int sync[] = {1, 1};
36162306a36Sopenharmony_cimodule_param_array(sync, int, NULL, 0);
36262306a36Sopenharmony_ciMODULE_PARM_DESC(sync,"use synchronous transfers");
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic int delay[] = {DELAY_DEFAULT, DELAY_DEFAULT};
36562306a36Sopenharmony_cimodule_param_array(delay, int, NULL, 0);
36662306a36Sopenharmony_ciMODULE_PARM_DESC(delay,"scsi reset delay");
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic int exttrans[] = {0, 0};
36962306a36Sopenharmony_cimodule_param_array(exttrans, int, NULL, 0);
37062306a36Sopenharmony_ciMODULE_PARM_DESC(exttrans,"use extended translation");
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
37362306a36Sopenharmony_cimodule_param_array(aha152x, int, NULL, 0);
37462306a36Sopenharmony_ciMODULE_PARM_DESC(aha152x, "parameters for first controller");
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistatic int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
37762306a36Sopenharmony_cimodule_param_array(aha152x1, int, NULL, 0);
37862306a36Sopenharmony_ciMODULE_PARM_DESC(aha152x1, "parameters for second controller");
37962306a36Sopenharmony_ci#endif /* MODULE */
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci#ifdef __ISAPNP__
38262306a36Sopenharmony_cistatic struct isapnp_device_id id_table[] = {
38362306a36Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1502), 0 },
38462306a36Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1505), 0 },
38562306a36Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1510), 0 },
38662306a36Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1515), 0 },
38762306a36Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1520), 0 },
38862306a36Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2015), 0 },
38962306a36Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1522), 0 },
39062306a36Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2215), 0 },
39162306a36Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1530), 0 },
39262306a36Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3015), 0 },
39362306a36Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1532), 0 },
39462306a36Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3215), 0 },
39562306a36Sopenharmony_ci	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x6360), 0 },
39662306a36Sopenharmony_ci	{ ISAPNP_DEVICE_SINGLE_END, }
39762306a36Sopenharmony_ci};
39862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(isapnp, id_table);
39962306a36Sopenharmony_ci#endif /* ISAPNP */
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci#endif /* !AHA152X_PCMCIA */
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic const struct scsi_host_template aha152x_driver_template;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci/*
40662306a36Sopenharmony_ci * internal states of the host
40762306a36Sopenharmony_ci *
40862306a36Sopenharmony_ci */
40962306a36Sopenharmony_cienum aha152x_state {
41062306a36Sopenharmony_ci	idle=0,
41162306a36Sopenharmony_ci	unknown,
41262306a36Sopenharmony_ci	seldo,
41362306a36Sopenharmony_ci	seldi,
41462306a36Sopenharmony_ci	selto,
41562306a36Sopenharmony_ci	busfree,
41662306a36Sopenharmony_ci	msgo,
41762306a36Sopenharmony_ci	cmd,
41862306a36Sopenharmony_ci	msgi,
41962306a36Sopenharmony_ci	status,
42062306a36Sopenharmony_ci	datai,
42162306a36Sopenharmony_ci	datao,
42262306a36Sopenharmony_ci	parerr,
42362306a36Sopenharmony_ci	rsti,
42462306a36Sopenharmony_ci	maxstate
42562306a36Sopenharmony_ci};
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci/*
42862306a36Sopenharmony_ci * current state information of the host
42962306a36Sopenharmony_ci *
43062306a36Sopenharmony_ci */
43162306a36Sopenharmony_cistruct aha152x_hostdata {
43262306a36Sopenharmony_ci	struct scsi_cmnd *issue_SC;
43362306a36Sopenharmony_ci		/* pending commands to issue */
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	struct scsi_cmnd *current_SC;
43662306a36Sopenharmony_ci		/* current command on the bus */
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	struct scsi_cmnd *disconnected_SC;
43962306a36Sopenharmony_ci		/* commands that disconnected */
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	struct scsi_cmnd *done_SC;
44262306a36Sopenharmony_ci		/* command that was completed */
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	spinlock_t lock;
44562306a36Sopenharmony_ci		/* host lock */
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci#if defined(AHA152X_STAT)
44862306a36Sopenharmony_ci	int	      total_commands;
44962306a36Sopenharmony_ci	int	      disconnections;
45062306a36Sopenharmony_ci	int	      busfree_without_any_action;
45162306a36Sopenharmony_ci	int	      busfree_without_old_command;
45262306a36Sopenharmony_ci	int	      busfree_without_new_command;
45362306a36Sopenharmony_ci	int	      busfree_without_done_command;
45462306a36Sopenharmony_ci	int	      busfree_with_check_condition;
45562306a36Sopenharmony_ci	int	      count[maxstate];
45662306a36Sopenharmony_ci	int	      count_trans[maxstate];
45762306a36Sopenharmony_ci	unsigned long time[maxstate];
45862306a36Sopenharmony_ci#endif
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	int commands;		/* current number of commands */
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	int reconnect;		/* disconnection allowed */
46362306a36Sopenharmony_ci	int parity;		/* parity checking enabled */
46462306a36Sopenharmony_ci	int synchronous;	/* synchronous transferes enabled */
46562306a36Sopenharmony_ci	int delay;		/* reset out delay */
46662306a36Sopenharmony_ci	int ext_trans;		/* extended translation enabled */
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	int swint;		/* software-interrupt was fired during detect() */
46962306a36Sopenharmony_ci	int service;		/* bh needs to be run */
47062306a36Sopenharmony_ci	int in_intr;		/* bh is running */
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/* current state,
47362306a36Sopenharmony_ci	   previous state,
47462306a36Sopenharmony_ci	   last state different from current state */
47562306a36Sopenharmony_ci	enum aha152x_state state, prevstate, laststate;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	int target;
47862306a36Sopenharmony_ci		/* reconnecting target */
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	unsigned char syncrate[8];
48162306a36Sopenharmony_ci		/* current synchronous transfer agreements */
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	unsigned char syncneg[8];
48462306a36Sopenharmony_ci		/* 0: no negotiation;
48562306a36Sopenharmony_ci		 * 1: negotiation in progress;
48662306a36Sopenharmony_ci		 * 2: negotiation completed
48762306a36Sopenharmony_ci		 */
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	int cmd_i;
49062306a36Sopenharmony_ci		/* number of sent bytes of current command */
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	int msgi_len;
49362306a36Sopenharmony_ci		/* number of received message bytes */
49462306a36Sopenharmony_ci	unsigned char msgi[256];
49562306a36Sopenharmony_ci		/* received message bytes */
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	int msgo_i, msgo_len;
49862306a36Sopenharmony_ci		/* number of sent bytes and length of current messages */
49962306a36Sopenharmony_ci	unsigned char msgo[256];
50062306a36Sopenharmony_ci		/* pending messages */
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	int data_len;
50362306a36Sopenharmony_ci		/* number of sent/received bytes in dataphase */
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	unsigned long io_port0;
50662306a36Sopenharmony_ci	unsigned long io_port1;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci#ifdef __ISAPNP__
50962306a36Sopenharmony_ci	struct pnp_dev *pnpdev;
51062306a36Sopenharmony_ci#endif
51162306a36Sopenharmony_ci	struct list_head host_list;
51262306a36Sopenharmony_ci};
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci/*
51662306a36Sopenharmony_ci * host specific command extension
51762306a36Sopenharmony_ci *
51862306a36Sopenharmony_ci */
51962306a36Sopenharmony_cistruct aha152x_scdata {
52062306a36Sopenharmony_ci	struct scsi_cmnd *next;	/* next sc in queue */
52162306a36Sopenharmony_ci	struct completion *done;/* semaphore to block on */
52262306a36Sopenharmony_ci	struct scsi_eh_save ses;
52362306a36Sopenharmony_ci};
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci/* access macros for hostdata */
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci#define HOSTDATA(shpnt)		((struct aha152x_hostdata *) &shpnt->hostdata)
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci#define HOSTNO			((shpnt)->host_no)
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci#define CURRENT_SC		(HOSTDATA(shpnt)->current_SC)
53262306a36Sopenharmony_ci#define DONE_SC			(HOSTDATA(shpnt)->done_SC)
53362306a36Sopenharmony_ci#define ISSUE_SC		(HOSTDATA(shpnt)->issue_SC)
53462306a36Sopenharmony_ci#define DISCONNECTED_SC		(HOSTDATA(shpnt)->disconnected_SC)
53562306a36Sopenharmony_ci#define QLOCK			(HOSTDATA(shpnt)->lock)
53662306a36Sopenharmony_ci#define QLOCKER			(HOSTDATA(shpnt)->locker)
53762306a36Sopenharmony_ci#define QLOCKERL		(HOSTDATA(shpnt)->lockerl)
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci#define STATE			(HOSTDATA(shpnt)->state)
54062306a36Sopenharmony_ci#define PREVSTATE		(HOSTDATA(shpnt)->prevstate)
54162306a36Sopenharmony_ci#define LASTSTATE		(HOSTDATA(shpnt)->laststate)
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci#define RECONN_TARGET		(HOSTDATA(shpnt)->target)
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci#define CMD_I			(HOSTDATA(shpnt)->cmd_i)
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci#define MSGO(i)			(HOSTDATA(shpnt)->msgo[i])
54862306a36Sopenharmony_ci#define MSGO_I			(HOSTDATA(shpnt)->msgo_i)
54962306a36Sopenharmony_ci#define MSGOLEN			(HOSTDATA(shpnt)->msgo_len)
55062306a36Sopenharmony_ci#define ADDMSGO(x)		(MSGOLEN<256 ? (void)(MSGO(MSGOLEN++)=x) : aha152x_error(shpnt,"MSGO overflow"))
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci#define MSGI(i)			(HOSTDATA(shpnt)->msgi[i])
55362306a36Sopenharmony_ci#define MSGILEN			(HOSTDATA(shpnt)->msgi_len)
55462306a36Sopenharmony_ci#define ADDMSGI(x)		(MSGILEN<256 ? (void)(MSGI(MSGILEN++)=x) : aha152x_error(shpnt,"MSGI overflow"))
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci#define DATA_LEN		(HOSTDATA(shpnt)->data_len)
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci#define SYNCRATE		(HOSTDATA(shpnt)->syncrate[CURRENT_SC->device->id])
55962306a36Sopenharmony_ci#define SYNCNEG			(HOSTDATA(shpnt)->syncneg[CURRENT_SC->device->id])
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci#define DELAY			(HOSTDATA(shpnt)->delay)
56262306a36Sopenharmony_ci#define EXT_TRANS		(HOSTDATA(shpnt)->ext_trans)
56362306a36Sopenharmony_ci#define TC1550			(HOSTDATA(shpnt)->tc1550)
56462306a36Sopenharmony_ci#define RECONNECT		(HOSTDATA(shpnt)->reconnect)
56562306a36Sopenharmony_ci#define PARITY			(HOSTDATA(shpnt)->parity)
56662306a36Sopenharmony_ci#define SYNCHRONOUS		(HOSTDATA(shpnt)->synchronous)
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci#define HOSTIOPORT0		(HOSTDATA(shpnt)->io_port0)
56962306a36Sopenharmony_ci#define HOSTIOPORT1		(HOSTDATA(shpnt)->io_port1)
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci#define SCDATA(SCpnt)		((struct aha152x_scdata *) (SCpnt)->host_scribble)
57262306a36Sopenharmony_ci#define SCNEXT(SCpnt)		SCDATA(SCpnt)->next
57362306a36Sopenharmony_ci#define SCSEM(SCpnt)		SCDATA(SCpnt)->done
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci#define SG_ADDRESS(buffer)	((char *) sg_virt((buffer)))
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci/* state handling */
57862306a36Sopenharmony_cistatic void seldi_run(struct Scsi_Host *shpnt);
57962306a36Sopenharmony_cistatic void seldo_run(struct Scsi_Host *shpnt);
58062306a36Sopenharmony_cistatic void selto_run(struct Scsi_Host *shpnt);
58162306a36Sopenharmony_cistatic void busfree_run(struct Scsi_Host *shpnt);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cistatic void msgo_init(struct Scsi_Host *shpnt);
58462306a36Sopenharmony_cistatic void msgo_run(struct Scsi_Host *shpnt);
58562306a36Sopenharmony_cistatic void msgo_end(struct Scsi_Host *shpnt);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cistatic void cmd_init(struct Scsi_Host *shpnt);
58862306a36Sopenharmony_cistatic void cmd_run(struct Scsi_Host *shpnt);
58962306a36Sopenharmony_cistatic void cmd_end(struct Scsi_Host *shpnt);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic void datai_init(struct Scsi_Host *shpnt);
59262306a36Sopenharmony_cistatic void datai_run(struct Scsi_Host *shpnt);
59362306a36Sopenharmony_cistatic void datai_end(struct Scsi_Host *shpnt);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_cistatic void datao_init(struct Scsi_Host *shpnt);
59662306a36Sopenharmony_cistatic void datao_run(struct Scsi_Host *shpnt);
59762306a36Sopenharmony_cistatic void datao_end(struct Scsi_Host *shpnt);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_cistatic void status_run(struct Scsi_Host *shpnt);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_cistatic void msgi_run(struct Scsi_Host *shpnt);
60262306a36Sopenharmony_cistatic void msgi_end(struct Scsi_Host *shpnt);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic void parerr_run(struct Scsi_Host *shpnt);
60562306a36Sopenharmony_cistatic void rsti_run(struct Scsi_Host *shpnt);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic void is_complete(struct Scsi_Host *shpnt);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci/*
61062306a36Sopenharmony_ci * driver states
61162306a36Sopenharmony_ci *
61262306a36Sopenharmony_ci */
61362306a36Sopenharmony_cistatic struct {
61462306a36Sopenharmony_ci	char		*name;
61562306a36Sopenharmony_ci	void		(*init)(struct Scsi_Host *);
61662306a36Sopenharmony_ci	void		(*run)(struct Scsi_Host *);
61762306a36Sopenharmony_ci	void		(*end)(struct Scsi_Host *);
61862306a36Sopenharmony_ci	int		spio;
61962306a36Sopenharmony_ci} states[] = {
62062306a36Sopenharmony_ci	{ "idle",	NULL,		NULL,		NULL,		0},
62162306a36Sopenharmony_ci	{ "unknown",	NULL,		NULL,		NULL,		0},
62262306a36Sopenharmony_ci	{ "seldo",	NULL,		seldo_run,	NULL,		0},
62362306a36Sopenharmony_ci	{ "seldi",	NULL,		seldi_run,	NULL,		0},
62462306a36Sopenharmony_ci	{ "selto",	NULL,		selto_run,	NULL,		0},
62562306a36Sopenharmony_ci	{ "busfree",	NULL,		busfree_run,	NULL,		0},
62662306a36Sopenharmony_ci	{ "msgo",	msgo_init,	msgo_run,	msgo_end,	1},
62762306a36Sopenharmony_ci	{ "cmd",	cmd_init,	cmd_run,	cmd_end,	1},
62862306a36Sopenharmony_ci	{ "msgi",	NULL,		msgi_run,	msgi_end,	1},
62962306a36Sopenharmony_ci	{ "status",	NULL,		status_run,	NULL,		1},
63062306a36Sopenharmony_ci	{ "datai",	datai_init,	datai_run,	datai_end,	0},
63162306a36Sopenharmony_ci	{ "datao",	datao_init,	datao_run,	datao_end,	0},
63262306a36Sopenharmony_ci	{ "parerr",	NULL,		parerr_run,	NULL,		0},
63362306a36Sopenharmony_ci	{ "rsti",	NULL,		rsti_run,	NULL,		0},
63462306a36Sopenharmony_ci};
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci/* setup & interrupt */
63762306a36Sopenharmony_cistatic irqreturn_t intr(int irq, void *dev_id);
63862306a36Sopenharmony_cistatic void reset_ports(struct Scsi_Host *shpnt);
63962306a36Sopenharmony_cistatic void aha152x_error(struct Scsi_Host *shpnt, char *msg);
64062306a36Sopenharmony_cistatic void done(struct Scsi_Host *shpnt, unsigned char status_byte,
64162306a36Sopenharmony_ci		 unsigned char host_byte);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci/* diagnostics */
64462306a36Sopenharmony_cistatic void show_command(struct scsi_cmnd * ptr);
64562306a36Sopenharmony_cistatic void show_queues(struct Scsi_Host *shpnt);
64662306a36Sopenharmony_cistatic void disp_enintr(struct Scsi_Host *shpnt);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci/*
65062306a36Sopenharmony_ci *  queue services:
65162306a36Sopenharmony_ci *
65262306a36Sopenharmony_ci */
65362306a36Sopenharmony_cistatic inline void append_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	struct scsi_cmnd *end;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	SCNEXT(new_SC) = NULL;
65862306a36Sopenharmony_ci	if (!*SC)
65962306a36Sopenharmony_ci		*SC = new_SC;
66062306a36Sopenharmony_ci	else {
66162306a36Sopenharmony_ci		for (end = *SC; SCNEXT(end); end = SCNEXT(end))
66262306a36Sopenharmony_ci			;
66362306a36Sopenharmony_ci		SCNEXT(end) = new_SC;
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic inline struct scsi_cmnd *remove_first_SC(struct scsi_cmnd ** SC)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	struct scsi_cmnd *ptr;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	ptr = *SC;
67262306a36Sopenharmony_ci	if (ptr) {
67362306a36Sopenharmony_ci		*SC = SCNEXT(*SC);
67462306a36Sopenharmony_ci		SCNEXT(ptr)=NULL;
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci	return ptr;
67762306a36Sopenharmony_ci}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_cistatic inline struct scsi_cmnd *remove_lun_SC(struct scsi_cmnd ** SC,
68062306a36Sopenharmony_ci					      int target, int lun)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	struct scsi_cmnd *ptr, *prev;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	for (ptr = *SC, prev = NULL;
68562306a36Sopenharmony_ci	     ptr && ((ptr->device->id != target) || (ptr->device->lun != lun));
68662306a36Sopenharmony_ci	     prev = ptr, ptr = SCNEXT(ptr))
68762306a36Sopenharmony_ci	     ;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	if (ptr) {
69062306a36Sopenharmony_ci		if (prev)
69162306a36Sopenharmony_ci			SCNEXT(prev) = SCNEXT(ptr);
69262306a36Sopenharmony_ci		else
69362306a36Sopenharmony_ci			*SC = SCNEXT(ptr);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci		SCNEXT(ptr)=NULL;
69662306a36Sopenharmony_ci	}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	return ptr;
69962306a36Sopenharmony_ci}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_cistatic inline struct scsi_cmnd *remove_SC(struct scsi_cmnd **SC,
70262306a36Sopenharmony_ci					  struct scsi_cmnd *SCp)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	struct scsi_cmnd *ptr, *prev;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	for (ptr = *SC, prev = NULL;
70762306a36Sopenharmony_ci	     ptr && SCp!=ptr;
70862306a36Sopenharmony_ci	     prev = ptr, ptr = SCNEXT(ptr))
70962306a36Sopenharmony_ci	     ;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	if (ptr) {
71262306a36Sopenharmony_ci		if (prev)
71362306a36Sopenharmony_ci			SCNEXT(prev) = SCNEXT(ptr);
71462306a36Sopenharmony_ci		else
71562306a36Sopenharmony_ci			*SC = SCNEXT(ptr);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci		SCNEXT(ptr)=NULL;
71862306a36Sopenharmony_ci	}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	return ptr;
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_cistatic irqreturn_t swintr(int irqno, void *dev_id)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	struct Scsi_Host *shpnt = dev_id;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	HOSTDATA(shpnt)->swint++;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	SETPORT(DMACNTRL0, INTEN);
73062306a36Sopenharmony_ci	return IRQ_HANDLED;
73162306a36Sopenharmony_ci}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_cistruct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
73462306a36Sopenharmony_ci{
73562306a36Sopenharmony_ci	struct Scsi_Host *shpnt;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	shpnt = scsi_host_alloc(&aha152x_driver_template, sizeof(struct aha152x_hostdata));
73862306a36Sopenharmony_ci	if (!shpnt) {
73962306a36Sopenharmony_ci		printk(KERN_ERR "aha152x: scsi_host_alloc failed\n");
74062306a36Sopenharmony_ci		return NULL;
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt));
74462306a36Sopenharmony_ci	INIT_LIST_HEAD(&HOSTDATA(shpnt)->host_list);
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	/* need to have host registered before triggering any interrupt */
74762306a36Sopenharmony_ci	list_add_tail(&HOSTDATA(shpnt)->host_list, &aha152x_host_list);
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	shpnt->io_port   = setup->io_port;
75062306a36Sopenharmony_ci	shpnt->n_io_port = IO_RANGE;
75162306a36Sopenharmony_ci	shpnt->irq       = setup->irq;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	if (!setup->tc1550) {
75462306a36Sopenharmony_ci		HOSTIOPORT0 = setup->io_port;
75562306a36Sopenharmony_ci		HOSTIOPORT1 = setup->io_port;
75662306a36Sopenharmony_ci	} else {
75762306a36Sopenharmony_ci		HOSTIOPORT0 = setup->io_port+0x10;
75862306a36Sopenharmony_ci		HOSTIOPORT1 = setup->io_port-0x10;
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	spin_lock_init(&QLOCK);
76262306a36Sopenharmony_ci	RECONNECT   = setup->reconnect;
76362306a36Sopenharmony_ci	SYNCHRONOUS = setup->synchronous;
76462306a36Sopenharmony_ci	PARITY      = setup->parity;
76562306a36Sopenharmony_ci	DELAY       = setup->delay;
76662306a36Sopenharmony_ci	EXT_TRANS   = setup->ext_trans;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	SETPORT(SCSIID, setup->scsiid << 4);
76962306a36Sopenharmony_ci	shpnt->this_id = setup->scsiid;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	if (setup->reconnect)
77262306a36Sopenharmony_ci		shpnt->can_queue = AHA152X_MAXQUEUE;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	/* RESET OUT */
77562306a36Sopenharmony_ci	printk("aha152x: resetting bus...\n");
77662306a36Sopenharmony_ci	SETPORT(SCSISEQ, SCSIRSTO);
77762306a36Sopenharmony_ci	mdelay(256);
77862306a36Sopenharmony_ci	SETPORT(SCSISEQ, 0);
77962306a36Sopenharmony_ci	mdelay(DELAY);
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	reset_ports(shpnt);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	printk(KERN_INFO
78462306a36Sopenharmony_ci	       "aha152x%d%s: "
78562306a36Sopenharmony_ci	       "vital data: rev=%x, "
78662306a36Sopenharmony_ci	       "io=0x%03lx (0x%03lx/0x%03lx), "
78762306a36Sopenharmony_ci	       "irq=%d, "
78862306a36Sopenharmony_ci	       "scsiid=%d, "
78962306a36Sopenharmony_ci	       "reconnect=%s, "
79062306a36Sopenharmony_ci	       "parity=%s, "
79162306a36Sopenharmony_ci	       "synchronous=%s, "
79262306a36Sopenharmony_ci	       "delay=%d, "
79362306a36Sopenharmony_ci	       "extended translation=%s\n",
79462306a36Sopenharmony_ci	       shpnt->host_no, setup->tc1550 ? " (tc1550 mode)" : "",
79562306a36Sopenharmony_ci	       GETPORT(REV) & 0x7,
79662306a36Sopenharmony_ci	       shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1,
79762306a36Sopenharmony_ci	       shpnt->irq,
79862306a36Sopenharmony_ci	       shpnt->this_id,
79962306a36Sopenharmony_ci	       RECONNECT ? "enabled" : "disabled",
80062306a36Sopenharmony_ci	       PARITY ? "enabled" : "disabled",
80162306a36Sopenharmony_ci	       SYNCHRONOUS ? "enabled" : "disabled",
80262306a36Sopenharmony_ci	       DELAY,
80362306a36Sopenharmony_ci	       EXT_TRANS ? "enabled" : "disabled");
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	/* not expecting any interrupts */
80662306a36Sopenharmony_ci	SETPORT(SIMODE0, 0);
80762306a36Sopenharmony_ci	SETPORT(SIMODE1, 0);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	if (request_irq(shpnt->irq, swintr, IRQF_SHARED, "aha152x", shpnt)) {
81062306a36Sopenharmony_ci		printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq);
81162306a36Sopenharmony_ci		goto out_host_put;
81262306a36Sopenharmony_ci	}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	HOSTDATA(shpnt)->swint = 0;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	printk(KERN_INFO "aha152x%d: trying software interrupt, ", shpnt->host_no);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	mb();
81962306a36Sopenharmony_ci	SETPORT(DMACNTRL0, SWINT|INTEN);
82062306a36Sopenharmony_ci	mdelay(1000);
82162306a36Sopenharmony_ci	free_irq(shpnt->irq, shpnt);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	if (!HOSTDATA(shpnt)->swint) {
82462306a36Sopenharmony_ci		if (TESTHI(DMASTAT, INTSTAT)) {
82562306a36Sopenharmony_ci			printk("lost.\n");
82662306a36Sopenharmony_ci		} else {
82762306a36Sopenharmony_ci			printk("failed.\n");
82862306a36Sopenharmony_ci		}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci		SETPORT(DMACNTRL0, INTEN);
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci		printk(KERN_ERR "aha152x%d: irq %d possibly wrong.  "
83362306a36Sopenharmony_ci				"Please verify.\n", shpnt->host_no, shpnt->irq);
83462306a36Sopenharmony_ci		goto out_host_put;
83562306a36Sopenharmony_ci	}
83662306a36Sopenharmony_ci	printk("ok.\n");
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	/* clear interrupts */
84062306a36Sopenharmony_ci	SETPORT(SSTAT0, 0x7f);
84162306a36Sopenharmony_ci	SETPORT(SSTAT1, 0xef);
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	if (request_irq(shpnt->irq, intr, IRQF_SHARED, "aha152x", shpnt)) {
84462306a36Sopenharmony_ci		printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq);
84562306a36Sopenharmony_ci		goto out_host_put;
84662306a36Sopenharmony_ci	}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	if( scsi_add_host(shpnt, NULL) ) {
84962306a36Sopenharmony_ci		free_irq(shpnt->irq, shpnt);
85062306a36Sopenharmony_ci		printk(KERN_ERR "aha152x%d: failed to add host.\n", shpnt->host_no);
85162306a36Sopenharmony_ci		goto out_host_put;
85262306a36Sopenharmony_ci	}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	scsi_scan_host(shpnt);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	return shpnt;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ciout_host_put:
85962306a36Sopenharmony_ci	list_del(&HOSTDATA(shpnt)->host_list);
86062306a36Sopenharmony_ci	scsi_host_put(shpnt);
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	return NULL;
86362306a36Sopenharmony_ci}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_civoid aha152x_release(struct Scsi_Host *shpnt)
86662306a36Sopenharmony_ci{
86762306a36Sopenharmony_ci	if (!shpnt)
86862306a36Sopenharmony_ci		return;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	scsi_remove_host(shpnt);
87162306a36Sopenharmony_ci	if (shpnt->irq)
87262306a36Sopenharmony_ci		free_irq(shpnt->irq, shpnt);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci#if !defined(AHA152X_PCMCIA)
87562306a36Sopenharmony_ci	if (shpnt->io_port)
87662306a36Sopenharmony_ci		release_region(shpnt->io_port, IO_RANGE);
87762306a36Sopenharmony_ci#endif
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci#ifdef __ISAPNP__
88062306a36Sopenharmony_ci	if (HOSTDATA(shpnt)->pnpdev)
88162306a36Sopenharmony_ci		pnp_device_detach(HOSTDATA(shpnt)->pnpdev);
88262306a36Sopenharmony_ci#endif
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	list_del(&HOSTDATA(shpnt)->host_list);
88562306a36Sopenharmony_ci	scsi_host_put(shpnt);
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci/*
89062306a36Sopenharmony_ci * setup controller to generate interrupts depending
89162306a36Sopenharmony_ci * on current state (lock has to be acquired)
89262306a36Sopenharmony_ci *
89362306a36Sopenharmony_ci */
89462306a36Sopenharmony_cistatic int setup_expected_interrupts(struct Scsi_Host *shpnt)
89562306a36Sopenharmony_ci{
89662306a36Sopenharmony_ci	if(CURRENT_SC) {
89762306a36Sopenharmony_ci		struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci		acp->phase |= 1 << 16;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci		if (acp->phase & selecting) {
90262306a36Sopenharmony_ci			SETPORT(SSTAT1, SELTO);
90362306a36Sopenharmony_ci			SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
90462306a36Sopenharmony_ci			SETPORT(SIMODE1, ENSELTIMO);
90562306a36Sopenharmony_ci		} else {
90662306a36Sopenharmony_ci			SETPORT(SIMODE0, (acp->phase & spiordy) ? ENSPIORDY : 0);
90762306a36Sopenharmony_ci			SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE);
90862306a36Sopenharmony_ci		}
90962306a36Sopenharmony_ci	} else if(STATE==seldi) {
91062306a36Sopenharmony_ci		SETPORT(SIMODE0, 0);
91162306a36Sopenharmony_ci		SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE);
91262306a36Sopenharmony_ci	} else {
91362306a36Sopenharmony_ci		SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
91462306a36Sopenharmony_ci		SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0));
91562306a36Sopenharmony_ci	}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	if(!HOSTDATA(shpnt)->in_intr)
91862306a36Sopenharmony_ci		SETBITS(DMACNTRL0, INTEN);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	return TESTHI(DMASTAT, INTSTAT);
92162306a36Sopenharmony_ci}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci/*
92562306a36Sopenharmony_ci *  Queue a command and setup interrupts for a free bus.
92662306a36Sopenharmony_ci */
92762306a36Sopenharmony_cistatic int aha152x_internal_queue(struct scsi_cmnd *SCpnt,
92862306a36Sopenharmony_ci				  struct completion *complete, int phase)
92962306a36Sopenharmony_ci{
93062306a36Sopenharmony_ci	struct aha152x_cmd_priv *acp = aha152x_priv(SCpnt);
93162306a36Sopenharmony_ci	struct Scsi_Host *shpnt = SCpnt->device->host;
93262306a36Sopenharmony_ci	unsigned long flags;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	acp->phase        = not_issued | phase;
93562306a36Sopenharmony_ci	acp->status       = 0x1; /* Illegal status by SCSI standard */
93662306a36Sopenharmony_ci	acp->message      = 0;
93762306a36Sopenharmony_ci	acp->sent_command = 0;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	if (acp->phase & (resetting | check_condition)) {
94062306a36Sopenharmony_ci		if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) {
94162306a36Sopenharmony_ci			scmd_printk(KERN_ERR, SCpnt, "cannot reuse command\n");
94262306a36Sopenharmony_ci			return FAILED;
94362306a36Sopenharmony_ci		}
94462306a36Sopenharmony_ci	} else {
94562306a36Sopenharmony_ci		SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
94662306a36Sopenharmony_ci		if(!SCpnt->host_scribble) {
94762306a36Sopenharmony_ci			scmd_printk(KERN_ERR, SCpnt, "allocation failed\n");
94862306a36Sopenharmony_ci			return FAILED;
94962306a36Sopenharmony_ci		}
95062306a36Sopenharmony_ci	}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	SCNEXT(SCpnt)		= NULL;
95362306a36Sopenharmony_ci	SCSEM(SCpnt)		= complete;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	/* setup scratch area
95662306a36Sopenharmony_ci	   SCp.ptr              : buffer pointer
95762306a36Sopenharmony_ci	   SCp.this_residual    : buffer length
95862306a36Sopenharmony_ci	   SCp.buffer           : next buffer
95962306a36Sopenharmony_ci	   SCp.phase            : current state of the command */
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	if ((phase & resetting) || !scsi_sglist(SCpnt)) {
96262306a36Sopenharmony_ci		acp->ptr           = NULL;
96362306a36Sopenharmony_ci		acp->this_residual = 0;
96462306a36Sopenharmony_ci		scsi_set_resid(SCpnt, 0);
96562306a36Sopenharmony_ci		acp->buffer        = NULL;
96662306a36Sopenharmony_ci	} else {
96762306a36Sopenharmony_ci		scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
96862306a36Sopenharmony_ci		acp->buffer        = scsi_sglist(SCpnt);
96962306a36Sopenharmony_ci		acp->ptr           = SG_ADDRESS(acp->buffer);
97062306a36Sopenharmony_ci		acp->this_residual = acp->buffer->length;
97162306a36Sopenharmony_ci	}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	DO_LOCK(flags);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci#if defined(AHA152X_STAT)
97662306a36Sopenharmony_ci	HOSTDATA(shpnt)->total_commands++;
97762306a36Sopenharmony_ci#endif
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	/* Turn led on, when this is the first command. */
98062306a36Sopenharmony_ci	HOSTDATA(shpnt)->commands++;
98162306a36Sopenharmony_ci	if (HOSTDATA(shpnt)->commands==1)
98262306a36Sopenharmony_ci		SETPORT(PORTA, 1);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	append_SC(&ISSUE_SC, SCpnt);
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	if(!HOSTDATA(shpnt)->in_intr)
98762306a36Sopenharmony_ci		setup_expected_interrupts(shpnt);
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	DO_UNLOCK(flags);
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	return 0;
99262306a36Sopenharmony_ci}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci/*
99562306a36Sopenharmony_ci *  queue a command
99662306a36Sopenharmony_ci *
99762306a36Sopenharmony_ci */
99862306a36Sopenharmony_cistatic int aha152x_queue_lck(struct scsi_cmnd *SCpnt)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	return aha152x_internal_queue(SCpnt, NULL, 0);
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_cistatic DEF_SCSI_QCMD(aha152x_queue)
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci/*
100762306a36Sopenharmony_ci *
100862306a36Sopenharmony_ci */
100962306a36Sopenharmony_cistatic void reset_done(struct scsi_cmnd *SCpnt)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	if(SCSEM(SCpnt)) {
101262306a36Sopenharmony_ci		complete(SCSEM(SCpnt));
101362306a36Sopenharmony_ci	} else {
101462306a36Sopenharmony_ci		printk(KERN_ERR "aha152x: reset_done w/o completion\n");
101562306a36Sopenharmony_ci	}
101662306a36Sopenharmony_ci}
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_cistatic void aha152x_scsi_done(struct scsi_cmnd *SCpnt)
101962306a36Sopenharmony_ci{
102062306a36Sopenharmony_ci	if (aha152x_priv(SCpnt)->phase & resetting)
102162306a36Sopenharmony_ci		reset_done(SCpnt);
102262306a36Sopenharmony_ci	else
102362306a36Sopenharmony_ci		scsi_done(SCpnt);
102462306a36Sopenharmony_ci}
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci/*
102762306a36Sopenharmony_ci *  Abort a command
102862306a36Sopenharmony_ci *
102962306a36Sopenharmony_ci */
103062306a36Sopenharmony_cistatic int aha152x_abort(struct scsi_cmnd *SCpnt)
103162306a36Sopenharmony_ci{
103262306a36Sopenharmony_ci	struct Scsi_Host *shpnt = SCpnt->device->host;
103362306a36Sopenharmony_ci	struct scsi_cmnd *ptr;
103462306a36Sopenharmony_ci	unsigned long flags;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	DO_LOCK(flags);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	ptr=remove_SC(&ISSUE_SC, SCpnt);
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	if(ptr) {
104162306a36Sopenharmony_ci		HOSTDATA(shpnt)->commands--;
104262306a36Sopenharmony_ci		if (!HOSTDATA(shpnt)->commands)
104362306a36Sopenharmony_ci			SETPORT(PORTA, 0);
104462306a36Sopenharmony_ci		DO_UNLOCK(flags);
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci		kfree(SCpnt->host_scribble);
104762306a36Sopenharmony_ci		SCpnt->host_scribble=NULL;
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci		return SUCCESS;
105062306a36Sopenharmony_ci	}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	DO_UNLOCK(flags);
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	/*
105562306a36Sopenharmony_ci	 * FIXME:
105662306a36Sopenharmony_ci	 * for current command: queue ABORT for message out and raise ATN
105762306a36Sopenharmony_ci	 * for disconnected command: pseudo SC with ABORT message or ABORT on reselection?
105862306a36Sopenharmony_ci	 *
105962306a36Sopenharmony_ci	 */
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	scmd_printk(KERN_ERR, SCpnt,
106262306a36Sopenharmony_ci		    "cannot abort running or disconnected command\n");
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	return FAILED;
106562306a36Sopenharmony_ci}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci/*
106862306a36Sopenharmony_ci * Reset a device
106962306a36Sopenharmony_ci *
107062306a36Sopenharmony_ci */
107162306a36Sopenharmony_cistatic int aha152x_device_reset(struct scsi_cmnd * SCpnt)
107262306a36Sopenharmony_ci{
107362306a36Sopenharmony_ci	struct Scsi_Host *shpnt = SCpnt->device->host;
107462306a36Sopenharmony_ci	DECLARE_COMPLETION(done);
107562306a36Sopenharmony_ci	int ret, issued, disconnected;
107662306a36Sopenharmony_ci	unsigned char old_cmd_len = SCpnt->cmd_len;
107762306a36Sopenharmony_ci	unsigned long flags;
107862306a36Sopenharmony_ci	unsigned long timeleft;
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	if(CURRENT_SC==SCpnt) {
108162306a36Sopenharmony_ci		scmd_printk(KERN_ERR, SCpnt, "cannot reset current device\n");
108262306a36Sopenharmony_ci		return FAILED;
108362306a36Sopenharmony_ci	}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	DO_LOCK(flags);
108662306a36Sopenharmony_ci	issued       = remove_SC(&ISSUE_SC, SCpnt) == NULL;
108762306a36Sopenharmony_ci	disconnected = issued && remove_SC(&DISCONNECTED_SC, SCpnt);
108862306a36Sopenharmony_ci	DO_UNLOCK(flags);
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	SCpnt->cmd_len         = 0;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	aha152x_internal_queue(SCpnt, &done, resetting);
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	timeleft = wait_for_completion_timeout(&done, 100*HZ);
109562306a36Sopenharmony_ci	if (!timeleft) {
109662306a36Sopenharmony_ci		/* remove command from issue queue */
109762306a36Sopenharmony_ci		DO_LOCK(flags);
109862306a36Sopenharmony_ci		remove_SC(&ISSUE_SC, SCpnt);
109962306a36Sopenharmony_ci		DO_UNLOCK(flags);
110062306a36Sopenharmony_ci	}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	SCpnt->cmd_len         = old_cmd_len;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	DO_LOCK(flags);
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	if (aha152x_priv(SCpnt)->phase & resetted) {
110762306a36Sopenharmony_ci		HOSTDATA(shpnt)->commands--;
110862306a36Sopenharmony_ci		if (!HOSTDATA(shpnt)->commands)
110962306a36Sopenharmony_ci			SETPORT(PORTA, 0);
111062306a36Sopenharmony_ci		kfree(SCpnt->host_scribble);
111162306a36Sopenharmony_ci		SCpnt->host_scribble=NULL;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci		ret = SUCCESS;
111462306a36Sopenharmony_ci	} else {
111562306a36Sopenharmony_ci		/* requeue */
111662306a36Sopenharmony_ci		if(!issued) {
111762306a36Sopenharmony_ci			append_SC(&ISSUE_SC, SCpnt);
111862306a36Sopenharmony_ci		} else if(disconnected) {
111962306a36Sopenharmony_ci			append_SC(&DISCONNECTED_SC, SCpnt);
112062306a36Sopenharmony_ci		}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci		ret = FAILED;
112362306a36Sopenharmony_ci	}
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	DO_UNLOCK(flags);
112662306a36Sopenharmony_ci	return ret;
112762306a36Sopenharmony_ci}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_cistatic void free_hard_reset_SCs(struct Scsi_Host *shpnt,
113062306a36Sopenharmony_ci				struct scsi_cmnd **SCs)
113162306a36Sopenharmony_ci{
113262306a36Sopenharmony_ci	struct scsi_cmnd *ptr;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	ptr=*SCs;
113562306a36Sopenharmony_ci	while(ptr) {
113662306a36Sopenharmony_ci		struct scsi_cmnd *next;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci		if(SCDATA(ptr)) {
113962306a36Sopenharmony_ci			next = SCNEXT(ptr);
114062306a36Sopenharmony_ci		} else {
114162306a36Sopenharmony_ci			scmd_printk(KERN_DEBUG, ptr,
114262306a36Sopenharmony_ci				    "queue corrupted at %p\n", ptr);
114362306a36Sopenharmony_ci			next = NULL;
114462306a36Sopenharmony_ci		}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci		if (!ptr->device->soft_reset) {
114762306a36Sopenharmony_ci			remove_SC(SCs, ptr);
114862306a36Sopenharmony_ci			HOSTDATA(shpnt)->commands--;
114962306a36Sopenharmony_ci			kfree(ptr->host_scribble);
115062306a36Sopenharmony_ci			ptr->host_scribble=NULL;
115162306a36Sopenharmony_ci		}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci		ptr = next;
115462306a36Sopenharmony_ci	}
115562306a36Sopenharmony_ci}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci/*
115862306a36Sopenharmony_ci * Reset the bus
115962306a36Sopenharmony_ci *
116062306a36Sopenharmony_ci * AIC-6260 has a hard reset (MRST signal), but apparently
116162306a36Sopenharmony_ci * one cannot trigger it via software. So live with
116262306a36Sopenharmony_ci * a soft reset; no-one seemed to have cared.
116362306a36Sopenharmony_ci */
116462306a36Sopenharmony_cistatic int aha152x_bus_reset_host(struct Scsi_Host *shpnt)
116562306a36Sopenharmony_ci{
116662306a36Sopenharmony_ci	unsigned long flags;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	DO_LOCK(flags);
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	free_hard_reset_SCs(shpnt, &ISSUE_SC);
117162306a36Sopenharmony_ci	free_hard_reset_SCs(shpnt, &DISCONNECTED_SC);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	SETPORT(SCSISEQ, SCSIRSTO);
117462306a36Sopenharmony_ci	mdelay(256);
117562306a36Sopenharmony_ci	SETPORT(SCSISEQ, 0);
117662306a36Sopenharmony_ci	mdelay(DELAY);
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	setup_expected_interrupts(shpnt);
117962306a36Sopenharmony_ci	if(HOSTDATA(shpnt)->commands==0)
118062306a36Sopenharmony_ci		SETPORT(PORTA, 0);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	DO_UNLOCK(flags);
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	return SUCCESS;
118562306a36Sopenharmony_ci}
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci/*
118862306a36Sopenharmony_ci * Reset the bus
118962306a36Sopenharmony_ci *
119062306a36Sopenharmony_ci */
119162306a36Sopenharmony_cistatic int aha152x_bus_reset(struct scsi_cmnd *SCpnt)
119262306a36Sopenharmony_ci{
119362306a36Sopenharmony_ci	return aha152x_bus_reset_host(SCpnt->device->host);
119462306a36Sopenharmony_ci}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci/*
119762306a36Sopenharmony_ci *  Restore default values to the AIC-6260 registers and reset the fifos
119862306a36Sopenharmony_ci *
119962306a36Sopenharmony_ci */
120062306a36Sopenharmony_cistatic void reset_ports(struct Scsi_Host *shpnt)
120162306a36Sopenharmony_ci{
120262306a36Sopenharmony_ci	unsigned long flags;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	/* disable interrupts */
120562306a36Sopenharmony_ci	SETPORT(DMACNTRL0, RSTFIFO);
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	SETPORT(SCSISEQ, 0);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	SETPORT(SXFRCTL1, 0);
121062306a36Sopenharmony_ci	SETPORT(SCSISIG, 0);
121162306a36Sopenharmony_ci	SETRATE(0);
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	/* clear all interrupt conditions */
121462306a36Sopenharmony_ci	SETPORT(SSTAT0, 0x7f);
121562306a36Sopenharmony_ci	SETPORT(SSTAT1, 0xef);
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	SETPORT(SSTAT4, SYNCERR | FWERR | FRERR);
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	SETPORT(DMACNTRL0, 0);
122062306a36Sopenharmony_ci	SETPORT(DMACNTRL1, 0);
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	SETPORT(BRSTCNTRL, 0xf1);
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	/* clear SCSI fifos and transfer count */
122562306a36Sopenharmony_ci	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
122662306a36Sopenharmony_ci	SETPORT(SXFRCTL0, CH1);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	DO_LOCK(flags);
122962306a36Sopenharmony_ci	setup_expected_interrupts(shpnt);
123062306a36Sopenharmony_ci	DO_UNLOCK(flags);
123162306a36Sopenharmony_ci}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci/*
123462306a36Sopenharmony_ci * Reset the host (bus and controller)
123562306a36Sopenharmony_ci *
123662306a36Sopenharmony_ci */
123762306a36Sopenharmony_ciint aha152x_host_reset_host(struct Scsi_Host *shpnt)
123862306a36Sopenharmony_ci{
123962306a36Sopenharmony_ci	aha152x_bus_reset_host(shpnt);
124062306a36Sopenharmony_ci	reset_ports(shpnt);
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	return SUCCESS;
124362306a36Sopenharmony_ci}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci/*
124662306a36Sopenharmony_ci * Return the "logical geometry"
124762306a36Sopenharmony_ci *
124862306a36Sopenharmony_ci */
124962306a36Sopenharmony_cistatic int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev,
125062306a36Sopenharmony_ci		sector_t capacity, int *info_array)
125162306a36Sopenharmony_ci{
125262306a36Sopenharmony_ci	struct Scsi_Host *shpnt = sdev->host;
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	/* try default translation */
125562306a36Sopenharmony_ci	info_array[0] = 64;
125662306a36Sopenharmony_ci	info_array[1] = 32;
125762306a36Sopenharmony_ci	info_array[2] = (unsigned long)capacity / (64 * 32);
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	/* for disks >1GB do some guessing */
126062306a36Sopenharmony_ci	if (info_array[2] >= 1024) {
126162306a36Sopenharmony_ci		int info[3];
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci		/* try to figure out the geometry from the partition table */
126462306a36Sopenharmony_ci		if (scsicam_bios_param(bdev, capacity, info) < 0 ||
126562306a36Sopenharmony_ci		    !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) {
126662306a36Sopenharmony_ci			if (EXT_TRANS) {
126762306a36Sopenharmony_ci				printk(KERN_NOTICE
126862306a36Sopenharmony_ci				       "aha152x: unable to verify geometry for disk with >1GB.\n"
126962306a36Sopenharmony_ci				       "         using extended translation.\n");
127062306a36Sopenharmony_ci				info_array[0] = 255;
127162306a36Sopenharmony_ci				info_array[1] = 63;
127262306a36Sopenharmony_ci				info_array[2] = (unsigned long)capacity / (255 * 63);
127362306a36Sopenharmony_ci			} else {
127462306a36Sopenharmony_ci				printk(KERN_NOTICE
127562306a36Sopenharmony_ci				       "aha152x: unable to verify geometry for disk with >1GB.\n"
127662306a36Sopenharmony_ci				       "         Using default translation. Please verify yourself.\n"
127762306a36Sopenharmony_ci				       "         Perhaps you need to enable extended translation in the driver.\n"
127862306a36Sopenharmony_ci				       "         See Documentation/scsi/aha152x.rst for details.\n");
127962306a36Sopenharmony_ci			}
128062306a36Sopenharmony_ci		} else {
128162306a36Sopenharmony_ci			info_array[0] = info[0];
128262306a36Sopenharmony_ci			info_array[1] = info[1];
128362306a36Sopenharmony_ci			info_array[2] = info[2];
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci			if (info[0] == 255 && !EXT_TRANS) {
128662306a36Sopenharmony_ci				printk(KERN_NOTICE
128762306a36Sopenharmony_ci				       "aha152x: current partition table is using extended translation.\n"
128862306a36Sopenharmony_ci				       "         using it also, although it's not explicitly enabled.\n");
128962306a36Sopenharmony_ci			}
129062306a36Sopenharmony_ci		}
129162306a36Sopenharmony_ci	}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	return 0;
129462306a36Sopenharmony_ci}
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci/*
129762306a36Sopenharmony_ci *  Internal done function
129862306a36Sopenharmony_ci *
129962306a36Sopenharmony_ci */
130062306a36Sopenharmony_cistatic void done(struct Scsi_Host *shpnt, unsigned char status_byte,
130162306a36Sopenharmony_ci		 unsigned char host_byte)
130262306a36Sopenharmony_ci{
130362306a36Sopenharmony_ci	if (CURRENT_SC) {
130462306a36Sopenharmony_ci		if(DONE_SC)
130562306a36Sopenharmony_ci			scmd_printk(KERN_ERR, CURRENT_SC,
130662306a36Sopenharmony_ci				    "there's already a completed command %p "
130762306a36Sopenharmony_ci				    "- will cause abort\n", DONE_SC);
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci		DONE_SC = CURRENT_SC;
131062306a36Sopenharmony_ci		CURRENT_SC = NULL;
131162306a36Sopenharmony_ci		set_status_byte(DONE_SC, status_byte);
131262306a36Sopenharmony_ci		set_host_byte(DONE_SC, host_byte);
131362306a36Sopenharmony_ci	} else
131462306a36Sopenharmony_ci		printk(KERN_ERR "aha152x: done() called outside of command\n");
131562306a36Sopenharmony_ci}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_cistatic struct work_struct aha152x_tq;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci/*
132062306a36Sopenharmony_ci * Run service completions on the card with interrupts enabled.
132162306a36Sopenharmony_ci *
132262306a36Sopenharmony_ci */
132362306a36Sopenharmony_cistatic void run(struct work_struct *work)
132462306a36Sopenharmony_ci{
132562306a36Sopenharmony_ci	struct aha152x_hostdata *hd;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	list_for_each_entry(hd, &aha152x_host_list, host_list) {
132862306a36Sopenharmony_ci		struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci		is_complete(shost);
133162306a36Sopenharmony_ci	}
133262306a36Sopenharmony_ci}
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci/*
133562306a36Sopenharmony_ci * Interrupt handler
133662306a36Sopenharmony_ci *
133762306a36Sopenharmony_ci */
133862306a36Sopenharmony_cistatic irqreturn_t intr(int irqno, void *dev_id)
133962306a36Sopenharmony_ci{
134062306a36Sopenharmony_ci	struct Scsi_Host *shpnt = dev_id;
134162306a36Sopenharmony_ci	unsigned long flags;
134262306a36Sopenharmony_ci	unsigned char rev, dmacntrl0;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	/*
134562306a36Sopenharmony_ci	 * Read a couple of registers that are known to not be all 1's. If
134662306a36Sopenharmony_ci	 * we read all 1's (-1), that means that either:
134762306a36Sopenharmony_ci	 *
134862306a36Sopenharmony_ci	 * a. The host adapter chip has gone bad, and we cannot control it,
134962306a36Sopenharmony_ci	 *	OR
135062306a36Sopenharmony_ci	 * b. The host adapter is a PCMCIA card that has been ejected
135162306a36Sopenharmony_ci	 *
135262306a36Sopenharmony_ci	 * In either case, we cannot do anything with the host adapter at
135362306a36Sopenharmony_ci	 * this point in time. So just ignore the interrupt and return.
135462306a36Sopenharmony_ci	 * In the latter case, the interrupt might actually be meant for
135562306a36Sopenharmony_ci	 * someone else sharing this IRQ, and that driver will handle it.
135662306a36Sopenharmony_ci	 */
135762306a36Sopenharmony_ci	rev = GETPORT(REV);
135862306a36Sopenharmony_ci	dmacntrl0 = GETPORT(DMACNTRL0);
135962306a36Sopenharmony_ci	if ((rev == 0xFF) && (dmacntrl0 == 0xFF))
136062306a36Sopenharmony_ci		return IRQ_NONE;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	if( TESTLO(DMASTAT, INTSTAT) )
136362306a36Sopenharmony_ci		return IRQ_NONE;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	/* no more interrupts from the controller, while we're busy.
136662306a36Sopenharmony_ci	   INTEN is restored by the BH handler */
136762306a36Sopenharmony_ci	CLRBITS(DMACNTRL0, INTEN);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	DO_LOCK(flags);
137062306a36Sopenharmony_ci	if( HOSTDATA(shpnt)->service==0 ) {
137162306a36Sopenharmony_ci		HOSTDATA(shpnt)->service=1;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci		/* Poke the BH handler */
137462306a36Sopenharmony_ci		INIT_WORK(&aha152x_tq, run);
137562306a36Sopenharmony_ci		schedule_work(&aha152x_tq);
137662306a36Sopenharmony_ci	}
137762306a36Sopenharmony_ci	DO_UNLOCK(flags);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	return IRQ_HANDLED;
138062306a36Sopenharmony_ci}
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci/*
138362306a36Sopenharmony_ci * busfree phase
138462306a36Sopenharmony_ci * - handle completition/disconnection/error of current command
138562306a36Sopenharmony_ci * - start selection for next command (if any)
138662306a36Sopenharmony_ci */
138762306a36Sopenharmony_cistatic void busfree_run(struct Scsi_Host *shpnt)
138862306a36Sopenharmony_ci{
138962306a36Sopenharmony_ci	unsigned long flags;
139062306a36Sopenharmony_ci#if defined(AHA152X_STAT)
139162306a36Sopenharmony_ci	int action=0;
139262306a36Sopenharmony_ci#endif
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
139562306a36Sopenharmony_ci	SETPORT(SXFRCTL0, CH1);
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	SETPORT(SSTAT1, CLRBUSFREE);
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	if(CURRENT_SC) {
140062306a36Sopenharmony_ci		struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci#if defined(AHA152X_STAT)
140362306a36Sopenharmony_ci		action++;
140462306a36Sopenharmony_ci#endif
140562306a36Sopenharmony_ci		acp->phase &= ~syncneg;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci		if (acp->phase & completed) {
140862306a36Sopenharmony_ci			/* target sent COMMAND COMPLETE */
140962306a36Sopenharmony_ci			done(shpnt, acp->status, DID_OK);
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci		} else if (acp->phase & aborted) {
141262306a36Sopenharmony_ci			done(shpnt, acp->status, DID_ABORT);
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci		} else if (acp->phase & resetted) {
141562306a36Sopenharmony_ci			done(shpnt, acp->status, DID_RESET);
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci		} else if (acp->phase & disconnected) {
141862306a36Sopenharmony_ci			/* target sent DISCONNECT */
141962306a36Sopenharmony_ci#if defined(AHA152X_STAT)
142062306a36Sopenharmony_ci			HOSTDATA(shpnt)->disconnections++;
142162306a36Sopenharmony_ci#endif
142262306a36Sopenharmony_ci			append_SC(&DISCONNECTED_SC, CURRENT_SC);
142362306a36Sopenharmony_ci			acp->phase |= 1 << 16;
142462306a36Sopenharmony_ci			CURRENT_SC = NULL;
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci		} else {
142762306a36Sopenharmony_ci			done(shpnt, SAM_STAT_GOOD, DID_ERROR);
142862306a36Sopenharmony_ci		}
142962306a36Sopenharmony_ci#if defined(AHA152X_STAT)
143062306a36Sopenharmony_ci	} else {
143162306a36Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_old_command++;
143262306a36Sopenharmony_ci#endif
143362306a36Sopenharmony_ci	}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	DO_LOCK(flags);
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	if(DONE_SC) {
143862306a36Sopenharmony_ci#if defined(AHA152X_STAT)
143962306a36Sopenharmony_ci		action++;
144062306a36Sopenharmony_ci#endif
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci		if (aha152x_priv(DONE_SC)->phase & check_condition) {
144362306a36Sopenharmony_ci			struct scsi_cmnd *cmd = HOSTDATA(shpnt)->done_SC;
144462306a36Sopenharmony_ci			struct aha152x_scdata *sc = SCDATA(cmd);
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci			scsi_eh_restore_cmnd(cmd, &sc->ses);
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci			aha152x_priv(cmd)->status = SAM_STAT_CHECK_CONDITION;
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci			HOSTDATA(shpnt)->commands--;
145162306a36Sopenharmony_ci			if (!HOSTDATA(shpnt)->commands)
145262306a36Sopenharmony_ci				SETPORT(PORTA, 0);	/* turn led off */
145362306a36Sopenharmony_ci		} else if (aha152x_priv(DONE_SC)->status == SAM_STAT_CHECK_CONDITION) {
145462306a36Sopenharmony_ci#if defined(AHA152X_STAT)
145562306a36Sopenharmony_ci			HOSTDATA(shpnt)->busfree_with_check_condition++;
145662306a36Sopenharmony_ci#endif
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci			if (!(aha152x_priv(DONE_SC)->phase & not_issued)) {
145962306a36Sopenharmony_ci				struct aha152x_scdata *sc;
146062306a36Sopenharmony_ci				struct scsi_cmnd *ptr = DONE_SC;
146162306a36Sopenharmony_ci				DONE_SC=NULL;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci				sc = SCDATA(ptr);
146462306a36Sopenharmony_ci				/* It was allocated in aha152x_internal_queue? */
146562306a36Sopenharmony_ci				BUG_ON(!sc);
146662306a36Sopenharmony_ci				scsi_eh_prep_cmnd(ptr, &sc->ses, NULL, 0, ~0);
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci				DO_UNLOCK(flags);
146962306a36Sopenharmony_ci				aha152x_internal_queue(ptr, NULL, check_condition);
147062306a36Sopenharmony_ci				DO_LOCK(flags);
147162306a36Sopenharmony_ci			}
147262306a36Sopenharmony_ci		}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci		if (DONE_SC) {
147562306a36Sopenharmony_ci			struct scsi_cmnd *ptr = DONE_SC;
147662306a36Sopenharmony_ci			DONE_SC=NULL;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci			/* turn led off, when no commands are in the driver */
147962306a36Sopenharmony_ci			HOSTDATA(shpnt)->commands--;
148062306a36Sopenharmony_ci			if (!HOSTDATA(shpnt)->commands)
148162306a36Sopenharmony_ci				SETPORT(PORTA, 0);	/* turn led off */
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci			if (!(aha152x_priv(ptr)->phase & resetting)) {
148462306a36Sopenharmony_ci				kfree(ptr->host_scribble);
148562306a36Sopenharmony_ci				ptr->host_scribble=NULL;
148662306a36Sopenharmony_ci			}
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci			DO_UNLOCK(flags);
148962306a36Sopenharmony_ci			aha152x_scsi_done(ptr);
149062306a36Sopenharmony_ci			DO_LOCK(flags);
149162306a36Sopenharmony_ci		}
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci		DONE_SC=NULL;
149462306a36Sopenharmony_ci#if defined(AHA152X_STAT)
149562306a36Sopenharmony_ci	} else {
149662306a36Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_done_command++;
149762306a36Sopenharmony_ci#endif
149862306a36Sopenharmony_ci	}
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	if(ISSUE_SC)
150162306a36Sopenharmony_ci		CURRENT_SC = remove_first_SC(&ISSUE_SC);
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	DO_UNLOCK(flags);
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	if(CURRENT_SC) {
150662306a36Sopenharmony_ci		struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci#if defined(AHA152X_STAT)
150962306a36Sopenharmony_ci		action++;
151062306a36Sopenharmony_ci#endif
151162306a36Sopenharmony_ci		acp->phase |= selecting;
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci		/* clear selection timeout */
151462306a36Sopenharmony_ci		SETPORT(SSTAT1, SELTO);
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci		SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->device->id);
151762306a36Sopenharmony_ci		SETPORT(SXFRCTL1, (PARITY ? ENSPCHK : 0 ) | ENSTIMER);
151862306a36Sopenharmony_ci		SETPORT(SCSISEQ, ENSELO | ENAUTOATNO | (DISCONNECTED_SC ? ENRESELI : 0));
151962306a36Sopenharmony_ci	} else {
152062306a36Sopenharmony_ci#if defined(AHA152X_STAT)
152162306a36Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_new_command++;
152262306a36Sopenharmony_ci#endif
152362306a36Sopenharmony_ci		SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
152462306a36Sopenharmony_ci	}
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci#if defined(AHA152X_STAT)
152762306a36Sopenharmony_ci	if(!action)
152862306a36Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_any_action++;
152962306a36Sopenharmony_ci#endif
153062306a36Sopenharmony_ci}
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci/*
153362306a36Sopenharmony_ci * Selection done (OUT)
153462306a36Sopenharmony_ci * - queue IDENTIFY message and SDTR to selected target for message out
153562306a36Sopenharmony_ci *   (ATN asserted automagically via ENAUTOATNO in busfree())
153662306a36Sopenharmony_ci */
153762306a36Sopenharmony_cistatic void seldo_run(struct Scsi_Host *shpnt)
153862306a36Sopenharmony_ci{
153962306a36Sopenharmony_ci	struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	SETPORT(SCSISIG, 0);
154262306a36Sopenharmony_ci	SETPORT(SSTAT1, CLRBUSFREE);
154362306a36Sopenharmony_ci	SETPORT(SSTAT1, CLRPHASECHG);
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	acp->phase &= ~(selecting | not_issued);
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci	SETPORT(SCSISEQ, 0);
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	if (TESTLO(SSTAT0, SELDO)) {
155062306a36Sopenharmony_ci		scmd_printk(KERN_ERR, CURRENT_SC,
155162306a36Sopenharmony_ci			    "aha152x: passing bus free condition\n");
155262306a36Sopenharmony_ci		done(shpnt, SAM_STAT_GOOD, DID_NO_CONNECT);
155362306a36Sopenharmony_ci		return;
155462306a36Sopenharmony_ci	}
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	SETPORT(SSTAT0, CLRSELDO);
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	if (acp->phase & aborting) {
156162306a36Sopenharmony_ci		ADDMSGO(ABORT);
156262306a36Sopenharmony_ci	} else if (acp->phase & resetting) {
156362306a36Sopenharmony_ci		ADDMSGO(BUS_DEVICE_RESET);
156462306a36Sopenharmony_ci	} else if (SYNCNEG==0 && SYNCHRONOUS) {
156562306a36Sopenharmony_ci		acp->phase |= syncneg;
156662306a36Sopenharmony_ci		MSGOLEN += spi_populate_sync_msg(&MSGO(MSGOLEN), 50, 8);
156762306a36Sopenharmony_ci		SYNCNEG=1;		/* negotiation in progress */
156862306a36Sopenharmony_ci	}
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	SETRATE(SYNCRATE);
157162306a36Sopenharmony_ci}
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci/*
157462306a36Sopenharmony_ci * Selection timeout
157562306a36Sopenharmony_ci * - return command to mid-level with failure cause
157662306a36Sopenharmony_ci *
157762306a36Sopenharmony_ci */
157862306a36Sopenharmony_cistatic void selto_run(struct Scsi_Host *shpnt)
157962306a36Sopenharmony_ci{
158062306a36Sopenharmony_ci	struct aha152x_cmd_priv *acp;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	SETPORT(SCSISEQ, 0);
158362306a36Sopenharmony_ci	SETPORT(SSTAT1, CLRSELTIMO);
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	if (!CURRENT_SC)
158662306a36Sopenharmony_ci		return;
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	acp = aha152x_priv(CURRENT_SC);
158962306a36Sopenharmony_ci	acp->phase &= ~selecting;
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	if (acp->phase & aborted)
159262306a36Sopenharmony_ci		done(shpnt, SAM_STAT_GOOD, DID_ABORT);
159362306a36Sopenharmony_ci	else if (TESTLO(SSTAT0, SELINGO))
159462306a36Sopenharmony_ci		done(shpnt, SAM_STAT_GOOD, DID_BUS_BUSY);
159562306a36Sopenharmony_ci	else
159662306a36Sopenharmony_ci		/* ARBITRATION won, but SELECTION failed */
159762306a36Sopenharmony_ci		done(shpnt, SAM_STAT_GOOD, DID_NO_CONNECT);
159862306a36Sopenharmony_ci}
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci/*
160162306a36Sopenharmony_ci * Selection in done
160262306a36Sopenharmony_ci * - put current command back to issue queue
160362306a36Sopenharmony_ci *   (reconnection of a disconnected nexus instead
160462306a36Sopenharmony_ci *    of successful selection out)
160562306a36Sopenharmony_ci *
160662306a36Sopenharmony_ci */
160762306a36Sopenharmony_cistatic void seldi_run(struct Scsi_Host *shpnt)
160862306a36Sopenharmony_ci{
160962306a36Sopenharmony_ci	int selid;
161062306a36Sopenharmony_ci	int target;
161162306a36Sopenharmony_ci	unsigned long flags;
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	SETPORT(SCSISIG, 0);
161462306a36Sopenharmony_ci	SETPORT(SSTAT0, CLRSELDI);
161562306a36Sopenharmony_ci	SETPORT(SSTAT1, CLRBUSFREE);
161662306a36Sopenharmony_ci	SETPORT(SSTAT1, CLRPHASECHG);
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	if(CURRENT_SC) {
161962306a36Sopenharmony_ci		struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci		if (!(acp->phase & not_issued))
162262306a36Sopenharmony_ci			scmd_printk(KERN_ERR, CURRENT_SC,
162362306a36Sopenharmony_ci				    "command should not have been issued yet\n");
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci		DO_LOCK(flags);
162662306a36Sopenharmony_ci		append_SC(&ISSUE_SC, CURRENT_SC);
162762306a36Sopenharmony_ci		DO_UNLOCK(flags);
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci		CURRENT_SC = NULL;
163062306a36Sopenharmony_ci	}
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	if (!DISCONNECTED_SC)
163362306a36Sopenharmony_ci		return;
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	RECONN_TARGET=-1;
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	selid = GETPORT(SELID) & ~(1 << shpnt->this_id);
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	if (selid==0) {
164062306a36Sopenharmony_ci		shost_printk(KERN_INFO, shpnt,
164162306a36Sopenharmony_ci			     "target id unknown (%02x)\n", selid);
164262306a36Sopenharmony_ci		return;
164362306a36Sopenharmony_ci	}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	for(target=7; !(selid & (1 << target)); target--)
164662306a36Sopenharmony_ci		;
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	if(selid & ~(1 << target)) {
164962306a36Sopenharmony_ci		shost_printk(KERN_INFO, shpnt,
165062306a36Sopenharmony_ci			     "multiple targets reconnected (%02x)\n", selid);
165162306a36Sopenharmony_ci	}
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	SETPORT(SCSIID, (shpnt->this_id << OID_) | target);
165562306a36Sopenharmony_ci	SETPORT(SCSISEQ, 0);
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	SETRATE(HOSTDATA(shpnt)->syncrate[target]);
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	RECONN_TARGET=target;
166062306a36Sopenharmony_ci}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci/*
166362306a36Sopenharmony_ci * message in phase
166462306a36Sopenharmony_ci * - handle initial message after reconnection to identify
166562306a36Sopenharmony_ci *   reconnecting nexus
166662306a36Sopenharmony_ci * - queue command on DISCONNECTED_SC on DISCONNECT message
166762306a36Sopenharmony_ci * - set completed flag on COMMAND COMPLETE
166862306a36Sopenharmony_ci *   (other completition code moved to busfree_run)
166962306a36Sopenharmony_ci * - handle response to SDTR
167062306a36Sopenharmony_ci * - clear synchronous transfer agreements on BUS RESET
167162306a36Sopenharmony_ci *
167262306a36Sopenharmony_ci * FIXME: what about SAVE POINTERS, RESTORE POINTERS?
167362306a36Sopenharmony_ci *
167462306a36Sopenharmony_ci */
167562306a36Sopenharmony_cistatic void msgi_run(struct Scsi_Host *shpnt)
167662306a36Sopenharmony_ci{
167762306a36Sopenharmony_ci	for(;;) {
167862306a36Sopenharmony_ci		struct aha152x_cmd_priv *acp;
167962306a36Sopenharmony_ci		int sstat1 = GETPORT(SSTAT1);
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci		if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT))
168262306a36Sopenharmony_ci			return;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci		if (TESTLO(SSTAT0, SPIORDY))
168562306a36Sopenharmony_ci			return;
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci		ADDMSGI(GETPORT(SCSIDAT));
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci		if(!CURRENT_SC) {
169062306a36Sopenharmony_ci			if(LASTSTATE!=seldi) {
169162306a36Sopenharmony_ci				shost_printk(KERN_ERR, shpnt,
169262306a36Sopenharmony_ci					     "message in w/o current command"
169362306a36Sopenharmony_ci					     " not after reselection\n");
169462306a36Sopenharmony_ci			}
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci			/*
169762306a36Sopenharmony_ci			 * Handle reselection
169862306a36Sopenharmony_ci			 */
169962306a36Sopenharmony_ci			if(!(MSGI(0) & IDENTIFY_BASE)) {
170062306a36Sopenharmony_ci				shost_printk(KERN_ERR, shpnt,
170162306a36Sopenharmony_ci					     "target didn't identify after reselection\n");
170262306a36Sopenharmony_ci				continue;
170362306a36Sopenharmony_ci			}
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci			CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f);
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci			if (!CURRENT_SC) {
170862306a36Sopenharmony_ci				show_queues(shpnt);
170962306a36Sopenharmony_ci				shost_printk(KERN_ERR, shpnt,
171062306a36Sopenharmony_ci					     "no disconnected command"
171162306a36Sopenharmony_ci					     " for target %d/%d\n",
171262306a36Sopenharmony_ci					     RECONN_TARGET, MSGI(0) & 0x3f);
171362306a36Sopenharmony_ci				continue;
171462306a36Sopenharmony_ci			}
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci			acp = aha152x_priv(CURRENT_SC);
171762306a36Sopenharmony_ci			acp->message = MSGI(0);
171862306a36Sopenharmony_ci			acp->phase &= ~disconnected;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci			MSGILEN=0;
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci			/* next message if any */
172362306a36Sopenharmony_ci			continue;
172462306a36Sopenharmony_ci		}
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci		acp = aha152x_priv(CURRENT_SC);
172762306a36Sopenharmony_ci		acp->message = MSGI(0);
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci		switch (MSGI(0)) {
173062306a36Sopenharmony_ci		case DISCONNECT:
173162306a36Sopenharmony_ci			if (!RECONNECT)
173262306a36Sopenharmony_ci				scmd_printk(KERN_WARNING, CURRENT_SC,
173362306a36Sopenharmony_ci					    "target was not allowed to disconnect\n");
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci			acp->phase |= disconnected;
173662306a36Sopenharmony_ci			break;
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci		case COMMAND_COMPLETE:
173962306a36Sopenharmony_ci			acp->phase |= completed;
174062306a36Sopenharmony_ci			break;
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci		case MESSAGE_REJECT:
174362306a36Sopenharmony_ci			if (SYNCNEG==1) {
174462306a36Sopenharmony_ci				scmd_printk(KERN_INFO, CURRENT_SC,
174562306a36Sopenharmony_ci					    "Synchronous Data Transfer Request"
174662306a36Sopenharmony_ci					    " was rejected\n");
174762306a36Sopenharmony_ci				SYNCNEG=2;	/* negotiation completed */
174862306a36Sopenharmony_ci			} else
174962306a36Sopenharmony_ci				scmd_printk(KERN_INFO, CURRENT_SC,
175062306a36Sopenharmony_ci					    "inbound message (MESSAGE REJECT)\n");
175162306a36Sopenharmony_ci			break;
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci		case SAVE_POINTERS:
175462306a36Sopenharmony_ci			break;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci		case RESTORE_POINTERS:
175762306a36Sopenharmony_ci			break;
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci		case EXTENDED_MESSAGE:
176062306a36Sopenharmony_ci			if(MSGILEN<2 || MSGILEN<MSGI(1)+2) {
176162306a36Sopenharmony_ci				/* not yet completed */
176262306a36Sopenharmony_ci				continue;
176362306a36Sopenharmony_ci			}
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci			switch (MSGI(2)) {
176662306a36Sopenharmony_ci			case EXTENDED_SDTR:
176762306a36Sopenharmony_ci				{
176862306a36Sopenharmony_ci					long ticks;
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci					if (MSGI(1) != 3) {
177162306a36Sopenharmony_ci						scmd_printk(KERN_ERR, CURRENT_SC,
177262306a36Sopenharmony_ci							    "SDTR message length!=3\n");
177362306a36Sopenharmony_ci						break;
177462306a36Sopenharmony_ci					}
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci					if (!HOSTDATA(shpnt)->synchronous)
177762306a36Sopenharmony_ci						break;
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci					printk(INFO_LEAD, CMDINFO(CURRENT_SC));
178062306a36Sopenharmony_ci					spi_print_msg(&MSGI(0));
178162306a36Sopenharmony_ci					printk("\n");
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci					ticks = (MSGI(3) * 4 + 49) / 50;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci					if (syncneg) {
178662306a36Sopenharmony_ci						/* negotiation in progress */
178762306a36Sopenharmony_ci						if (ticks > 9 || MSGI(4) < 1 || MSGI(4) > 8) {
178862306a36Sopenharmony_ci							ADDMSGO(MESSAGE_REJECT);
178962306a36Sopenharmony_ci							scmd_printk(KERN_INFO,
179062306a36Sopenharmony_ci								    CURRENT_SC,
179162306a36Sopenharmony_ci								    "received Synchronous Data Transfer Request invalid - rejected\n");
179262306a36Sopenharmony_ci							break;
179362306a36Sopenharmony_ci						}
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci						SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
179662306a36Sopenharmony_ci					} else if (ticks <= 9 && MSGI(4) >= 1) {
179762306a36Sopenharmony_ci						ADDMSGO(EXTENDED_MESSAGE);
179862306a36Sopenharmony_ci						ADDMSGO(3);
179962306a36Sopenharmony_ci						ADDMSGO(EXTENDED_SDTR);
180062306a36Sopenharmony_ci						if (ticks < 4) {
180162306a36Sopenharmony_ci							ticks = 4;
180262306a36Sopenharmony_ci							ADDMSGO(50);
180362306a36Sopenharmony_ci						} else
180462306a36Sopenharmony_ci							ADDMSGO(MSGI(3));
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci						if (MSGI(4) > 8)
180762306a36Sopenharmony_ci							MSGI(4) = 8;
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci						ADDMSGO(MSGI(4));
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci						SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
181262306a36Sopenharmony_ci					} else {
181362306a36Sopenharmony_ci						/* requested SDTR is too slow, do it asynchronously */
181462306a36Sopenharmony_ci						scmd_printk(KERN_INFO,
181562306a36Sopenharmony_ci							    CURRENT_SC,
181662306a36Sopenharmony_ci							    "Synchronous Data Transfer Request too slow - Rejecting\n");
181762306a36Sopenharmony_ci						ADDMSGO(MESSAGE_REJECT);
181862306a36Sopenharmony_ci					}
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci					/* negotiation completed */
182162306a36Sopenharmony_ci					SYNCNEG=2;
182262306a36Sopenharmony_ci					SETRATE(SYNCRATE);
182362306a36Sopenharmony_ci				}
182462306a36Sopenharmony_ci				break;
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci			case BUS_DEVICE_RESET:
182762306a36Sopenharmony_ci				{
182862306a36Sopenharmony_ci					int i;
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci					for(i=0; i<8; i++) {
183162306a36Sopenharmony_ci						HOSTDATA(shpnt)->syncrate[i]=0;
183262306a36Sopenharmony_ci						HOSTDATA(shpnt)->syncneg[i]=0;
183362306a36Sopenharmony_ci					}
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci				}
183662306a36Sopenharmony_ci				break;
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci			case EXTENDED_MODIFY_DATA_POINTER:
183962306a36Sopenharmony_ci			case EXTENDED_EXTENDED_IDENTIFY:
184062306a36Sopenharmony_ci			case EXTENDED_WDTR:
184162306a36Sopenharmony_ci			default:
184262306a36Sopenharmony_ci				ADDMSGO(MESSAGE_REJECT);
184362306a36Sopenharmony_ci				break;
184462306a36Sopenharmony_ci			}
184562306a36Sopenharmony_ci			break;
184662306a36Sopenharmony_ci		}
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci		MSGILEN=0;
184962306a36Sopenharmony_ci	}
185062306a36Sopenharmony_ci}
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_cistatic void msgi_end(struct Scsi_Host *shpnt)
185362306a36Sopenharmony_ci{
185462306a36Sopenharmony_ci	if(MSGILEN>0)
185562306a36Sopenharmony_ci		scmd_printk(KERN_WARNING, CURRENT_SC,
185662306a36Sopenharmony_ci			    "target left before message completed (%d)\n",
185762306a36Sopenharmony_ci			    MSGILEN);
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE))
186062306a36Sopenharmony_ci		SETPORT(SCSISIG, P_MSGI | SIG_ATNO);
186162306a36Sopenharmony_ci}
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci/*
186462306a36Sopenharmony_ci * message out phase
186562306a36Sopenharmony_ci *
186662306a36Sopenharmony_ci */
186762306a36Sopenharmony_cistatic void msgo_init(struct Scsi_Host *shpnt)
186862306a36Sopenharmony_ci{
186962306a36Sopenharmony_ci	if(MSGOLEN==0) {
187062306a36Sopenharmony_ci		if ((aha152x_priv(CURRENT_SC)->phase & syncneg) &&
187162306a36Sopenharmony_ci		    SYNCNEG == 2 && SYNCRATE == 0) {
187262306a36Sopenharmony_ci			ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
187362306a36Sopenharmony_ci		} else {
187462306a36Sopenharmony_ci			scmd_printk(KERN_INFO, CURRENT_SC,
187562306a36Sopenharmony_ci				    "unexpected MESSAGE OUT phase; rejecting\n");
187662306a36Sopenharmony_ci			ADDMSGO(MESSAGE_REJECT);
187762306a36Sopenharmony_ci		}
187862306a36Sopenharmony_ci	}
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci}
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci/*
188362306a36Sopenharmony_ci * message out phase
188462306a36Sopenharmony_ci *
188562306a36Sopenharmony_ci */
188662306a36Sopenharmony_cistatic void msgo_run(struct Scsi_Host *shpnt)
188762306a36Sopenharmony_ci{
188862306a36Sopenharmony_ci	struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	while(MSGO_I<MSGOLEN) {
189162306a36Sopenharmony_ci		if (TESTLO(SSTAT0, SPIORDY))
189262306a36Sopenharmony_ci			return;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci		if (MSGO_I==MSGOLEN-1) {
189562306a36Sopenharmony_ci			/* Leave MESSAGE OUT after transfer */
189662306a36Sopenharmony_ci			SETPORT(SSTAT1, CLRATNO);
189762306a36Sopenharmony_ci		}
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci		if (MSGO(MSGO_I) & IDENTIFY_BASE)
190162306a36Sopenharmony_ci			acp->phase |= identified;
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci		if (MSGO(MSGO_I)==ABORT)
190462306a36Sopenharmony_ci			acp->phase |= aborted;
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci		if (MSGO(MSGO_I)==BUS_DEVICE_RESET)
190762306a36Sopenharmony_ci			acp->phase |= resetted;
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci		SETPORT(SCSIDAT, MSGO(MSGO_I++));
191062306a36Sopenharmony_ci	}
191162306a36Sopenharmony_ci}
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_cistatic void msgo_end(struct Scsi_Host *shpnt)
191462306a36Sopenharmony_ci{
191562306a36Sopenharmony_ci	if(MSGO_I<MSGOLEN) {
191662306a36Sopenharmony_ci		scmd_printk(KERN_ERR, CURRENT_SC,
191762306a36Sopenharmony_ci			    "message sent incompletely (%d/%d)\n",
191862306a36Sopenharmony_ci			    MSGO_I, MSGOLEN);
191962306a36Sopenharmony_ci		if(SYNCNEG==1) {
192062306a36Sopenharmony_ci			scmd_printk(KERN_INFO, CURRENT_SC,
192162306a36Sopenharmony_ci				    "Synchronous Data Transfer Request was rejected\n");
192262306a36Sopenharmony_ci			SYNCNEG=2;
192362306a36Sopenharmony_ci		}
192462306a36Sopenharmony_ci	}
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	MSGO_I  = 0;
192762306a36Sopenharmony_ci	MSGOLEN = 0;
192862306a36Sopenharmony_ci}
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci/*
193162306a36Sopenharmony_ci * command phase
193262306a36Sopenharmony_ci *
193362306a36Sopenharmony_ci */
193462306a36Sopenharmony_cistatic void cmd_init(struct Scsi_Host *shpnt)
193562306a36Sopenharmony_ci{
193662306a36Sopenharmony_ci	if (aha152x_priv(CURRENT_SC)->sent_command) {
193762306a36Sopenharmony_ci		scmd_printk(KERN_ERR, CURRENT_SC,
193862306a36Sopenharmony_ci			    "command already sent\n");
193962306a36Sopenharmony_ci		done(shpnt, SAM_STAT_GOOD, DID_ERROR);
194062306a36Sopenharmony_ci		return;
194162306a36Sopenharmony_ci	}
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	CMD_I=0;
194462306a36Sopenharmony_ci}
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci/*
194762306a36Sopenharmony_ci * command phase
194862306a36Sopenharmony_ci *
194962306a36Sopenharmony_ci */
195062306a36Sopenharmony_cistatic void cmd_run(struct Scsi_Host *shpnt)
195162306a36Sopenharmony_ci{
195262306a36Sopenharmony_ci	while(CMD_I<CURRENT_SC->cmd_len) {
195362306a36Sopenharmony_ci		if (TESTLO(SSTAT0, SPIORDY))
195462306a36Sopenharmony_ci			return;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci		SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]);
195762306a36Sopenharmony_ci	}
195862306a36Sopenharmony_ci}
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_cistatic void cmd_end(struct Scsi_Host *shpnt)
196162306a36Sopenharmony_ci{
196262306a36Sopenharmony_ci	if(CMD_I<CURRENT_SC->cmd_len)
196362306a36Sopenharmony_ci		scmd_printk(KERN_ERR, CURRENT_SC,
196462306a36Sopenharmony_ci			    "command sent incompletely (%d/%d)\n",
196562306a36Sopenharmony_ci			    CMD_I, CURRENT_SC->cmd_len);
196662306a36Sopenharmony_ci	else
196762306a36Sopenharmony_ci		aha152x_priv(CURRENT_SC)->sent_command++;
196862306a36Sopenharmony_ci}
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci/*
197162306a36Sopenharmony_ci * status phase
197262306a36Sopenharmony_ci *
197362306a36Sopenharmony_ci */
197462306a36Sopenharmony_cistatic void status_run(struct Scsi_Host *shpnt)
197562306a36Sopenharmony_ci{
197662306a36Sopenharmony_ci	if (TESTLO(SSTAT0, SPIORDY))
197762306a36Sopenharmony_ci		return;
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci	aha152x_priv(CURRENT_SC)->status = GETPORT(SCSIDAT);
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci}
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci/*
198462306a36Sopenharmony_ci * data in phase
198562306a36Sopenharmony_ci *
198662306a36Sopenharmony_ci */
198762306a36Sopenharmony_cistatic void datai_init(struct Scsi_Host *shpnt)
198862306a36Sopenharmony_ci{
198962306a36Sopenharmony_ci	SETPORT(DMACNTRL0, RSTFIFO);
199062306a36Sopenharmony_ci	SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
199362306a36Sopenharmony_ci	SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	SETPORT(SIMODE0, 0);
199662306a36Sopenharmony_ci	SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE);
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	DATA_LEN=0;
199962306a36Sopenharmony_ci}
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_cistatic void datai_run(struct Scsi_Host *shpnt)
200262306a36Sopenharmony_ci{
200362306a36Sopenharmony_ci	struct aha152x_cmd_priv *acp;
200462306a36Sopenharmony_ci	unsigned long the_time;
200562306a36Sopenharmony_ci	int fifodata, data_count;
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci	/*
200862306a36Sopenharmony_ci	 * loop while the phase persists or the fifos are not empty
200962306a36Sopenharmony_ci	 *
201062306a36Sopenharmony_ci	 */
201162306a36Sopenharmony_ci	while(TESTLO(DMASTAT, INTSTAT) || TESTLO(DMASTAT, DFIFOEMP) || TESTLO(SSTAT2, SEMPTY)) {
201262306a36Sopenharmony_ci		/* FIXME: maybe this should be done by setting up
201362306a36Sopenharmony_ci		 * STCNT to trigger ENSWRAP interrupt, instead of
201462306a36Sopenharmony_ci		 * polling for DFIFOFULL
201562306a36Sopenharmony_ci		 */
201662306a36Sopenharmony_ci		the_time=jiffies + 100*HZ;
201762306a36Sopenharmony_ci		while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time))
201862306a36Sopenharmony_ci			barrier();
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci		if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) {
202162306a36Sopenharmony_ci			scmd_printk(KERN_ERR, CURRENT_SC, "datai timeout\n");
202262306a36Sopenharmony_ci			break;
202362306a36Sopenharmony_ci		}
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci		if(TESTHI(DMASTAT, DFIFOFULL)) {
202662306a36Sopenharmony_ci			fifodata = 128;
202762306a36Sopenharmony_ci		} else {
202862306a36Sopenharmony_ci			the_time=jiffies + 100*HZ;
202962306a36Sopenharmony_ci			while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time))
203062306a36Sopenharmony_ci				barrier();
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci			if(TESTLO(SSTAT2, SEMPTY)) {
203362306a36Sopenharmony_ci				scmd_printk(KERN_ERR, CURRENT_SC,
203462306a36Sopenharmony_ci					    "datai sempty timeout");
203562306a36Sopenharmony_ci				break;
203662306a36Sopenharmony_ci			}
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci			fifodata = GETPORT(FIFOSTAT);
203962306a36Sopenharmony_ci		}
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_ci		acp = aha152x_priv(CURRENT_SC);
204262306a36Sopenharmony_ci		if (acp->this_residual > 0) {
204362306a36Sopenharmony_ci			while (fifodata > 0 && acp->this_residual > 0) {
204462306a36Sopenharmony_ci				data_count = fifodata > acp->this_residual ?
204562306a36Sopenharmony_ci						acp->this_residual : fifodata;
204662306a36Sopenharmony_ci				fifodata -= data_count;
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci				if (data_count & 1) {
204962306a36Sopenharmony_ci					SETPORT(DMACNTRL0, ENDMA|_8BIT);
205062306a36Sopenharmony_ci					*acp->ptr++ = GETPORT(DATAPORT);
205162306a36Sopenharmony_ci					acp->this_residual--;
205262306a36Sopenharmony_ci					DATA_LEN++;
205362306a36Sopenharmony_ci					SETPORT(DMACNTRL0, ENDMA);
205462306a36Sopenharmony_ci				}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci				if (data_count > 1) {
205762306a36Sopenharmony_ci					data_count >>= 1;
205862306a36Sopenharmony_ci					insw(DATAPORT, acp->ptr, data_count);
205962306a36Sopenharmony_ci					acp->ptr += 2 * data_count;
206062306a36Sopenharmony_ci					acp->this_residual -= 2 * data_count;
206162306a36Sopenharmony_ci					DATA_LEN += 2 * data_count;
206262306a36Sopenharmony_ci				}
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci				if (acp->this_residual == 0 &&
206562306a36Sopenharmony_ci				    !sg_is_last(acp->buffer)) {
206662306a36Sopenharmony_ci					/* advance to next buffer */
206762306a36Sopenharmony_ci					acp->buffer = sg_next(acp->buffer);
206862306a36Sopenharmony_ci					acp->ptr = SG_ADDRESS(acp->buffer);
206962306a36Sopenharmony_ci					acp->this_residual = acp->buffer->length;
207062306a36Sopenharmony_ci				}
207162306a36Sopenharmony_ci			}
207262306a36Sopenharmony_ci		} else if (fifodata > 0) {
207362306a36Sopenharmony_ci			scmd_printk(KERN_ERR, CURRENT_SC,
207462306a36Sopenharmony_ci				    "no buffers left for %d(%d) bytes"
207562306a36Sopenharmony_ci				    " (data overrun!?)\n",
207662306a36Sopenharmony_ci				    fifodata, GETPORT(FIFOSTAT));
207762306a36Sopenharmony_ci			SETPORT(DMACNTRL0, ENDMA|_8BIT);
207862306a36Sopenharmony_ci			while(fifodata>0) {
207962306a36Sopenharmony_ci				GETPORT(DATAPORT);
208062306a36Sopenharmony_ci				fifodata--;
208162306a36Sopenharmony_ci				DATA_LEN++;
208262306a36Sopenharmony_ci			}
208362306a36Sopenharmony_ci			SETPORT(DMACNTRL0, ENDMA|_8BIT);
208462306a36Sopenharmony_ci		}
208562306a36Sopenharmony_ci	}
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	if(TESTLO(DMASTAT, INTSTAT) ||
208862306a36Sopenharmony_ci	   TESTLO(DMASTAT, DFIFOEMP) ||
208962306a36Sopenharmony_ci	   TESTLO(SSTAT2, SEMPTY) ||
209062306a36Sopenharmony_ci	   GETPORT(FIFOSTAT)>0) {
209162306a36Sopenharmony_ci		/*
209262306a36Sopenharmony_ci		 * something went wrong, if there's something left in the fifos
209362306a36Sopenharmony_ci		 * or the phase didn't change
209462306a36Sopenharmony_ci		 */
209562306a36Sopenharmony_ci		scmd_printk(KERN_ERR, CURRENT_SC,
209662306a36Sopenharmony_ci			    "fifos should be empty and phase should have changed\n");
209762306a36Sopenharmony_ci	}
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	if(DATA_LEN!=GETSTCNT()) {
210062306a36Sopenharmony_ci		scmd_printk(KERN_ERR, CURRENT_SC,
210162306a36Sopenharmony_ci			    "manual transfer count differs from automatic "
210262306a36Sopenharmony_ci			    "(count=%d;stcnt=%d;diff=%d;fifostat=%d)",
210362306a36Sopenharmony_ci			    DATA_LEN, GETSTCNT(), GETSTCNT()-DATA_LEN,
210462306a36Sopenharmony_ci			    GETPORT(FIFOSTAT));
210562306a36Sopenharmony_ci		mdelay(10000);
210662306a36Sopenharmony_ci	}
210762306a36Sopenharmony_ci}
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_cistatic void datai_end(struct Scsi_Host *shpnt)
211062306a36Sopenharmony_ci{
211162306a36Sopenharmony_ci	CMD_INC_RESID(CURRENT_SC, -GETSTCNT());
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
211462306a36Sopenharmony_ci	SETPORT(DMACNTRL0, 0);
211562306a36Sopenharmony_ci}
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci/*
211862306a36Sopenharmony_ci * data out phase
211962306a36Sopenharmony_ci *
212062306a36Sopenharmony_ci */
212162306a36Sopenharmony_cistatic void datao_init(struct Scsi_Host *shpnt)
212262306a36Sopenharmony_ci{
212362306a36Sopenharmony_ci	SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
212462306a36Sopenharmony_ci	SETPORT(DMACNTRL0, WRITE_READ | ENDMA);
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
212762306a36Sopenharmony_ci	SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	SETPORT(SIMODE0, 0);
213062306a36Sopenharmony_ci	SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE );
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci	DATA_LEN = scsi_get_resid(CURRENT_SC);
213362306a36Sopenharmony_ci}
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_cistatic void datao_run(struct Scsi_Host *shpnt)
213662306a36Sopenharmony_ci{
213762306a36Sopenharmony_ci	struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
213862306a36Sopenharmony_ci	unsigned long the_time;
213962306a36Sopenharmony_ci	int data_count;
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	/* until phase changes or all data sent */
214262306a36Sopenharmony_ci	while (TESTLO(DMASTAT, INTSTAT) && acp->this_residual > 0) {
214362306a36Sopenharmony_ci		data_count = 128;
214462306a36Sopenharmony_ci		if (data_count > acp->this_residual)
214562306a36Sopenharmony_ci			data_count = acp->this_residual;
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci		if(TESTLO(DMASTAT, DFIFOEMP)) {
214862306a36Sopenharmony_ci			scmd_printk(KERN_ERR, CURRENT_SC,
214962306a36Sopenharmony_ci				    "datao fifo not empty (%d)",
215062306a36Sopenharmony_ci				    GETPORT(FIFOSTAT));
215162306a36Sopenharmony_ci			break;
215262306a36Sopenharmony_ci		}
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci		if(data_count & 1) {
215562306a36Sopenharmony_ci			SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT);
215662306a36Sopenharmony_ci			SETPORT(DATAPORT, *acp->ptr++);
215762306a36Sopenharmony_ci			acp->this_residual--;
215862306a36Sopenharmony_ci			CMD_INC_RESID(CURRENT_SC, -1);
215962306a36Sopenharmony_ci			SETPORT(DMACNTRL0,WRITE_READ|ENDMA);
216062306a36Sopenharmony_ci		}
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci		if(data_count > 1) {
216362306a36Sopenharmony_ci			data_count >>= 1;
216462306a36Sopenharmony_ci			outsw(DATAPORT, acp->ptr, data_count);
216562306a36Sopenharmony_ci			acp->ptr += 2 * data_count;
216662306a36Sopenharmony_ci			acp->this_residual -= 2 * data_count;
216762306a36Sopenharmony_ci			CMD_INC_RESID(CURRENT_SC, -2 * data_count);
216862306a36Sopenharmony_ci		}
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci		if (acp->this_residual == 0 && !sg_is_last(acp->buffer)) {
217162306a36Sopenharmony_ci			/* advance to next buffer */
217262306a36Sopenharmony_ci			acp->buffer = sg_next(acp->buffer);
217362306a36Sopenharmony_ci			acp->ptr = SG_ADDRESS(acp->buffer);
217462306a36Sopenharmony_ci			acp->this_residual = acp->buffer->length;
217562306a36Sopenharmony_ci		}
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci		the_time=jiffies + 100*HZ;
217862306a36Sopenharmony_ci		while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time))
217962306a36Sopenharmony_ci			barrier();
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci		if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) {
218262306a36Sopenharmony_ci			scmd_printk(KERN_ERR, CURRENT_SC, "dataout timeout\n");
218362306a36Sopenharmony_ci			break;
218462306a36Sopenharmony_ci		}
218562306a36Sopenharmony_ci	}
218662306a36Sopenharmony_ci}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_cistatic void datao_end(struct Scsi_Host *shpnt)
218962306a36Sopenharmony_ci{
219062306a36Sopenharmony_ci	struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	if(TESTLO(DMASTAT, DFIFOEMP)) {
219362306a36Sopenharmony_ci		u32 datao_cnt = GETSTCNT();
219462306a36Sopenharmony_ci		int datao_out = DATA_LEN - scsi_get_resid(CURRENT_SC);
219562306a36Sopenharmony_ci		int done;
219662306a36Sopenharmony_ci		struct scatterlist *sg = scsi_sglist(CURRENT_SC);
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_ci		CMD_INC_RESID(CURRENT_SC, datao_out - datao_cnt);
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci		done = scsi_bufflen(CURRENT_SC) - scsi_get_resid(CURRENT_SC);
220162306a36Sopenharmony_ci		/* Locate the first SG entry not yet sent */
220262306a36Sopenharmony_ci		while (done > 0 && !sg_is_last(sg)) {
220362306a36Sopenharmony_ci			if (done < sg->length)
220462306a36Sopenharmony_ci				break;
220562306a36Sopenharmony_ci			done -= sg->length;
220662306a36Sopenharmony_ci			sg = sg_next(sg);
220762306a36Sopenharmony_ci		}
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci		acp->buffer = sg;
221062306a36Sopenharmony_ci		acp->ptr = SG_ADDRESS(acp->buffer) + done;
221162306a36Sopenharmony_ci		acp->this_residual = acp->buffer->length - done;
221262306a36Sopenharmony_ci	}
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
221562306a36Sopenharmony_ci	SETPORT(SXFRCTL0, CH1);
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci	SETPORT(DMACNTRL0, 0);
221862306a36Sopenharmony_ci}
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci/*
222162306a36Sopenharmony_ci * figure out what state we're in
222262306a36Sopenharmony_ci *
222362306a36Sopenharmony_ci */
222462306a36Sopenharmony_cistatic int update_state(struct Scsi_Host *shpnt)
222562306a36Sopenharmony_ci{
222662306a36Sopenharmony_ci	int dataphase=0;
222762306a36Sopenharmony_ci	unsigned int stat0 = GETPORT(SSTAT0);
222862306a36Sopenharmony_ci	unsigned int stat1 = GETPORT(SSTAT1);
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	PREVSTATE = STATE;
223162306a36Sopenharmony_ci	STATE=unknown;
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ci	if(stat1 & SCSIRSTI) {
223462306a36Sopenharmony_ci		STATE=rsti;
223562306a36Sopenharmony_ci		SETPORT(SCSISEQ,0);
223662306a36Sopenharmony_ci		SETPORT(SSTAT1,SCSIRSTI);
223762306a36Sopenharmony_ci	} else if (stat0 & SELDI && PREVSTATE == busfree) {
223862306a36Sopenharmony_ci		STATE=seldi;
223962306a36Sopenharmony_ci	} else if (stat0 & SELDO && CURRENT_SC &&
224062306a36Sopenharmony_ci		   (aha152x_priv(CURRENT_SC)->phase & selecting)) {
224162306a36Sopenharmony_ci		STATE=seldo;
224262306a36Sopenharmony_ci	} else if(stat1 & SELTO) {
224362306a36Sopenharmony_ci		STATE=selto;
224462306a36Sopenharmony_ci	} else if(stat1 & BUSFREE) {
224562306a36Sopenharmony_ci		STATE=busfree;
224662306a36Sopenharmony_ci		SETPORT(SSTAT1,BUSFREE);
224762306a36Sopenharmony_ci	} else if(stat1 & SCSIPERR) {
224862306a36Sopenharmony_ci		STATE=parerr;
224962306a36Sopenharmony_ci		SETPORT(SSTAT1,SCSIPERR);
225062306a36Sopenharmony_ci	} else if(stat1 & REQINIT) {
225162306a36Sopenharmony_ci		switch(GETPORT(SCSISIG) & P_MASK) {
225262306a36Sopenharmony_ci		case P_MSGI:	STATE=msgi;	break;
225362306a36Sopenharmony_ci		case P_MSGO:	STATE=msgo;	break;
225462306a36Sopenharmony_ci		case P_DATAO:	STATE=datao;	break;
225562306a36Sopenharmony_ci		case P_DATAI:	STATE=datai;	break;
225662306a36Sopenharmony_ci		case P_STATUS:	STATE=status;	break;
225762306a36Sopenharmony_ci		case P_CMD:	STATE=cmd;	break;
225862306a36Sopenharmony_ci		}
225962306a36Sopenharmony_ci		dataphase=1;
226062306a36Sopenharmony_ci	}
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	if((stat0 & SELDI) && STATE!=seldi && !dataphase) {
226362306a36Sopenharmony_ci		scmd_printk(KERN_INFO, CURRENT_SC, "reselection missed?");
226462306a36Sopenharmony_ci	}
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci	if(STATE!=PREVSTATE) {
226762306a36Sopenharmony_ci		LASTSTATE=PREVSTATE;
226862306a36Sopenharmony_ci	}
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci	return dataphase;
227162306a36Sopenharmony_ci}
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci/*
227462306a36Sopenharmony_ci * handle parity error
227562306a36Sopenharmony_ci *
227662306a36Sopenharmony_ci * FIXME: in which phase?
227762306a36Sopenharmony_ci *
227862306a36Sopenharmony_ci */
227962306a36Sopenharmony_cistatic void parerr_run(struct Scsi_Host *shpnt)
228062306a36Sopenharmony_ci{
228162306a36Sopenharmony_ci	scmd_printk(KERN_ERR, CURRENT_SC, "parity error\n");
228262306a36Sopenharmony_ci	done(shpnt, SAM_STAT_GOOD, DID_PARITY);
228362306a36Sopenharmony_ci}
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ci/*
228662306a36Sopenharmony_ci * handle reset in
228762306a36Sopenharmony_ci *
228862306a36Sopenharmony_ci */
228962306a36Sopenharmony_cistatic void rsti_run(struct Scsi_Host *shpnt)
229062306a36Sopenharmony_ci{
229162306a36Sopenharmony_ci	struct scsi_cmnd *ptr;
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_ci	shost_printk(KERN_NOTICE, shpnt, "scsi reset in\n");
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	ptr=DISCONNECTED_SC;
229662306a36Sopenharmony_ci	while(ptr) {
229762306a36Sopenharmony_ci		struct scsi_cmnd *next = SCNEXT(ptr);
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ci		if (!ptr->device->soft_reset) {
230062306a36Sopenharmony_ci			remove_SC(&DISCONNECTED_SC, ptr);
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci			kfree(ptr->host_scribble);
230362306a36Sopenharmony_ci			ptr->host_scribble=NULL;
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci			set_host_byte(ptr, DID_RESET);
230662306a36Sopenharmony_ci			aha152x_scsi_done(ptr);
230762306a36Sopenharmony_ci		}
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci		ptr = next;
231062306a36Sopenharmony_ci	}
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_ci	if(CURRENT_SC && !CURRENT_SC->device->soft_reset)
231362306a36Sopenharmony_ci		done(shpnt, SAM_STAT_GOOD, DID_RESET);
231462306a36Sopenharmony_ci}
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci/*
231862306a36Sopenharmony_ci * bottom-half handler
231962306a36Sopenharmony_ci *
232062306a36Sopenharmony_ci */
232162306a36Sopenharmony_cistatic void is_complete(struct Scsi_Host *shpnt)
232262306a36Sopenharmony_ci{
232362306a36Sopenharmony_ci	int dataphase;
232462306a36Sopenharmony_ci	unsigned long flags;
232562306a36Sopenharmony_ci	int pending;
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	if(!shpnt)
232862306a36Sopenharmony_ci		return;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	DO_LOCK(flags);
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci	if( HOSTDATA(shpnt)->service==0 )  {
233362306a36Sopenharmony_ci		DO_UNLOCK(flags);
233462306a36Sopenharmony_ci		return;
233562306a36Sopenharmony_ci	}
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci	HOSTDATA(shpnt)->service = 0;
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	if(HOSTDATA(shpnt)->in_intr) {
234062306a36Sopenharmony_ci		DO_UNLOCK(flags);
234162306a36Sopenharmony_ci		/* aha152x_error never returns.. */
234262306a36Sopenharmony_ci		aha152x_error(shpnt, "bottom-half already running!?");
234362306a36Sopenharmony_ci	}
234462306a36Sopenharmony_ci	HOSTDATA(shpnt)->in_intr++;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	/*
234762306a36Sopenharmony_ci	 * loop while there are interrupt conditions pending
234862306a36Sopenharmony_ci	 *
234962306a36Sopenharmony_ci	 */
235062306a36Sopenharmony_ci	do {
235162306a36Sopenharmony_ci		unsigned long start = jiffies;
235262306a36Sopenharmony_ci		DO_UNLOCK(flags);
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_ci		dataphase=update_state(shpnt);
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci		/*
235762306a36Sopenharmony_ci		 * end previous state
235862306a36Sopenharmony_ci		 *
235962306a36Sopenharmony_ci		 */
236062306a36Sopenharmony_ci		if(PREVSTATE!=STATE && states[PREVSTATE].end)
236162306a36Sopenharmony_ci			states[PREVSTATE].end(shpnt);
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci		/*
236462306a36Sopenharmony_ci		 * disable SPIO mode if previous phase used it
236562306a36Sopenharmony_ci		 * and this one doesn't
236662306a36Sopenharmony_ci		 *
236762306a36Sopenharmony_ci		 */
236862306a36Sopenharmony_ci		if(states[PREVSTATE].spio && !states[STATE].spio) {
236962306a36Sopenharmony_ci			SETPORT(SXFRCTL0, CH1);
237062306a36Sopenharmony_ci			SETPORT(DMACNTRL0, 0);
237162306a36Sopenharmony_ci			if(CURRENT_SC)
237262306a36Sopenharmony_ci				aha152x_priv(CURRENT_SC)->phase &= ~spiordy;
237362306a36Sopenharmony_ci		}
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci		/*
237662306a36Sopenharmony_ci		 * accept current dataphase phase
237762306a36Sopenharmony_ci		 *
237862306a36Sopenharmony_ci		 */
237962306a36Sopenharmony_ci		if(dataphase) {
238062306a36Sopenharmony_ci			SETPORT(SSTAT0, REQINIT);
238162306a36Sopenharmony_ci			SETPORT(SCSISIG, GETPORT(SCSISIG) & P_MASK);
238262306a36Sopenharmony_ci			SETPORT(SSTAT1, PHASECHG);
238362306a36Sopenharmony_ci		}
238462306a36Sopenharmony_ci
238562306a36Sopenharmony_ci		/*
238662306a36Sopenharmony_ci		 * enable SPIO mode if previous didn't use it
238762306a36Sopenharmony_ci		 * and this one does
238862306a36Sopenharmony_ci		 *
238962306a36Sopenharmony_ci		 */
239062306a36Sopenharmony_ci		if(!states[PREVSTATE].spio && states[STATE].spio) {
239162306a36Sopenharmony_ci			SETPORT(DMACNTRL0, 0);
239262306a36Sopenharmony_ci			SETPORT(SXFRCTL0, CH1|SPIOEN);
239362306a36Sopenharmony_ci			if(CURRENT_SC)
239462306a36Sopenharmony_ci				aha152x_priv(CURRENT_SC)->phase |= spiordy;
239562306a36Sopenharmony_ci		}
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci		/*
239862306a36Sopenharmony_ci		 * initialize for new state
239962306a36Sopenharmony_ci		 *
240062306a36Sopenharmony_ci		 */
240162306a36Sopenharmony_ci		if(PREVSTATE!=STATE && states[STATE].init)
240262306a36Sopenharmony_ci			states[STATE].init(shpnt);
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci		/*
240562306a36Sopenharmony_ci		 * handle current state
240662306a36Sopenharmony_ci		 *
240762306a36Sopenharmony_ci		 */
240862306a36Sopenharmony_ci		if(states[STATE].run)
240962306a36Sopenharmony_ci			states[STATE].run(shpnt);
241062306a36Sopenharmony_ci		else
241162306a36Sopenharmony_ci			scmd_printk(KERN_ERR, CURRENT_SC,
241262306a36Sopenharmony_ci				    "unexpected state (%x)\n", STATE);
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci		/*
241562306a36Sopenharmony_ci		 * setup controller to interrupt on
241662306a36Sopenharmony_ci		 * the next expected condition and
241762306a36Sopenharmony_ci		 * loop if it's already there
241862306a36Sopenharmony_ci		 *
241962306a36Sopenharmony_ci		 */
242062306a36Sopenharmony_ci		DO_LOCK(flags);
242162306a36Sopenharmony_ci		pending=setup_expected_interrupts(shpnt);
242262306a36Sopenharmony_ci#if defined(AHA152X_STAT)
242362306a36Sopenharmony_ci		HOSTDATA(shpnt)->count[STATE]++;
242462306a36Sopenharmony_ci		if(PREVSTATE!=STATE)
242562306a36Sopenharmony_ci			HOSTDATA(shpnt)->count_trans[STATE]++;
242662306a36Sopenharmony_ci		HOSTDATA(shpnt)->time[STATE] += jiffies-start;
242762306a36Sopenharmony_ci#endif
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_ci	} while(pending);
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci	/*
243262306a36Sopenharmony_ci	 * enable interrupts and leave bottom-half
243362306a36Sopenharmony_ci	 *
243462306a36Sopenharmony_ci	 */
243562306a36Sopenharmony_ci	HOSTDATA(shpnt)->in_intr--;
243662306a36Sopenharmony_ci	SETBITS(DMACNTRL0, INTEN);
243762306a36Sopenharmony_ci	DO_UNLOCK(flags);
243862306a36Sopenharmony_ci}
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_ci/*
244262306a36Sopenharmony_ci * Dump the current driver status and panic
244362306a36Sopenharmony_ci */
244462306a36Sopenharmony_cistatic void aha152x_error(struct Scsi_Host *shpnt, char *msg)
244562306a36Sopenharmony_ci{
244662306a36Sopenharmony_ci	shost_printk(KERN_EMERG, shpnt, "%s\n", msg);
244762306a36Sopenharmony_ci	show_queues(shpnt);
244862306a36Sopenharmony_ci	panic("aha152x panic\n");
244962306a36Sopenharmony_ci}
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci/*
245262306a36Sopenharmony_ci * display enabled interrupts
245362306a36Sopenharmony_ci */
245462306a36Sopenharmony_cistatic void disp_enintr(struct Scsi_Host *shpnt)
245562306a36Sopenharmony_ci{
245662306a36Sopenharmony_ci	int s0, s1;
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci	s0 = GETPORT(SIMODE0);
245962306a36Sopenharmony_ci	s1 = GETPORT(SIMODE1);
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	shost_printk(KERN_DEBUG, shpnt,
246262306a36Sopenharmony_ci		     "enabled interrupts (%s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n",
246362306a36Sopenharmony_ci		     (s0 & ENSELDO) ? "ENSELDO " : "",
246462306a36Sopenharmony_ci		     (s0 & ENSELDI) ? "ENSELDI " : "",
246562306a36Sopenharmony_ci		     (s0 & ENSELINGO) ? "ENSELINGO " : "",
246662306a36Sopenharmony_ci		     (s0 & ENSWRAP) ? "ENSWRAP " : "",
246762306a36Sopenharmony_ci		     (s0 & ENSDONE) ? "ENSDONE " : "",
246862306a36Sopenharmony_ci		     (s0 & ENSPIORDY) ? "ENSPIORDY " : "",
246962306a36Sopenharmony_ci		     (s0 & ENDMADONE) ? "ENDMADONE " : "",
247062306a36Sopenharmony_ci		     (s1 & ENSELTIMO) ? "ENSELTIMO " : "",
247162306a36Sopenharmony_ci		     (s1 & ENATNTARG) ? "ENATNTARG " : "",
247262306a36Sopenharmony_ci		     (s1 & ENPHASEMIS) ? "ENPHASEMIS " : "",
247362306a36Sopenharmony_ci		     (s1 & ENBUSFREE) ? "ENBUSFREE " : "",
247462306a36Sopenharmony_ci		     (s1 & ENSCSIPERR) ? "ENSCSIPERR " : "",
247562306a36Sopenharmony_ci		     (s1 & ENPHASECHG) ? "ENPHASECHG " : "",
247662306a36Sopenharmony_ci		     (s1 & ENREQINIT) ? "ENREQINIT " : "");
247762306a36Sopenharmony_ci}
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci/*
248062306a36Sopenharmony_ci * Show the command data of a command
248162306a36Sopenharmony_ci */
248262306a36Sopenharmony_cistatic void show_command(struct scsi_cmnd *ptr)
248362306a36Sopenharmony_ci{
248462306a36Sopenharmony_ci	const int phase = aha152x_priv(ptr)->phase;
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci	scsi_print_command(ptr);
248762306a36Sopenharmony_ci	scmd_printk(KERN_DEBUG, ptr,
248862306a36Sopenharmony_ci		    "request_bufflen=%d; resid=%d; "
248962306a36Sopenharmony_ci		    "phase |%s%s%s%s%s%s%s%s%s; next=0x%p",
249062306a36Sopenharmony_ci		    scsi_bufflen(ptr), scsi_get_resid(ptr),
249162306a36Sopenharmony_ci		    phase & not_issued ? "not issued|" : "",
249262306a36Sopenharmony_ci		    phase & selecting ? "selecting|" : "",
249362306a36Sopenharmony_ci		    phase & identified ? "identified|" : "",
249462306a36Sopenharmony_ci		    phase & disconnected ? "disconnected|" : "",
249562306a36Sopenharmony_ci		    phase & completed ? "completed|" : "",
249662306a36Sopenharmony_ci		    phase & spiordy ? "spiordy|" : "",
249762306a36Sopenharmony_ci		    phase & syncneg ? "syncneg|" : "",
249862306a36Sopenharmony_ci		    phase & aborted ? "aborted|" : "",
249962306a36Sopenharmony_ci		    phase & resetted ? "resetted|" : "",
250062306a36Sopenharmony_ci		    SCDATA(ptr) ? SCNEXT(ptr) : NULL);
250162306a36Sopenharmony_ci}
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci/*
250462306a36Sopenharmony_ci * Dump the queued data
250562306a36Sopenharmony_ci */
250662306a36Sopenharmony_cistatic void show_queues(struct Scsi_Host *shpnt)
250762306a36Sopenharmony_ci{
250862306a36Sopenharmony_ci	struct scsi_cmnd *ptr;
250962306a36Sopenharmony_ci	unsigned long flags;
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_ci	DO_LOCK(flags);
251262306a36Sopenharmony_ci	printk(KERN_DEBUG "\nqueue status:\nissue_SC:\n");
251362306a36Sopenharmony_ci	for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
251462306a36Sopenharmony_ci		show_command(ptr);
251562306a36Sopenharmony_ci	DO_UNLOCK(flags);
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci	printk(KERN_DEBUG "current_SC:\n");
251862306a36Sopenharmony_ci	if (CURRENT_SC)
251962306a36Sopenharmony_ci		show_command(CURRENT_SC);
252062306a36Sopenharmony_ci	else
252162306a36Sopenharmony_ci		printk(KERN_DEBUG "none\n");
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci	printk(KERN_DEBUG "disconnected_SC:\n");
252462306a36Sopenharmony_ci	for (ptr = DISCONNECTED_SC; ptr; ptr = SCDATA(ptr) ? SCNEXT(ptr) : NULL)
252562306a36Sopenharmony_ci		show_command(ptr);
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci	disp_enintr(shpnt);
252862306a36Sopenharmony_ci}
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_cistatic void get_command(struct seq_file *m, struct scsi_cmnd * ptr)
253162306a36Sopenharmony_ci{
253262306a36Sopenharmony_ci	struct aha152x_cmd_priv *acp = aha152x_priv(ptr);
253362306a36Sopenharmony_ci	const int phase = acp->phase;
253462306a36Sopenharmony_ci	int i;
253562306a36Sopenharmony_ci
253662306a36Sopenharmony_ci	seq_printf(m, "%p: target=%d; lun=%d; cmnd=( ",
253762306a36Sopenharmony_ci		ptr, ptr->device->id, (u8)ptr->device->lun);
253862306a36Sopenharmony_ci
253962306a36Sopenharmony_ci	for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++)
254062306a36Sopenharmony_ci		seq_printf(m, "0x%02x ", ptr->cmnd[i]);
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	seq_printf(m, "); resid=%d; residual=%d; buffers=%d; phase |",
254362306a36Sopenharmony_ci		scsi_get_resid(ptr), acp->this_residual,
254462306a36Sopenharmony_ci		sg_nents(acp->buffer) - 1);
254562306a36Sopenharmony_ci
254662306a36Sopenharmony_ci	if (phase & not_issued)
254762306a36Sopenharmony_ci		seq_puts(m, "not issued|");
254862306a36Sopenharmony_ci	if (phase & selecting)
254962306a36Sopenharmony_ci		seq_puts(m, "selecting|");
255062306a36Sopenharmony_ci	if (phase & disconnected)
255162306a36Sopenharmony_ci		seq_puts(m, "disconnected|");
255262306a36Sopenharmony_ci	if (phase & aborted)
255362306a36Sopenharmony_ci		seq_puts(m, "aborted|");
255462306a36Sopenharmony_ci	if (phase & identified)
255562306a36Sopenharmony_ci		seq_puts(m, "identified|");
255662306a36Sopenharmony_ci	if (phase & completed)
255762306a36Sopenharmony_ci		seq_puts(m, "completed|");
255862306a36Sopenharmony_ci	if (phase & spiordy)
255962306a36Sopenharmony_ci		seq_puts(m, "spiordy|");
256062306a36Sopenharmony_ci	if (phase & syncneg)
256162306a36Sopenharmony_ci		seq_puts(m, "syncneg|");
256262306a36Sopenharmony_ci	seq_printf(m, "; next=0x%p\n", SCNEXT(ptr));
256362306a36Sopenharmony_ci}
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_cistatic void get_ports(struct seq_file *m, struct Scsi_Host *shpnt)
256662306a36Sopenharmony_ci{
256762306a36Sopenharmony_ci	int s;
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci	seq_printf(m, "\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name);
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci	s = GETPORT(SCSISEQ);
257262306a36Sopenharmony_ci	seq_puts(m, "SCSISEQ( ");
257362306a36Sopenharmony_ci	if (s & TEMODEO)
257462306a36Sopenharmony_ci		seq_puts(m, "TARGET MODE ");
257562306a36Sopenharmony_ci	if (s & ENSELO)
257662306a36Sopenharmony_ci		seq_puts(m, "SELO ");
257762306a36Sopenharmony_ci	if (s & ENSELI)
257862306a36Sopenharmony_ci		seq_puts(m, "SELI ");
257962306a36Sopenharmony_ci	if (s & ENRESELI)
258062306a36Sopenharmony_ci		seq_puts(m, "RESELI ");
258162306a36Sopenharmony_ci	if (s & ENAUTOATNO)
258262306a36Sopenharmony_ci		seq_puts(m, "AUTOATNO ");
258362306a36Sopenharmony_ci	if (s & ENAUTOATNI)
258462306a36Sopenharmony_ci		seq_puts(m, "AUTOATNI ");
258562306a36Sopenharmony_ci	if (s & ENAUTOATNP)
258662306a36Sopenharmony_ci		seq_puts(m, "AUTOATNP ");
258762306a36Sopenharmony_ci	if (s & SCSIRSTO)
258862306a36Sopenharmony_ci		seq_puts(m, "SCSIRSTO ");
258962306a36Sopenharmony_ci	seq_puts(m, ");");
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	seq_puts(m, " SCSISIG(");
259262306a36Sopenharmony_ci	s = GETPORT(SCSISIG);
259362306a36Sopenharmony_ci	switch (s & P_MASK) {
259462306a36Sopenharmony_ci	case P_DATAO:
259562306a36Sopenharmony_ci		seq_puts(m, "DATA OUT");
259662306a36Sopenharmony_ci		break;
259762306a36Sopenharmony_ci	case P_DATAI:
259862306a36Sopenharmony_ci		seq_puts(m, "DATA IN");
259962306a36Sopenharmony_ci		break;
260062306a36Sopenharmony_ci	case P_CMD:
260162306a36Sopenharmony_ci		seq_puts(m, "COMMAND");
260262306a36Sopenharmony_ci		break;
260362306a36Sopenharmony_ci	case P_STATUS:
260462306a36Sopenharmony_ci		seq_puts(m, "STATUS");
260562306a36Sopenharmony_ci		break;
260662306a36Sopenharmony_ci	case P_MSGO:
260762306a36Sopenharmony_ci		seq_puts(m, "MESSAGE OUT");
260862306a36Sopenharmony_ci		break;
260962306a36Sopenharmony_ci	case P_MSGI:
261062306a36Sopenharmony_ci		seq_puts(m, "MESSAGE IN");
261162306a36Sopenharmony_ci		break;
261262306a36Sopenharmony_ci	default:
261362306a36Sopenharmony_ci		seq_puts(m, "*invalid*");
261462306a36Sopenharmony_ci		break;
261562306a36Sopenharmony_ci	}
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci	seq_puts(m, "); ");
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci	seq_printf(m, "INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci	seq_puts(m, "SSTAT( ");
262262306a36Sopenharmony_ci	s = GETPORT(SSTAT0);
262362306a36Sopenharmony_ci	if (s & TARGET)
262462306a36Sopenharmony_ci		seq_puts(m, "TARGET ");
262562306a36Sopenharmony_ci	if (s & SELDO)
262662306a36Sopenharmony_ci		seq_puts(m, "SELDO ");
262762306a36Sopenharmony_ci	if (s & SELDI)
262862306a36Sopenharmony_ci		seq_puts(m, "SELDI ");
262962306a36Sopenharmony_ci	if (s & SELINGO)
263062306a36Sopenharmony_ci		seq_puts(m, "SELINGO ");
263162306a36Sopenharmony_ci	if (s & SWRAP)
263262306a36Sopenharmony_ci		seq_puts(m, "SWRAP ");
263362306a36Sopenharmony_ci	if (s & SDONE)
263462306a36Sopenharmony_ci		seq_puts(m, "SDONE ");
263562306a36Sopenharmony_ci	if (s & SPIORDY)
263662306a36Sopenharmony_ci		seq_puts(m, "SPIORDY ");
263762306a36Sopenharmony_ci	if (s & DMADONE)
263862306a36Sopenharmony_ci		seq_puts(m, "DMADONE ");
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci	s = GETPORT(SSTAT1);
264162306a36Sopenharmony_ci	if (s & SELTO)
264262306a36Sopenharmony_ci		seq_puts(m, "SELTO ");
264362306a36Sopenharmony_ci	if (s & ATNTARG)
264462306a36Sopenharmony_ci		seq_puts(m, "ATNTARG ");
264562306a36Sopenharmony_ci	if (s & SCSIRSTI)
264662306a36Sopenharmony_ci		seq_puts(m, "SCSIRSTI ");
264762306a36Sopenharmony_ci	if (s & PHASEMIS)
264862306a36Sopenharmony_ci		seq_puts(m, "PHASEMIS ");
264962306a36Sopenharmony_ci	if (s & BUSFREE)
265062306a36Sopenharmony_ci		seq_puts(m, "BUSFREE ");
265162306a36Sopenharmony_ci	if (s & SCSIPERR)
265262306a36Sopenharmony_ci		seq_puts(m, "SCSIPERR ");
265362306a36Sopenharmony_ci	if (s & PHASECHG)
265462306a36Sopenharmony_ci		seq_puts(m, "PHASECHG ");
265562306a36Sopenharmony_ci	if (s & REQINIT)
265662306a36Sopenharmony_ci		seq_puts(m, "REQINIT ");
265762306a36Sopenharmony_ci	seq_puts(m, "); ");
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_ci
266062306a36Sopenharmony_ci	seq_puts(m, "SSTAT( ");
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	if (s & TARGET)
266562306a36Sopenharmony_ci		seq_puts(m, "TARGET ");
266662306a36Sopenharmony_ci	if (s & SELDO)
266762306a36Sopenharmony_ci		seq_puts(m, "SELDO ");
266862306a36Sopenharmony_ci	if (s & SELDI)
266962306a36Sopenharmony_ci		seq_puts(m, "SELDI ");
267062306a36Sopenharmony_ci	if (s & SELINGO)
267162306a36Sopenharmony_ci		seq_puts(m, "SELINGO ");
267262306a36Sopenharmony_ci	if (s & SWRAP)
267362306a36Sopenharmony_ci		seq_puts(m, "SWRAP ");
267462306a36Sopenharmony_ci	if (s & SDONE)
267562306a36Sopenharmony_ci		seq_puts(m, "SDONE ");
267662306a36Sopenharmony_ci	if (s & SPIORDY)
267762306a36Sopenharmony_ci		seq_puts(m, "SPIORDY ");
267862306a36Sopenharmony_ci	if (s & DMADONE)
267962306a36Sopenharmony_ci		seq_puts(m, "DMADONE ");
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci	s = GETPORT(SSTAT1) & GETPORT(SIMODE1);
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci	if (s & SELTO)
268462306a36Sopenharmony_ci		seq_puts(m, "SELTO ");
268562306a36Sopenharmony_ci	if (s & ATNTARG)
268662306a36Sopenharmony_ci		seq_puts(m, "ATNTARG ");
268762306a36Sopenharmony_ci	if (s & SCSIRSTI)
268862306a36Sopenharmony_ci		seq_puts(m, "SCSIRSTI ");
268962306a36Sopenharmony_ci	if (s & PHASEMIS)
269062306a36Sopenharmony_ci		seq_puts(m, "PHASEMIS ");
269162306a36Sopenharmony_ci	if (s & BUSFREE)
269262306a36Sopenharmony_ci		seq_puts(m, "BUSFREE ");
269362306a36Sopenharmony_ci	if (s & SCSIPERR)
269462306a36Sopenharmony_ci		seq_puts(m, "SCSIPERR ");
269562306a36Sopenharmony_ci	if (s & PHASECHG)
269662306a36Sopenharmony_ci		seq_puts(m, "PHASECHG ");
269762306a36Sopenharmony_ci	if (s & REQINIT)
269862306a36Sopenharmony_ci		seq_puts(m, "REQINIT ");
269962306a36Sopenharmony_ci	seq_puts(m, "); ");
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci	seq_puts(m, "SXFRCTL0( ");
270262306a36Sopenharmony_ci
270362306a36Sopenharmony_ci	s = GETPORT(SXFRCTL0);
270462306a36Sopenharmony_ci	if (s & SCSIEN)
270562306a36Sopenharmony_ci		seq_puts(m, "SCSIEN ");
270662306a36Sopenharmony_ci	if (s & DMAEN)
270762306a36Sopenharmony_ci		seq_puts(m, "DMAEN ");
270862306a36Sopenharmony_ci	if (s & CH1)
270962306a36Sopenharmony_ci		seq_puts(m, "CH1 ");
271062306a36Sopenharmony_ci	if (s & CLRSTCNT)
271162306a36Sopenharmony_ci		seq_puts(m, "CLRSTCNT ");
271262306a36Sopenharmony_ci	if (s & SPIOEN)
271362306a36Sopenharmony_ci		seq_puts(m, "SPIOEN ");
271462306a36Sopenharmony_ci	if (s & CLRCH1)
271562306a36Sopenharmony_ci		seq_puts(m, "CLRCH1 ");
271662306a36Sopenharmony_ci	seq_puts(m, "); ");
271762306a36Sopenharmony_ci
271862306a36Sopenharmony_ci	seq_puts(m, "SIGNAL( ");
271962306a36Sopenharmony_ci
272062306a36Sopenharmony_ci	s = GETPORT(SCSISIG);
272162306a36Sopenharmony_ci	if (s & SIG_ATNI)
272262306a36Sopenharmony_ci		seq_puts(m, "ATNI ");
272362306a36Sopenharmony_ci	if (s & SIG_SELI)
272462306a36Sopenharmony_ci		seq_puts(m, "SELI ");
272562306a36Sopenharmony_ci	if (s & SIG_BSYI)
272662306a36Sopenharmony_ci		seq_puts(m, "BSYI ");
272762306a36Sopenharmony_ci	if (s & SIG_REQI)
272862306a36Sopenharmony_ci		seq_puts(m, "REQI ");
272962306a36Sopenharmony_ci	if (s & SIG_ACKI)
273062306a36Sopenharmony_ci		seq_puts(m, "ACKI ");
273162306a36Sopenharmony_ci	seq_puts(m, "); ");
273262306a36Sopenharmony_ci
273362306a36Sopenharmony_ci	seq_printf(m, "SELID(%02x), ", GETPORT(SELID));
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci	seq_printf(m, "STCNT(%d), ", GETSTCNT());
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci	seq_puts(m, "SSTAT2( ");
273862306a36Sopenharmony_ci
273962306a36Sopenharmony_ci	s = GETPORT(SSTAT2);
274062306a36Sopenharmony_ci	if (s & SOFFSET)
274162306a36Sopenharmony_ci		seq_puts(m, "SOFFSET ");
274262306a36Sopenharmony_ci	if (s & SEMPTY)
274362306a36Sopenharmony_ci		seq_puts(m, "SEMPTY ");
274462306a36Sopenharmony_ci	if (s & SFULL)
274562306a36Sopenharmony_ci		seq_puts(m, "SFULL ");
274662306a36Sopenharmony_ci	seq_printf(m, "); SFCNT (%d); ", s & (SFULL | SFCNT));
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_ci	s = GETPORT(SSTAT3);
274962306a36Sopenharmony_ci	seq_printf(m, "SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci	seq_puts(m, "SSTAT4( ");
275262306a36Sopenharmony_ci	s = GETPORT(SSTAT4);
275362306a36Sopenharmony_ci	if (s & SYNCERR)
275462306a36Sopenharmony_ci		seq_puts(m, "SYNCERR ");
275562306a36Sopenharmony_ci	if (s & FWERR)
275662306a36Sopenharmony_ci		seq_puts(m, "FWERR ");
275762306a36Sopenharmony_ci	if (s & FRERR)
275862306a36Sopenharmony_ci		seq_puts(m, "FRERR ");
275962306a36Sopenharmony_ci	seq_puts(m, "); ");
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci	seq_puts(m, "DMACNTRL0( ");
276262306a36Sopenharmony_ci	s = GETPORT(DMACNTRL0);
276362306a36Sopenharmony_ci	seq_printf(m, "%s ", s & _8BIT ? "8BIT" : "16BIT");
276462306a36Sopenharmony_ci	seq_printf(m, "%s ", s & DMA ? "DMA" : "PIO");
276562306a36Sopenharmony_ci	seq_printf(m, "%s ", s & WRITE_READ ? "WRITE" : "READ");
276662306a36Sopenharmony_ci	if (s & ENDMA)
276762306a36Sopenharmony_ci		seq_puts(m, "ENDMA ");
276862306a36Sopenharmony_ci	if (s & INTEN)
276962306a36Sopenharmony_ci		seq_puts(m, "INTEN ");
277062306a36Sopenharmony_ci	if (s & RSTFIFO)
277162306a36Sopenharmony_ci		seq_puts(m, "RSTFIFO ");
277262306a36Sopenharmony_ci	if (s & SWINT)
277362306a36Sopenharmony_ci		seq_puts(m, "SWINT ");
277462306a36Sopenharmony_ci	seq_puts(m, "); ");
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci	seq_puts(m, "DMASTAT( ");
277762306a36Sopenharmony_ci	s = GETPORT(DMASTAT);
277862306a36Sopenharmony_ci	if (s & ATDONE)
277962306a36Sopenharmony_ci		seq_puts(m, "ATDONE ");
278062306a36Sopenharmony_ci	if (s & WORDRDY)
278162306a36Sopenharmony_ci		seq_puts(m, "WORDRDY ");
278262306a36Sopenharmony_ci	if (s & DFIFOFULL)
278362306a36Sopenharmony_ci		seq_puts(m, "DFIFOFULL ");
278462306a36Sopenharmony_ci	if (s & DFIFOEMP)
278562306a36Sopenharmony_ci		seq_puts(m, "DFIFOEMP ");
278662306a36Sopenharmony_ci	seq_puts(m, ")\n");
278762306a36Sopenharmony_ci
278862306a36Sopenharmony_ci	seq_puts(m, "enabled interrupts( ");
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci	s = GETPORT(SIMODE0);
279162306a36Sopenharmony_ci	if (s & ENSELDO)
279262306a36Sopenharmony_ci		seq_puts(m, "ENSELDO ");
279362306a36Sopenharmony_ci	if (s & ENSELDI)
279462306a36Sopenharmony_ci		seq_puts(m, "ENSELDI ");
279562306a36Sopenharmony_ci	if (s & ENSELINGO)
279662306a36Sopenharmony_ci		seq_puts(m, "ENSELINGO ");
279762306a36Sopenharmony_ci	if (s & ENSWRAP)
279862306a36Sopenharmony_ci		seq_puts(m, "ENSWRAP ");
279962306a36Sopenharmony_ci	if (s & ENSDONE)
280062306a36Sopenharmony_ci		seq_puts(m, "ENSDONE ");
280162306a36Sopenharmony_ci	if (s & ENSPIORDY)
280262306a36Sopenharmony_ci		seq_puts(m, "ENSPIORDY ");
280362306a36Sopenharmony_ci	if (s & ENDMADONE)
280462306a36Sopenharmony_ci		seq_puts(m, "ENDMADONE ");
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci	s = GETPORT(SIMODE1);
280762306a36Sopenharmony_ci	if (s & ENSELTIMO)
280862306a36Sopenharmony_ci		seq_puts(m, "ENSELTIMO ");
280962306a36Sopenharmony_ci	if (s & ENATNTARG)
281062306a36Sopenharmony_ci		seq_puts(m, "ENATNTARG ");
281162306a36Sopenharmony_ci	if (s & ENPHASEMIS)
281262306a36Sopenharmony_ci		seq_puts(m, "ENPHASEMIS ");
281362306a36Sopenharmony_ci	if (s & ENBUSFREE)
281462306a36Sopenharmony_ci		seq_puts(m, "ENBUSFREE ");
281562306a36Sopenharmony_ci	if (s & ENSCSIPERR)
281662306a36Sopenharmony_ci		seq_puts(m, "ENSCSIPERR ");
281762306a36Sopenharmony_ci	if (s & ENPHASECHG)
281862306a36Sopenharmony_ci		seq_puts(m, "ENPHASECHG ");
281962306a36Sopenharmony_ci	if (s & ENREQINIT)
282062306a36Sopenharmony_ci		seq_puts(m, "ENREQINIT ");
282162306a36Sopenharmony_ci	seq_puts(m, ")\n");
282262306a36Sopenharmony_ci}
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_cistatic int aha152x_set_info(struct Scsi_Host *shpnt, char *buffer, int length)
282562306a36Sopenharmony_ci{
282662306a36Sopenharmony_ci	if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0)
282762306a36Sopenharmony_ci		return -EINVAL;
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci#if defined(AHA152X_STAT)
283062306a36Sopenharmony_ci	if(length>13 && strncmp("reset", buffer+8, 5)==0) {
283162306a36Sopenharmony_ci		int i;
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci		HOSTDATA(shpnt)->total_commands=0;
283462306a36Sopenharmony_ci		HOSTDATA(shpnt)->disconnections=0;
283562306a36Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_any_action=0;
283662306a36Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_old_command=0;
283762306a36Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_new_command=0;
283862306a36Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_done_command=0;
283962306a36Sopenharmony_ci		HOSTDATA(shpnt)->busfree_with_check_condition=0;
284062306a36Sopenharmony_ci		for (i = idle; i<maxstate; i++) {
284162306a36Sopenharmony_ci			HOSTDATA(shpnt)->count[i]=0;
284262306a36Sopenharmony_ci			HOSTDATA(shpnt)->count_trans[i]=0;
284362306a36Sopenharmony_ci			HOSTDATA(shpnt)->time[i]=0;
284462306a36Sopenharmony_ci		}
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ci		shost_printk(KERN_INFO, shpnt, "aha152x: stats reset.\n");
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci	} else
284962306a36Sopenharmony_ci#endif
285062306a36Sopenharmony_ci	{
285162306a36Sopenharmony_ci		return -EINVAL;
285262306a36Sopenharmony_ci	}
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci	return length;
285662306a36Sopenharmony_ci}
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_cistatic int aha152x_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
285962306a36Sopenharmony_ci{
286062306a36Sopenharmony_ci	int i;
286162306a36Sopenharmony_ci	struct scsi_cmnd *ptr;
286262306a36Sopenharmony_ci	unsigned long flags;
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ci	seq_puts(m, AHA152X_REVID "\n");
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_ci	seq_printf(m, "ioports 0x%04lx to 0x%04lx\n",
286762306a36Sopenharmony_ci		shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1);
286862306a36Sopenharmony_ci	seq_printf(m, "interrupt 0x%02x\n", shpnt->irq);
286962306a36Sopenharmony_ci	seq_printf(m, "disconnection/reconnection %s\n",
287062306a36Sopenharmony_ci		RECONNECT ? "enabled" : "disabled");
287162306a36Sopenharmony_ci	seq_printf(m, "parity checking %s\n",
287262306a36Sopenharmony_ci		PARITY ? "enabled" : "disabled");
287362306a36Sopenharmony_ci	seq_printf(m, "synchronous transfers %s\n",
287462306a36Sopenharmony_ci		SYNCHRONOUS ? "enabled" : "disabled");
287562306a36Sopenharmony_ci	seq_printf(m, "%d commands currently queued\n", HOSTDATA(shpnt)->commands);
287662306a36Sopenharmony_ci
287762306a36Sopenharmony_ci	if(SYNCHRONOUS) {
287862306a36Sopenharmony_ci		seq_puts(m, "synchronously operating targets (tick=50 ns):\n");
287962306a36Sopenharmony_ci		for (i = 0; i < 8; i++)
288062306a36Sopenharmony_ci			if (HOSTDATA(shpnt)->syncrate[i] & 0x7f)
288162306a36Sopenharmony_ci				seq_printf(m, "target %d: period %dT/%dns; req/ack offset %d\n",
288262306a36Sopenharmony_ci					i,
288362306a36Sopenharmony_ci					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2),
288462306a36Sopenharmony_ci					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50,
288562306a36Sopenharmony_ci				    HOSTDATA(shpnt)->syncrate[i] & 0x0f);
288662306a36Sopenharmony_ci	}
288762306a36Sopenharmony_ci	seq_puts(m, "\nqueue status:\n");
288862306a36Sopenharmony_ci	DO_LOCK(flags);
288962306a36Sopenharmony_ci	if (ISSUE_SC) {
289062306a36Sopenharmony_ci		seq_puts(m, "not yet issued commands:\n");
289162306a36Sopenharmony_ci		for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
289262306a36Sopenharmony_ci			get_command(m, ptr);
289362306a36Sopenharmony_ci	} else
289462306a36Sopenharmony_ci		seq_puts(m, "no not yet issued commands\n");
289562306a36Sopenharmony_ci	DO_UNLOCK(flags);
289662306a36Sopenharmony_ci
289762306a36Sopenharmony_ci	if (CURRENT_SC) {
289862306a36Sopenharmony_ci		seq_puts(m, "current command:\n");
289962306a36Sopenharmony_ci		get_command(m, CURRENT_SC);
290062306a36Sopenharmony_ci	} else
290162306a36Sopenharmony_ci		seq_puts(m, "no current command\n");
290262306a36Sopenharmony_ci
290362306a36Sopenharmony_ci	if (DISCONNECTED_SC) {
290462306a36Sopenharmony_ci		seq_puts(m, "disconnected commands:\n");
290562306a36Sopenharmony_ci		for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr))
290662306a36Sopenharmony_ci			get_command(m, ptr);
290762306a36Sopenharmony_ci	} else
290862306a36Sopenharmony_ci		seq_puts(m, "no disconnected commands\n");
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci	get_ports(m, shpnt);
291162306a36Sopenharmony_ci
291262306a36Sopenharmony_ci#if defined(AHA152X_STAT)
291362306a36Sopenharmony_ci	seq_printf(m, "statistics:\n"
291462306a36Sopenharmony_ci		"total commands:               %d\n"
291562306a36Sopenharmony_ci		"disconnections:               %d\n"
291662306a36Sopenharmony_ci		"busfree with check condition: %d\n"
291762306a36Sopenharmony_ci		"busfree without old command:  %d\n"
291862306a36Sopenharmony_ci		"busfree without new command:  %d\n"
291962306a36Sopenharmony_ci		"busfree without done command: %d\n"
292062306a36Sopenharmony_ci		"busfree without any action:   %d\n"
292162306a36Sopenharmony_ci		"state      "
292262306a36Sopenharmony_ci		"transitions  "
292362306a36Sopenharmony_ci		"count        "
292462306a36Sopenharmony_ci		"time\n",
292562306a36Sopenharmony_ci		HOSTDATA(shpnt)->total_commands,
292662306a36Sopenharmony_ci		HOSTDATA(shpnt)->disconnections,
292762306a36Sopenharmony_ci		HOSTDATA(shpnt)->busfree_with_check_condition,
292862306a36Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_old_command,
292962306a36Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_new_command,
293062306a36Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_done_command,
293162306a36Sopenharmony_ci		HOSTDATA(shpnt)->busfree_without_any_action);
293262306a36Sopenharmony_ci	for(i=0; i<maxstate; i++) {
293362306a36Sopenharmony_ci		seq_printf(m, "%-10s %-12d %-12d %-12ld\n",
293462306a36Sopenharmony_ci			states[i].name,
293562306a36Sopenharmony_ci			HOSTDATA(shpnt)->count_trans[i],
293662306a36Sopenharmony_ci			HOSTDATA(shpnt)->count[i],
293762306a36Sopenharmony_ci			HOSTDATA(shpnt)->time[i]);
293862306a36Sopenharmony_ci	}
293962306a36Sopenharmony_ci#endif
294062306a36Sopenharmony_ci	return 0;
294162306a36Sopenharmony_ci}
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_cistatic int aha152x_adjust_queue(struct scsi_device *device)
294462306a36Sopenharmony_ci{
294562306a36Sopenharmony_ci	blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH);
294662306a36Sopenharmony_ci	return 0;
294762306a36Sopenharmony_ci}
294862306a36Sopenharmony_ci
294962306a36Sopenharmony_cistatic const struct scsi_host_template aha152x_driver_template = {
295062306a36Sopenharmony_ci	.module				= THIS_MODULE,
295162306a36Sopenharmony_ci	.name				= AHA152X_REVID,
295262306a36Sopenharmony_ci	.proc_name			= "aha152x",
295362306a36Sopenharmony_ci	.show_info			= aha152x_show_info,
295462306a36Sopenharmony_ci	.write_info			= aha152x_set_info,
295562306a36Sopenharmony_ci	.queuecommand			= aha152x_queue,
295662306a36Sopenharmony_ci	.eh_abort_handler		= aha152x_abort,
295762306a36Sopenharmony_ci	.eh_device_reset_handler	= aha152x_device_reset,
295862306a36Sopenharmony_ci	.eh_bus_reset_handler		= aha152x_bus_reset,
295962306a36Sopenharmony_ci	.bios_param			= aha152x_biosparam,
296062306a36Sopenharmony_ci	.can_queue			= 1,
296162306a36Sopenharmony_ci	.this_id			= 7,
296262306a36Sopenharmony_ci	.sg_tablesize			= SG_ALL,
296362306a36Sopenharmony_ci	.dma_boundary			= PAGE_SIZE - 1,
296462306a36Sopenharmony_ci	.slave_alloc			= aha152x_adjust_queue,
296562306a36Sopenharmony_ci	.cmd_size			= sizeof(struct aha152x_cmd_priv),
296662306a36Sopenharmony_ci};
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_ci#if !defined(AHA152X_PCMCIA)
296962306a36Sopenharmony_cistatic int setup_count;
297062306a36Sopenharmony_cistatic struct aha152x_setup setup[2];
297162306a36Sopenharmony_ci
297262306a36Sopenharmony_ci/* possible i/o addresses for the AIC-6260; default first */
297362306a36Sopenharmony_cistatic unsigned short ports[] = { 0x340, 0x140 };
297462306a36Sopenharmony_ci
297562306a36Sopenharmony_ci#if !defined(SKIP_BIOSTEST)
297662306a36Sopenharmony_ci/* possible locations for the Adaptec BIOS; defaults first */
297762306a36Sopenharmony_cistatic unsigned int addresses[] =
297862306a36Sopenharmony_ci{
297962306a36Sopenharmony_ci	0xdc000,		/* default first */
298062306a36Sopenharmony_ci	0xc8000,
298162306a36Sopenharmony_ci	0xcc000,
298262306a36Sopenharmony_ci	0xd0000,
298362306a36Sopenharmony_ci	0xd4000,
298462306a36Sopenharmony_ci	0xd8000,
298562306a36Sopenharmony_ci	0xe0000,
298662306a36Sopenharmony_ci	0xeb800,		/* VTech Platinum SMP */
298762306a36Sopenharmony_ci	0xf0000,
298862306a36Sopenharmony_ci};
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci/* signatures for various AIC-6[23]60 based controllers.
299162306a36Sopenharmony_ci   The point in detecting signatures is to avoid useless and maybe
299262306a36Sopenharmony_ci   harmful probes on ports. I'm not sure that all listed boards pass
299362306a36Sopenharmony_ci   auto-configuration. For those which fail the BIOS signature is
299462306a36Sopenharmony_ci   obsolete, because user intervention to supply the configuration is
299562306a36Sopenharmony_ci   needed anyway.  May be an information whether or not the BIOS supports
299662306a36Sopenharmony_ci   extended translation could be also useful here. */
299762306a36Sopenharmony_cistatic struct signature {
299862306a36Sopenharmony_ci	unsigned char *signature;
299962306a36Sopenharmony_ci	int sig_offset;
300062306a36Sopenharmony_ci	int sig_length;
300162306a36Sopenharmony_ci} signatures[] =
300262306a36Sopenharmony_ci{
300362306a36Sopenharmony_ci	{ "Adaptec AHA-1520 BIOS",	0x102e, 21 },
300462306a36Sopenharmony_ci		/* Adaptec 152x */
300562306a36Sopenharmony_ci	{ "Adaptec AHA-1520B",		0x000b, 17 },
300662306a36Sopenharmony_ci		/* Adaptec 152x rev B */
300762306a36Sopenharmony_ci	{ "Adaptec AHA-1520B",		0x0026, 17 },
300862306a36Sopenharmony_ci		/* Iomega Jaz Jet ISA (AIC6370Q) */
300962306a36Sopenharmony_ci	{ "Adaptec ASW-B626 BIOS",	0x1029, 21 },
301062306a36Sopenharmony_ci		/* on-board controller */
301162306a36Sopenharmony_ci	{ "Adaptec BIOS: ASW-B626",	0x000f, 22 },
301262306a36Sopenharmony_ci		/* on-board controller */
301362306a36Sopenharmony_ci	{ "Adaptec ASW-B626 S2",	0x2e6c, 19 },
301462306a36Sopenharmony_ci		/* on-board controller */
301562306a36Sopenharmony_ci	{ "Adaptec BIOS:AIC-6360",	0x000c, 21 },
301662306a36Sopenharmony_ci		/* on-board controller */
301762306a36Sopenharmony_ci	{ "ScsiPro SP-360 BIOS",	0x2873, 19 },
301862306a36Sopenharmony_ci		/* ScsiPro-Controller  */
301962306a36Sopenharmony_ci	{ "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 },
302062306a36Sopenharmony_ci		/* Gigabyte Local-Bus-SCSI */
302162306a36Sopenharmony_ci	{ "Adaptec BIOS:AVA-282X",	0x000c, 21 },
302262306a36Sopenharmony_ci		/* Adaptec 282x */
302362306a36Sopenharmony_ci	{ "Adaptec IBM Dock II SCSI",   0x2edd, 24 },
302462306a36Sopenharmony_ci		/* IBM Thinkpad Dock II */
302562306a36Sopenharmony_ci	{ "Adaptec BIOS:AHA-1532P",     0x001c, 22 },
302662306a36Sopenharmony_ci		/* IBM Thinkpad Dock II SCSI */
302762306a36Sopenharmony_ci	{ "DTC3520A Host Adapter BIOS", 0x318a, 26 },
302862306a36Sopenharmony_ci		/* DTC 3520A ISA SCSI */
302962306a36Sopenharmony_ci};
303062306a36Sopenharmony_ci#endif /* !SKIP_BIOSTEST */
303162306a36Sopenharmony_ci
303262306a36Sopenharmony_ci/*
303362306a36Sopenharmony_ci * Test, if port_base is valid.
303462306a36Sopenharmony_ci *
303562306a36Sopenharmony_ci */
303662306a36Sopenharmony_cistatic int aha152x_porttest(int io_port)
303762306a36Sopenharmony_ci{
303862306a36Sopenharmony_ci	int i;
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_ci	SETPORT(io_port + O_DMACNTRL1, 0);	/* reset stack pointer */
304162306a36Sopenharmony_ci	for (i = 0; i < 16; i++)
304262306a36Sopenharmony_ci		SETPORT(io_port + O_STACK, i);
304362306a36Sopenharmony_ci
304462306a36Sopenharmony_ci	SETPORT(io_port + O_DMACNTRL1, 0);	/* reset stack pointer */
304562306a36Sopenharmony_ci	for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++)
304662306a36Sopenharmony_ci		;
304762306a36Sopenharmony_ci
304862306a36Sopenharmony_ci	return (i == 16);
304962306a36Sopenharmony_ci}
305062306a36Sopenharmony_ci
305162306a36Sopenharmony_cistatic int tc1550_porttest(int io_port)
305262306a36Sopenharmony_ci{
305362306a36Sopenharmony_ci	int i;
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_ci	SETPORT(io_port + O_TC_DMACNTRL1, 0);	/* reset stack pointer */
305662306a36Sopenharmony_ci	for (i = 0; i < 16; i++)
305762306a36Sopenharmony_ci		SETPORT(io_port + O_STACK, i);
305862306a36Sopenharmony_ci
305962306a36Sopenharmony_ci	SETPORT(io_port + O_TC_DMACNTRL1, 0);	/* reset stack pointer */
306062306a36Sopenharmony_ci	for (i = 0; i < 16 && GETPORT(io_port + O_TC_STACK) == i; i++)
306162306a36Sopenharmony_ci		;
306262306a36Sopenharmony_ci
306362306a36Sopenharmony_ci	return (i == 16);
306462306a36Sopenharmony_ci}
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci
306762306a36Sopenharmony_cistatic int checksetup(struct aha152x_setup *setup)
306862306a36Sopenharmony_ci{
306962306a36Sopenharmony_ci	int i;
307062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ports) && (setup->io_port != ports[i]); i++)
307162306a36Sopenharmony_ci		;
307262306a36Sopenharmony_ci
307362306a36Sopenharmony_ci	if (i == ARRAY_SIZE(ports))
307462306a36Sopenharmony_ci		return 0;
307562306a36Sopenharmony_ci
307662306a36Sopenharmony_ci	if (!request_region(setup->io_port, IO_RANGE, "aha152x")) {
307762306a36Sopenharmony_ci		printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup->io_port);
307862306a36Sopenharmony_ci		return 0;
307962306a36Sopenharmony_ci	}
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_ci	if( aha152x_porttest(setup->io_port) ) {
308262306a36Sopenharmony_ci		setup->tc1550=0;
308362306a36Sopenharmony_ci	} else if( tc1550_porttest(setup->io_port) ) {
308462306a36Sopenharmony_ci		setup->tc1550=1;
308562306a36Sopenharmony_ci	} else {
308662306a36Sopenharmony_ci		release_region(setup->io_port, IO_RANGE);
308762306a36Sopenharmony_ci		return 0;
308862306a36Sopenharmony_ci	}
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ci	release_region(setup->io_port, IO_RANGE);
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_ci	if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX))
309362306a36Sopenharmony_ci		return 0;
309462306a36Sopenharmony_ci
309562306a36Sopenharmony_ci	if ((setup->scsiid < 0) || (setup->scsiid > 7))
309662306a36Sopenharmony_ci		return 0;
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci	if ((setup->reconnect < 0) || (setup->reconnect > 1))
309962306a36Sopenharmony_ci		return 0;
310062306a36Sopenharmony_ci
310162306a36Sopenharmony_ci	if ((setup->parity < 0) || (setup->parity > 1))
310262306a36Sopenharmony_ci		return 0;
310362306a36Sopenharmony_ci
310462306a36Sopenharmony_ci	if ((setup->synchronous < 0) || (setup->synchronous > 1))
310562306a36Sopenharmony_ci		return 0;
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_ci	if ((setup->ext_trans < 0) || (setup->ext_trans > 1))
310862306a36Sopenharmony_ci		return 0;
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_ci
311162306a36Sopenharmony_ci	return 1;
311262306a36Sopenharmony_ci}
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci
311562306a36Sopenharmony_cistatic int __init aha152x_init(void)
311662306a36Sopenharmony_ci{
311762306a36Sopenharmony_ci	int i, j, ok;
311862306a36Sopenharmony_ci#if defined(AUTOCONF)
311962306a36Sopenharmony_ci	aha152x_config conf;
312062306a36Sopenharmony_ci#endif
312162306a36Sopenharmony_ci#ifdef __ISAPNP__
312262306a36Sopenharmony_ci	struct pnp_dev *dev=NULL, *pnpdev[2] = {NULL, NULL};
312362306a36Sopenharmony_ci#endif
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci	if ( setup_count ) {
312662306a36Sopenharmony_ci		printk(KERN_INFO "aha152x: processing commandline: ");
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_ci		for (i = 0; i<setup_count; i++) {
312962306a36Sopenharmony_ci			if (!checksetup(&setup[i])) {
313062306a36Sopenharmony_ci				printk(KERN_ERR "\naha152x: %s\n", setup[i].conf);
313162306a36Sopenharmony_ci				printk(KERN_ERR "aha152x: invalid line\n");
313262306a36Sopenharmony_ci			}
313362306a36Sopenharmony_ci		}
313462306a36Sopenharmony_ci		printk("ok\n");
313562306a36Sopenharmony_ci	}
313662306a36Sopenharmony_ci
313762306a36Sopenharmony_ci#if defined(SETUP0)
313862306a36Sopenharmony_ci	if (setup_count < ARRAY_SIZE(setup)) {
313962306a36Sopenharmony_ci		struct aha152x_setup override = SETUP0;
314062306a36Sopenharmony_ci
314162306a36Sopenharmony_ci		if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
314262306a36Sopenharmony_ci			if (!checksetup(&override)) {
314362306a36Sopenharmony_ci				printk(KERN_ERR "\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
314462306a36Sopenharmony_ci				       override.io_port,
314562306a36Sopenharmony_ci				       override.irq,
314662306a36Sopenharmony_ci				       override.scsiid,
314762306a36Sopenharmony_ci				       override.reconnect,
314862306a36Sopenharmony_ci				       override.parity,
314962306a36Sopenharmony_ci				       override.synchronous,
315062306a36Sopenharmony_ci				       override.delay,
315162306a36Sopenharmony_ci				       override.ext_trans);
315262306a36Sopenharmony_ci			} else
315362306a36Sopenharmony_ci				setup[setup_count++] = override;
315462306a36Sopenharmony_ci		}
315562306a36Sopenharmony_ci	}
315662306a36Sopenharmony_ci#endif
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_ci#if defined(SETUP1)
315962306a36Sopenharmony_ci	if (setup_count < ARRAY_SIZE(setup)) {
316062306a36Sopenharmony_ci		struct aha152x_setup override = SETUP1;
316162306a36Sopenharmony_ci
316262306a36Sopenharmony_ci		if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
316362306a36Sopenharmony_ci			if (!checksetup(&override)) {
316462306a36Sopenharmony_ci				printk(KERN_ERR "\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
316562306a36Sopenharmony_ci				       override.io_port,
316662306a36Sopenharmony_ci				       override.irq,
316762306a36Sopenharmony_ci				       override.scsiid,
316862306a36Sopenharmony_ci				       override.reconnect,
316962306a36Sopenharmony_ci				       override.parity,
317062306a36Sopenharmony_ci				       override.synchronous,
317162306a36Sopenharmony_ci				       override.delay,
317262306a36Sopenharmony_ci				       override.ext_trans);
317362306a36Sopenharmony_ci			} else
317462306a36Sopenharmony_ci				setup[setup_count++] = override;
317562306a36Sopenharmony_ci		}
317662306a36Sopenharmony_ci	}
317762306a36Sopenharmony_ci#endif
317862306a36Sopenharmony_ci
317962306a36Sopenharmony_ci#if defined(MODULE)
318062306a36Sopenharmony_ci	if (setup_count<ARRAY_SIZE(setup) && (aha152x[0]!=0 || io[0]!=0 || irq[0]!=0)) {
318162306a36Sopenharmony_ci		if(aha152x[0]!=0) {
318262306a36Sopenharmony_ci			setup[setup_count].conf        = "";
318362306a36Sopenharmony_ci			setup[setup_count].io_port     = aha152x[0];
318462306a36Sopenharmony_ci			setup[setup_count].irq         = aha152x[1];
318562306a36Sopenharmony_ci			setup[setup_count].scsiid      = aha152x[2];
318662306a36Sopenharmony_ci			setup[setup_count].reconnect   = aha152x[3];
318762306a36Sopenharmony_ci			setup[setup_count].parity      = aha152x[4];
318862306a36Sopenharmony_ci			setup[setup_count].synchronous = aha152x[5];
318962306a36Sopenharmony_ci			setup[setup_count].delay       = aha152x[6];
319062306a36Sopenharmony_ci			setup[setup_count].ext_trans   = aha152x[7];
319162306a36Sopenharmony_ci		} else if (io[0] != 0 || irq[0] != 0) {
319262306a36Sopenharmony_ci			if(io[0]!=0)  setup[setup_count].io_port = io[0];
319362306a36Sopenharmony_ci			if(irq[0]!=0) setup[setup_count].irq     = irq[0];
319462306a36Sopenharmony_ci
319562306a36Sopenharmony_ci			setup[setup_count].scsiid      = scsiid[0];
319662306a36Sopenharmony_ci			setup[setup_count].reconnect   = reconnect[0];
319762306a36Sopenharmony_ci			setup[setup_count].parity      = parity[0];
319862306a36Sopenharmony_ci			setup[setup_count].synchronous = sync[0];
319962306a36Sopenharmony_ci			setup[setup_count].delay       = delay[0];
320062306a36Sopenharmony_ci			setup[setup_count].ext_trans   = exttrans[0];
320162306a36Sopenharmony_ci		}
320262306a36Sopenharmony_ci
320362306a36Sopenharmony_ci		if (checksetup(&setup[setup_count]))
320462306a36Sopenharmony_ci			setup_count++;
320562306a36Sopenharmony_ci		else
320662306a36Sopenharmony_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",
320762306a36Sopenharmony_ci			       setup[setup_count].io_port,
320862306a36Sopenharmony_ci			       setup[setup_count].irq,
320962306a36Sopenharmony_ci			       setup[setup_count].scsiid,
321062306a36Sopenharmony_ci			       setup[setup_count].reconnect,
321162306a36Sopenharmony_ci			       setup[setup_count].parity,
321262306a36Sopenharmony_ci			       setup[setup_count].synchronous,
321362306a36Sopenharmony_ci			       setup[setup_count].delay,
321462306a36Sopenharmony_ci			       setup[setup_count].ext_trans);
321562306a36Sopenharmony_ci	}
321662306a36Sopenharmony_ci
321762306a36Sopenharmony_ci	if (setup_count<ARRAY_SIZE(setup) && (aha152x1[0]!=0 || io[1]!=0 || irq[1]!=0)) {
321862306a36Sopenharmony_ci		if(aha152x1[0]!=0) {
321962306a36Sopenharmony_ci			setup[setup_count].conf        = "";
322062306a36Sopenharmony_ci			setup[setup_count].io_port     = aha152x1[0];
322162306a36Sopenharmony_ci			setup[setup_count].irq         = aha152x1[1];
322262306a36Sopenharmony_ci			setup[setup_count].scsiid      = aha152x1[2];
322362306a36Sopenharmony_ci			setup[setup_count].reconnect   = aha152x1[3];
322462306a36Sopenharmony_ci			setup[setup_count].parity      = aha152x1[4];
322562306a36Sopenharmony_ci			setup[setup_count].synchronous = aha152x1[5];
322662306a36Sopenharmony_ci			setup[setup_count].delay       = aha152x1[6];
322762306a36Sopenharmony_ci			setup[setup_count].ext_trans   = aha152x1[7];
322862306a36Sopenharmony_ci		} else if (io[1] != 0 || irq[1] != 0) {
322962306a36Sopenharmony_ci			if(io[1]!=0)  setup[setup_count].io_port = io[1];
323062306a36Sopenharmony_ci			if(irq[1]!=0) setup[setup_count].irq     = irq[1];
323162306a36Sopenharmony_ci
323262306a36Sopenharmony_ci			setup[setup_count].scsiid      = scsiid[1];
323362306a36Sopenharmony_ci			setup[setup_count].reconnect   = reconnect[1];
323462306a36Sopenharmony_ci			setup[setup_count].parity      = parity[1];
323562306a36Sopenharmony_ci			setup[setup_count].synchronous = sync[1];
323662306a36Sopenharmony_ci			setup[setup_count].delay       = delay[1];
323762306a36Sopenharmony_ci			setup[setup_count].ext_trans   = exttrans[1];
323862306a36Sopenharmony_ci		}
323962306a36Sopenharmony_ci		if (checksetup(&setup[setup_count]))
324062306a36Sopenharmony_ci			setup_count++;
324162306a36Sopenharmony_ci		else
324262306a36Sopenharmony_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",
324362306a36Sopenharmony_ci			       setup[setup_count].io_port,
324462306a36Sopenharmony_ci			       setup[setup_count].irq,
324562306a36Sopenharmony_ci			       setup[setup_count].scsiid,
324662306a36Sopenharmony_ci			       setup[setup_count].reconnect,
324762306a36Sopenharmony_ci			       setup[setup_count].parity,
324862306a36Sopenharmony_ci			       setup[setup_count].synchronous,
324962306a36Sopenharmony_ci			       setup[setup_count].delay,
325062306a36Sopenharmony_ci			       setup[setup_count].ext_trans);
325162306a36Sopenharmony_ci	}
325262306a36Sopenharmony_ci#endif
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci#ifdef __ISAPNP__
325562306a36Sopenharmony_ci	for(i=0; setup_count<ARRAY_SIZE(setup) && id_table[i].vendor; i++) {
325662306a36Sopenharmony_ci		while ( setup_count<ARRAY_SIZE(setup) &&
325762306a36Sopenharmony_ci			(dev=pnp_find_dev(NULL, id_table[i].vendor, id_table[i].function, dev)) ) {
325862306a36Sopenharmony_ci			if (pnp_device_attach(dev) < 0)
325962306a36Sopenharmony_ci				continue;
326062306a36Sopenharmony_ci
326162306a36Sopenharmony_ci			if (pnp_activate_dev(dev) < 0) {
326262306a36Sopenharmony_ci				pnp_device_detach(dev);
326362306a36Sopenharmony_ci				continue;
326462306a36Sopenharmony_ci			}
326562306a36Sopenharmony_ci
326662306a36Sopenharmony_ci			if (!pnp_port_valid(dev, 0)) {
326762306a36Sopenharmony_ci				pnp_device_detach(dev);
326862306a36Sopenharmony_ci				continue;
326962306a36Sopenharmony_ci			}
327062306a36Sopenharmony_ci
327162306a36Sopenharmony_ci			if (setup_count==1 && pnp_port_start(dev, 0)==setup[0].io_port) {
327262306a36Sopenharmony_ci				pnp_device_detach(dev);
327362306a36Sopenharmony_ci				continue;
327462306a36Sopenharmony_ci			}
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci			setup[setup_count].io_port     = pnp_port_start(dev, 0);
327762306a36Sopenharmony_ci			setup[setup_count].irq         = pnp_irq(dev, 0);
327862306a36Sopenharmony_ci			setup[setup_count].scsiid      = 7;
327962306a36Sopenharmony_ci			setup[setup_count].reconnect   = 1;
328062306a36Sopenharmony_ci			setup[setup_count].parity      = 1;
328162306a36Sopenharmony_ci			setup[setup_count].synchronous = 1;
328262306a36Sopenharmony_ci			setup[setup_count].delay       = DELAY_DEFAULT;
328362306a36Sopenharmony_ci			setup[setup_count].ext_trans   = 0;
328462306a36Sopenharmony_ci#if defined(__ISAPNP__)
328562306a36Sopenharmony_ci			pnpdev[setup_count]            = dev;
328662306a36Sopenharmony_ci#endif
328762306a36Sopenharmony_ci			printk (KERN_INFO
328862306a36Sopenharmony_ci				"aha152x: found ISAPnP adapter at io=0x%03x, irq=%d\n",
328962306a36Sopenharmony_ci				setup[setup_count].io_port, setup[setup_count].irq);
329062306a36Sopenharmony_ci			setup_count++;
329162306a36Sopenharmony_ci		}
329262306a36Sopenharmony_ci	}
329362306a36Sopenharmony_ci#endif
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci#if defined(AUTOCONF)
329662306a36Sopenharmony_ci	if (setup_count<ARRAY_SIZE(setup)) {
329762306a36Sopenharmony_ci#if !defined(SKIP_BIOSTEST)
329862306a36Sopenharmony_ci		ok = 0;
329962306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(addresses) && !ok; i++) {
330062306a36Sopenharmony_ci			void __iomem *p = ioremap(addresses[i], 0x4000);
330162306a36Sopenharmony_ci			if (!p)
330262306a36Sopenharmony_ci				continue;
330362306a36Sopenharmony_ci			for (j = 0; j<ARRAY_SIZE(signatures) && !ok; j++)
330462306a36Sopenharmony_ci				ok = check_signature(p + signatures[j].sig_offset,
330562306a36Sopenharmony_ci								signatures[j].signature, signatures[j].sig_length);
330662306a36Sopenharmony_ci			iounmap(p);
330762306a36Sopenharmony_ci		}
330862306a36Sopenharmony_ci		if (!ok && setup_count == 0)
330962306a36Sopenharmony_ci			return -ENODEV;
331062306a36Sopenharmony_ci
331162306a36Sopenharmony_ci		printk(KERN_INFO "aha152x: BIOS test: passed, ");
331262306a36Sopenharmony_ci#else
331362306a36Sopenharmony_ci		printk(KERN_INFO "aha152x: ");
331462306a36Sopenharmony_ci#endif				/* !SKIP_BIOSTEST */
331562306a36Sopenharmony_ci
331662306a36Sopenharmony_ci		ok = 0;
331762306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(ports) && setup_count < 2; i++) {
331862306a36Sopenharmony_ci			if ((setup_count == 1) && (setup[0].io_port == ports[i]))
331962306a36Sopenharmony_ci				continue;
332062306a36Sopenharmony_ci
332162306a36Sopenharmony_ci			if (!request_region(ports[i], IO_RANGE, "aha152x")) {
332262306a36Sopenharmony_ci				printk(KERN_ERR "aha152x: io port 0x%x busy.\n", ports[i]);
332362306a36Sopenharmony_ci				continue;
332462306a36Sopenharmony_ci			}
332562306a36Sopenharmony_ci
332662306a36Sopenharmony_ci			if (aha152x_porttest(ports[i])) {
332762306a36Sopenharmony_ci				setup[setup_count].tc1550  = 0;
332862306a36Sopenharmony_ci
332962306a36Sopenharmony_ci				conf.cf_port =
333062306a36Sopenharmony_ci				    (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB);
333162306a36Sopenharmony_ci			} else if (tc1550_porttest(ports[i])) {
333262306a36Sopenharmony_ci				setup[setup_count].tc1550  = 1;
333362306a36Sopenharmony_ci
333462306a36Sopenharmony_ci				conf.cf_port =
333562306a36Sopenharmony_ci				    (GETPORT(ports[i] + O_TC_PORTA) << 8) + GETPORT(ports[i] + O_TC_PORTB);
333662306a36Sopenharmony_ci			} else {
333762306a36Sopenharmony_ci				release_region(ports[i], IO_RANGE);
333862306a36Sopenharmony_ci				continue;
333962306a36Sopenharmony_ci			}
334062306a36Sopenharmony_ci
334162306a36Sopenharmony_ci			release_region(ports[i], IO_RANGE);
334262306a36Sopenharmony_ci
334362306a36Sopenharmony_ci			ok++;
334462306a36Sopenharmony_ci			setup[setup_count].io_port = ports[i];
334562306a36Sopenharmony_ci			setup[setup_count].irq = IRQ_MIN + conf.cf_irq;
334662306a36Sopenharmony_ci			setup[setup_count].scsiid = conf.cf_id;
334762306a36Sopenharmony_ci			setup[setup_count].reconnect = conf.cf_tardisc;
334862306a36Sopenharmony_ci			setup[setup_count].parity = !conf.cf_parity;
334962306a36Sopenharmony_ci			setup[setup_count].synchronous = conf.cf_syncneg;
335062306a36Sopenharmony_ci			setup[setup_count].delay = DELAY_DEFAULT;
335162306a36Sopenharmony_ci			setup[setup_count].ext_trans = 0;
335262306a36Sopenharmony_ci			setup_count++;
335362306a36Sopenharmony_ci
335462306a36Sopenharmony_ci		}
335562306a36Sopenharmony_ci
335662306a36Sopenharmony_ci		if (ok)
335762306a36Sopenharmony_ci			printk("auto configuration: ok, ");
335862306a36Sopenharmony_ci	}
335962306a36Sopenharmony_ci#endif
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_ci	printk("%d controller(s) configured\n", setup_count);
336262306a36Sopenharmony_ci
336362306a36Sopenharmony_ci	for (i=0; i<setup_count; i++) {
336462306a36Sopenharmony_ci		if ( request_region(setup[i].io_port, IO_RANGE, "aha152x") ) {
336562306a36Sopenharmony_ci			struct Scsi_Host *shpnt = aha152x_probe_one(&setup[i]);
336662306a36Sopenharmony_ci
336762306a36Sopenharmony_ci			if( !shpnt ) {
336862306a36Sopenharmony_ci				release_region(setup[i].io_port, IO_RANGE);
336962306a36Sopenharmony_ci#if defined(__ISAPNP__)
337062306a36Sopenharmony_ci			} else if( pnpdev[i] ) {
337162306a36Sopenharmony_ci				HOSTDATA(shpnt)->pnpdev=pnpdev[i];
337262306a36Sopenharmony_ci				pnpdev[i]=NULL;
337362306a36Sopenharmony_ci#endif
337462306a36Sopenharmony_ci			}
337562306a36Sopenharmony_ci		} else {
337662306a36Sopenharmony_ci			printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup[i].io_port);
337762306a36Sopenharmony_ci		}
337862306a36Sopenharmony_ci
337962306a36Sopenharmony_ci#if defined(__ISAPNP__)
338062306a36Sopenharmony_ci		if( pnpdev[i] )
338162306a36Sopenharmony_ci			pnp_device_detach(pnpdev[i]);
338262306a36Sopenharmony_ci#endif
338362306a36Sopenharmony_ci	}
338462306a36Sopenharmony_ci
338562306a36Sopenharmony_ci	return 0;
338662306a36Sopenharmony_ci}
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_cistatic void __exit aha152x_exit(void)
338962306a36Sopenharmony_ci{
339062306a36Sopenharmony_ci	struct aha152x_hostdata *hd, *tmp;
339162306a36Sopenharmony_ci
339262306a36Sopenharmony_ci	list_for_each_entry_safe(hd, tmp, &aha152x_host_list, host_list) {
339362306a36Sopenharmony_ci		struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
339462306a36Sopenharmony_ci
339562306a36Sopenharmony_ci		aha152x_release(shost);
339662306a36Sopenharmony_ci	}
339762306a36Sopenharmony_ci}
339862306a36Sopenharmony_ci
339962306a36Sopenharmony_cimodule_init(aha152x_init);
340062306a36Sopenharmony_cimodule_exit(aha152x_exit);
340162306a36Sopenharmony_ci
340262306a36Sopenharmony_ci#if !defined(MODULE)
340362306a36Sopenharmony_cistatic int __init aha152x_setup(char *str)
340462306a36Sopenharmony_ci{
340562306a36Sopenharmony_ci	int ints[10];
340662306a36Sopenharmony_ci
340762306a36Sopenharmony_ci	get_options(str, ARRAY_SIZE(ints), ints);
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ci	if(setup_count>=ARRAY_SIZE(setup)) {
341062306a36Sopenharmony_ci		printk(KERN_ERR "aha152x: you can only configure up to two controllers\n");
341162306a36Sopenharmony_ci		return 1;
341262306a36Sopenharmony_ci	}
341362306a36Sopenharmony_ci
341462306a36Sopenharmony_ci	setup[setup_count].conf        = str;
341562306a36Sopenharmony_ci	setup[setup_count].io_port     = ints[0] >= 1 ? ints[1] : 0x340;
341662306a36Sopenharmony_ci	setup[setup_count].irq         = ints[0] >= 2 ? ints[2] : 11;
341762306a36Sopenharmony_ci	setup[setup_count].scsiid      = ints[0] >= 3 ? ints[3] : 7;
341862306a36Sopenharmony_ci	setup[setup_count].reconnect   = ints[0] >= 4 ? ints[4] : 1;
341962306a36Sopenharmony_ci	setup[setup_count].parity      = ints[0] >= 5 ? ints[5] : 1;
342062306a36Sopenharmony_ci	setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 1;
342162306a36Sopenharmony_ci	setup[setup_count].delay       = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT;
342262306a36Sopenharmony_ci	setup[setup_count].ext_trans   = ints[0] >= 8 ? ints[8] : 0;
342362306a36Sopenharmony_ci	if (ints[0] > 8)
342462306a36Sopenharmony_ci		printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
342562306a36Sopenharmony_ci		       "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n");
342662306a36Sopenharmony_ci	else
342762306a36Sopenharmony_ci		setup_count++;
342862306a36Sopenharmony_ci
342962306a36Sopenharmony_ci	return 1;
343062306a36Sopenharmony_ci}
343162306a36Sopenharmony_ci__setup("aha152x=", aha152x_setup);
343262306a36Sopenharmony_ci#endif
343362306a36Sopenharmony_ci
343462306a36Sopenharmony_ci#endif /* !AHA152X_PCMCIA */
3435