diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-05 06:47:02 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-05 06:47:02 +0000 |
commit | 99a7e12f34b3661a0d1354eef83a0eef4df5e34c (patch) | |
tree | 3560aca9ca86792f9ab7bd87861ea143a1b3c7a3 /drivers/scsi/aha152x.c | |
parent | e73a04659c0b8cdee4dd40e58630e2cf63afb316 (diff) |
Merge with Linux 2.3.38.
Diffstat (limited to 'drivers/scsi/aha152x.c')
-rw-r--r-- | drivers/scsi/aha152x.c | 4057 |
1 files changed, 2173 insertions, 1884 deletions
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 67c026bc2..38550e1d3 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -1,13 +1,6 @@ /* aha152x.c -- Adaptec AHA-152x driver - * Author: Jürgen E. Fischer, fischer@et-inf.fho-emden.de - * Copyright 1993, 1994, 1995, 1996 Jürgen E. Fischer - * - * - * This driver is based on - * fdomain.c -- Future Domain TMC-16x0 driver - * which is - * Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu) - * + * Author: Jürgen E. Fischer, fischer@norbit.de + * Copyright 1993-1999 Jürgen E. Fischer * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -20,9 +13,30 @@ * General Public License for more details. * * - * $Id: aha152x.c,v 1.18 1996/09/07 20:10:40 fischer Exp $ + * $Id: aha152x.c,v 2.0 1999/12/25 15:07:32 fischer Exp fischer $ * * $Log: aha152x.c,v $ + * Revision 2.0 1999/12/25 15:07:32 fischer + * - interrupt routine completly reworked + * - basic support for new eh code + * + * Revision 1.21 1999/11/10 23:46:36 fischer + * - default to synchronous operation + * - synchronous negotiation fixed + * - added timeout to loops + * - debugging output can be controlled through procfs + * + * Revision 1.20 1999/11/07 18:37:31 fischer + * - synchronous operation works + * - resid support for sg driver + * + * Revision 1.19 1999/11/02 22:39:59 fischer + * - moved leading comments to README.aha152x + * - new additional module parameters + * - updates for 2.3 + * - support for the Tripace TC1550 controller + * - interrupt handling changed + * * Revision 1.18 1996/09/07 20:10:40 fischer * - fixed can_queue handling (multiple outstanding commands working again) * @@ -181,152 +195,18 @@ * * ************************************************************************** - - - - DESCRIPTION: - - This is the Linux low-level SCSI driver for Adaptec AHA-1520/1522 SCSI - host adapters. - - - CONFIGURATION ARGUMENTS: - - IOPORT base io address (0x340/0x140) - IRQ interrupt level (9-12; default 11) - SCSI_ID scsi id of controller (0-7; default 7) - RECONNECT allow targets to disconnect from the bus (0/1; default 1 [on]) - PARITY enable parity checking (0/1; default 1 [on]) - SYNCHRONOUS enable synchronous transfers (0/1; default 0 [off]) - (NOT WORKING YET) - DELAY: bus reset delay (default 100) - EXT_TRANS: enable extended translation (0/1: default 0 [off]) - (see NOTES below) - - COMPILE TIME CONFIGURATION (put into AHA152X in drivers/scsi/Makefile): - - -DAUTOCONF - use configuration the controller reports (AHA-152x only) - - -DSKIP_BIOSTEST - Don't test for BIOS signature (AHA-1510 or disabled BIOS) - - -DSETUP0="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }" - override for the first controller - - -DSETUP1="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }" - override for the second controller - - - LILO COMMAND LINE OPTIONS: - - aha152x=<IOPORT>[,<IRQ>[,<SCSI-ID>[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY> [,<EXT_TRANS]]]]]]] - - The normal configuration can be overridden by specifying a command line. - When you do this, the BIOS test is skipped. Entered values have to be - valid (known). Don't use values that aren't supported under normal - operation. If you think that you need other values: contact me. - For two controllers use the aha152x statement twice. - - - SYMBOLS FOR MODULE CONFIGURATION: - - aha152x=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS - configuration override of first controller - - - aha152x1=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS - configuration override of second controller - - - NOTES ON EXT_TRANS: - - SCSI uses block numbers to address blocks/sectors on a device. - The BIOS uses a cylinder/head/sector addressing scheme (C/H/S) - scheme instead. DOS expects a BIOS or driver that understands this - C/H/S addressing. - - The number of cylinders/heads/sectors is called geometry and is required - as base for requests in C/H/S addressing. SCSI only knows about the - total capacity of disks in blocks (sectors). - - Therefore the SCSI BIOS/DOS driver has to calculate a logical/virtual - geometry just to be able to support that addressing scheme. The geometry - returned by the SCSI BIOS is a pure calculation and has nothing to - do with the real/physical geometry of the disk (which is usually - irrelevant anyway). - - Basically this has no impact at all on Linux, because it also uses block - instead of C/H/S addressing. Unfortunately C/H/S addressing is also used - in the partition table and therefore every operating system has to know - the right geometry to be able to interpret it. - - Moreover there are certain limitations to the C/H/S addressing scheme, - namely the address space is limited to upto 255 heads, upto 63 sectors - and a maximum of 1023 cylinders. - - The AHA-1522 BIOS calculates the geometry by fixing the number of heads - to 64, the number of sectors to 32 and by calculating the number of - cylinders by dividing the capacity reported by the disk by 64*32 (1 MB). - This is considered to be the default translation. - - With respect to the limit of 1023 cylinders using C/H/S you can only - address the first GB of your disk in the partition table. Therefore - BIOSes of some newer controllers based on the AIC-6260/6360 support - extended translation. This means that the BIOS uses 255 for heads, - 63 for sectors and then divides the capacity of the disk by 255*63 - (about 8 MB), as soon it sees a disk greater than 1 GB. That results - in a maximum of about 8 GB addressable diskspace in the partition table - (but there are already bigger disks out there today). - - To make it even more complicated the translation mode might/might - not be configurable in certain BIOS setups. - - This driver does some more or less failsafe guessing to get the - geometry right in most cases: - - - for disks<1GB: use default translation (C/32/64) - - for disks>1GB: - - take current geometry from the partition table - (using scsicam_bios_param and accept only `valid' geometries, - ie. either (C/32/64) or (C/63/255)). This can be extended - translation even if it's not enabled in the driver. - - if that fails, take extended translation if enabled by override, - kernel or module parameter, otherwise take default translation and - ask the user for verification. This might on not yet partitioned - disks or - - - REFERENCES USED: - - "AIC-6260 SCSI Chip Specification", Adaptec Corporation. - - "SCSI COMPUTER SYSTEM INTERFACE - 2 (SCSI-2)", X3T9.2/86-109 rev. 10h - - "Writing a SCSI device driver for Linux", Rik Faith (faith@cs.unc.edu) - - "Kernel Hacker's Guide", Michael K. Johnson (johnsonm@sunsite.unc.edu) - - "Adaptec 1520/1522 User's Guide", Adaptec Corporation. - - Michael K. Johnson (johnsonm@sunsite.unc.edu) - - Drew Eckhardt (drew@cs.colorado.edu) - - Eric Youngdale (ericy@cais.com) - - special thanks to Eric Youngdale for the free(!) supplying the - documentation on the chip. + + see README.aha152x for configuration details **************************************************************************/ -#ifdef PCMCIA +#if defined(PCMCIA) #define MODULE #endif #include <linux/module.h> -#ifdef PCMCIA +#if defined(PCMCIA) #undef MODULE #endif @@ -342,10 +222,13 @@ #include <linux/string.h> #include <linux/wait.h> #include <linux/ioport.h> +#include <linux/delay.h> #include <linux/proc_fs.h> #include <linux/interrupt.h> #include <linux/init.h> #include <linux/kernel.h> +#include <asm/semaphore.h> +#include <linux/spinlock.h> #include "aha152x.h" #include <linux/stat.h> @@ -365,53 +248,55 @@ #error define AUTOCONF or SETUP0 #endif -#if defined(DEBUG_AHA152X) - -#undef SKIP_PORTS /* don't display ports */ - -#undef DEBUG_QUEUE /* debug queue() */ -#undef DEBUG_RESET /* debug reset() */ -#undef DEBUG_INTR /* debug intr() */ -#undef DEBUG_SELECTION /* debug selection part in intr() */ -#undef DEBUG_MSGO /* debug message out phase in intr() */ -#undef DEBUG_MSGI /* debug message in phase in intr() */ -#undef DEBUG_STATUS /* debug status phase in intr() */ -#undef DEBUG_CMD /* debug command phase in intr() */ -#undef DEBUG_DATAI /* debug data in phase in intr() */ -#undef DEBUG_DATAO /* debug data out phase in intr() */ -#undef DEBUG_ABORT /* debug abort() */ -#undef DEBUG_DONE /* debug done() */ -#undef DEBUG_BIOSPARAM /* debug biosparam() */ - -#undef DEBUG_RACE /* debug race conditions */ -#undef DEBUG_PHASES /* debug phases (useful to trace) */ -#undef DEBUG_QUEUES /* debug reselection */ - -/* recently used for debugging */ -#if 0 -#endif - -#define DEBUG_SELECTION -#define DEBUG_PHASES -#define DEBUG_RESET -#define DEBUG_ABORT - -#define DEBUG_DEFAULT (debug_reset|debug_abort) - -#endif - -/* END OF DEFINES */ +#if defined(AHA152X_DEBUG) +#define DEBUG_DEFAULT debug_eh + +#define DPRINTK(when,msgs...) \ + do { if(HOSTDATA(shpnt)->debug & (when)) printk(msgs); } while(0) + +#define DO_LOCK(flags) \ + do { \ + if(QLOCK.lock) { \ + DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \ + } \ + DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \ + spin_lock_irqsave(&QLOCK,flags); \ + DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \ + QLOCKER=__FUNCTION__; \ + QLOCKERL=__LINE__; \ + } while(0) + +#define DO_UNLOCK(flags) \ + do { \ + DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \ + spin_unlock_irqrestore(&QLOCK,flags); \ + DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \ + QLOCKER="(not locked)"; \ + QLOCKERL=0; \ + } while(0) -extern long loops_per_sec; +#else +#define DPRINTK(when,msgs...) +#define DO_LOCK(flags) spin_lock_irqsave(&QLOCK,flags) +#define DO_UNLOCK(flags) spin_unlock_irqrestore(&QLOCK,flags) +#define DEBUG_DEFAULT 0 +#endif + +#define LEAD "(scsi%d:%d:%d) " +#define WARN_LEAD KERN_WARNING LEAD +#define INFO_LEAD KERN_INFO LEAD +#define NOTE_LEAD KERN_NOTICE LEAD +#define ERR_LEAD KERN_ERR LEAD +#define DEBUG_LEAD KERN_DEBUG LEAD +#define CMDINFO(cmd) \ + (cmd) ? ((cmd)->host->host_no) : -1, \ + (cmd) ? ((cmd)->target & 0x0f) : -1, \ + (cmd) ? ((cmd)->lun & 0x07) : -1 #define DELAY_DEFAULT 100 -/* some additional "phases" for getphase() */ -#define P_BUSFREE 1 -#define P_PARITY 2 - /* possible irq range */ -#ifdef PCMCIA +#if defined(PCMCIA) #define IRQ_MIN 0 #define IRQ_MAX 16 #else @@ -421,33 +306,76 @@ extern long loops_per_sec; #define IRQS IRQ_MAX-IRQ_MIN+1 enum { - not_issued = 0x0001, - in_selection = 0x0002, - disconnected = 0x0004, - aborted = 0x0008, - sent_ident = 0x0010, - in_other = 0x0020, - in_sync = 0x0040, - sync_ok = 0x0080, + not_issued = 0x0001, /* command not yet issued */ + selecting = 0x0002, /* target is beeing selected */ + identified = 0x0004, /* IDENTIFY was sent */ + disconnected = 0x0008, /* target disconnected */ + completed = 0x0010, /* target sent COMMAND COMPLETE */ + aborted = 0x0020, /* ABORT was sent */ + resetted = 0x0040, /* BUS DEVICE RESET was sent */ + spiordy = 0x0080, /* waiting for SPIORDY to raise */ + syncneg = 0x0100, /* synchronous negotiation in progress */ + aborting = 0x0200, /* ABORT is pending */ + resetting = 0x0400, /* BUS DEVICE RESET is pending */ }; #if defined(MODULE) -#if defined(DEBUG_AHA152X) -int aha152x[] = -{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT}; -int aha152x1[] = -{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT}; -MODULE_PARM(aha152x, "1-9i"); -MODULE_PARM(aha152x1, "1-9i"); -#else -int aha152x[] = -{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; -int aha152x1[] = -{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; +MODULE_AUTHOR("Jürgen Fischer"); +MODULE_DESCRIPTION(AHA152X_REVID); +MODULE_PARM(io, "1-2i"); +MODULE_PARM_DESC(io,"base io address of controller"); +static int io[] = {0, 0}; + +MODULE_PARM(irq, "1-2i"); +MODULE_PARM_DESC(irq,"interrupt for controller"); +static int irq[] = {0, 0}; + +MODULE_PARM(scsiid, "1-2i"); +MODULE_PARM_DESC(scsiid,"scsi id of controller"); +static int scsiid[] = {7, 7}; + +MODULE_PARM(reconnect, "1-2i"); +MODULE_PARM_DESC(reconnect,"allow targets to disconnect"); +static int reconnect[] = {1, 1}; + +MODULE_PARM(parity, "1-2i"); +MODULE_PARM_DESC(parity,"use scsi parity"); +static int parity[] = {1, 1}; + +MODULE_PARM(sync, "1-2i"); +MODULE_PARM_DESC(sync,"use synchronous transfers"); +static int sync[] = {1, 1}; + +MODULE_PARM(delay, "1-2i"); +MODULE_PARM_DESC(delay,"scsi reset delay"); +static int delay[] = {DELAY_DEFAULT, DELAY_DEFAULT}; + +MODULE_PARM(exttrans, "1-2i"); +MODULE_PARM_DESC(exttrans,"use extended translation"); +static int exttrans[] = {0, 0}; + +#if !defined(AHA152X_DEBUG) MODULE_PARM(aha152x, "1-8i"); +MODULE_PARM_DESC(aha152x, "parameters for first controller"); +static int aha152x[] = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT}; + MODULE_PARM(aha152x1, "1-8i"); -#endif -#endif +MODULE_PARM_DESC(aha152x1, "parameters for second controller"); +static int aha152x1[] = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT}; +#else +MODULE_PARM(debug, "1-2i"); +MODULE_PARM_DESC(debug, "flags for driver debugging"); +static int debug[] = {DEBUG_DEFAULT, DEBUG_DEFAULT}; + +MODULE_PARM(aha152x, "1-9i"); +MODULE_PARM_DESC(aha152x, "parameters for first controller"); +static int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; + +MODULE_PARM(aha152x1, "1-9i"); +MODULE_PARM_DESC(aha152x1, "parameters for second controller"); +static int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; +#endif /* !defined(AHA152X_DEBUG) */ +#endif /* MODULE */ /* set by aha152x_setup according to the command line */ static int setup_count = 0; @@ -461,7 +389,8 @@ static struct aha152x_setup { int synchronous; int delay; int ext_trans; -#ifdef DEBUG_AHA152X + int tc1550; +#if defined(AHA152X_DEBUG) int debug; #endif char *conf; @@ -469,73 +398,259 @@ static struct aha152x_setup { static struct Scsi_Host *aha152x_host[IRQS]; -#define HOSTDATA(shpnt) ((struct aha152x_hostdata *) &shpnt->hostdata) -#define CURRENT_SC (HOSTDATA(shpnt)->current_SC) -#define ISSUE_SC (HOSTDATA(shpnt)->issue_SC) -#define DISCONNECTED_SC (HOSTDATA(shpnt)->disconnected_SC) -#define DELAY (HOSTDATA(shpnt)->delay) -#define EXT_TRANS (HOSTDATA(shpnt)->ext_trans) -#define SYNCRATE (HOSTDATA(shpnt)->syncrate[CURRENT_SC->target]) -#define MSG(i) (HOSTDATA(shpnt)->message[i]) -#define MSGLEN (HOSTDATA(shpnt)->message_len) -#define ADDMSG(x) (MSG(MSGLEN++)=x) +/* + * internal states of the host + * + */ +enum aha152x_state { + idle=0, + unknown, + seldo, + seldi, + selto, + busfree, + msgo, + cmd, + msgi, + status, + datai, + datao, + parerr, + rsti, + maxstate +}; +/* + * current state information of the host + * + */ struct aha152x_hostdata { Scsi_Cmnd *issue_SC; + /* pending commands to issue */ + Scsi_Cmnd *current_SC; + /* current command on the bus */ + Scsi_Cmnd *disconnected_SC; - int aborting; - int abortion_complete; - int abort_result; - int commands; + /* commands that disconnected */ - int reconnect; - int parity; - int synchronous; - int delay; - int ext_trans; + Scsi_Cmnd *done_SC; + /* command that was completed */ - int swint; - int service; + spinlock_t lock; + /* host lock */ - unsigned char syncrate[8]; +#if defined(AHA152X_DEBUG) + char *locker; /* which function has the lock */ + int lockerl; /* where did it get it */ - unsigned char message[256]; - int message_len; + int debug; /* current debugging setting */ +#endif -#ifdef DEBUG_AHA152X - int debug; +#if defined(AHA152X_STAT) + int total_commands; + int disconnections; + int busfree_without_any_action; + int busfree_without_old_command; + int busfree_without_new_command; + int busfree_without_done_command; + int busfree_with_check_condition; + int count[maxstate]; + int count_trans[maxstate]; + unsigned long time[maxstate]; #endif + + int commands; /* current number of commands */ + + int reconnect; /* disconnection allowed */ + int parity; /* parity checking enabled */ + int synchronous; /* synchronous transferes enabled */ + int delay; /* reset out delay */ + int ext_trans; /* extended translation enabled */ + + int swint; /* software-interrupt was fired during detect() */ + int service; /* bh needs to be run */ + int in_intr; /* bh is running */ + + /* current state, + previous state, + last state different from current state */ + enum aha152x_state state, prevstate, laststate; + + int target; + /* reconnecting target */ + + unsigned char syncrate[8]; + /* current synchronous transfer agreements */ + + unsigned char syncneg[8]; + /* 0: no negotiation; + * 1: negotiation in progress; + * 2: negotiation completed + */ + + int cmd_i; + /* number of sent bytes of current command */ + + int msgi_len; + /* number of received message bytes */ + unsigned char msgi[256]; + /* received message bytes */ + + int msgo_i, msgo_len; + /* number of sent bytes and length of current messages */ + unsigned char msgo[256]; + /* pending messages */ + + int data_len; + /* number of sent/received bytes in dataphase */ + + unsigned long io_port0; + unsigned long io_port1; +}; + + +/* + * host specific command extension + * + */ +struct aha152x_scdata { + Scsi_Cmnd *next; /* next sc in queue */ + Scsi_Cmnd *done; /* done command */ + struct semaphore *sem; /* semaphore to block on */ }; -static void aha152x_intr(int irq, void *dev_id, struct pt_regs *); -void aha152x_done(struct Scsi_Host *shpnt, int error); -void aha152x_setup(char *str, int *ints); -int aha152x_checksetup(struct aha152x_setup *setup); -static void aha152x_reset_ports(struct Scsi_Host *shpnt); -static void aha152x_panic(struct Scsi_Host *shpnt, char *msg); +/* access macros for hostdata */ + +#define HOSTDATA(shpnt) ((struct aha152x_hostdata *) &shpnt->hostdata) + +#define HOSTNO ((shpnt)->host_no) +#define CURRENT_SC (HOSTDATA(shpnt)->current_SC) +#define DONE_SC (HOSTDATA(shpnt)->done_SC) +#define ISSUE_SC (HOSTDATA(shpnt)->issue_SC) +#define DISCONNECTED_SC (HOSTDATA(shpnt)->disconnected_SC) +#define QLOCK (HOSTDATA(shpnt)->lock) +#define QLOCKER (HOSTDATA(shpnt)->locker) +#define QLOCKERL (HOSTDATA(shpnt)->lockerl) + +#define STATE (HOSTDATA(shpnt)->state) +#define PREVSTATE (HOSTDATA(shpnt)->prevstate) +#define LASTSTATE (HOSTDATA(shpnt)->laststate) + +#define RECONN_TARGET (HOSTDATA(shpnt)->target) + +#define CMD_I (HOSTDATA(shpnt)->cmd_i) + +#define MSGO(i) (HOSTDATA(shpnt)->msgo[i]) +#define MSGO_I (HOSTDATA(shpnt)->msgo_i) +#define MSGOLEN (HOSTDATA(shpnt)->msgo_len) +#define ADDMSGO(x) (MSGOLEN<256 ? MSGO(MSGOLEN++)=x : aha152x_error(shpnt,"MSGO overflow")) + +#define MSGI(i) (HOSTDATA(shpnt)->msgi[i]) +#define MSGILEN (HOSTDATA(shpnt)->msgi_len) +#define ADDMSGI(x) (MSGILEN<256 ? MSGI(MSGILEN++)=x : aha152x_error(shpnt,"MSGI overflow")) + +#define DATA_LEN (HOSTDATA(shpnt)->data_len) + +#define SYNCRATE (HOSTDATA(shpnt)->syncrate[CURRENT_SC->target]) +#define SYNCNEG (HOSTDATA(shpnt)->syncneg[CURRENT_SC->target]) + +#define DELAY (HOSTDATA(shpnt)->delay) +#define EXT_TRANS (HOSTDATA(shpnt)->ext_trans) +#define TC1550 (HOSTDATA(shpnt)->tc1550) +#define RECONNECT (HOSTDATA(shpnt)->reconnect) +#define PARITY (HOSTDATA(shpnt)->parity) +#define SYNCHRONOUS (HOSTDATA(shpnt)->synchronous) + +#define HOSTIOPORT0 (HOSTDATA(shpnt)->io_port0) +#define HOSTIOPORT1 (HOSTDATA(shpnt)->io_port1) + +#define SCDATA(SCpnt) ((struct aha152x_scdata *) (SCpnt)->host_scribble) +#define SCNEXT(SCpnt) SCDATA(SCpnt)->next +#define SCDONE(SCpnt) SCDATA(SCpnt)->done +#define SCSEM(SCpnt) SCDATA(SCpnt)->sem + + +/* state handling */ +static void seldi_run(struct Scsi_Host *shpnt); +static void seldo_run(struct Scsi_Host *shpnt); +static void selto_run(struct Scsi_Host *shpnt); +static void busfree_run(struct Scsi_Host *shpnt); + +static void msgo_init(struct Scsi_Host *shpnt); +static void msgo_run(struct Scsi_Host *shpnt); +static void msgo_end(struct Scsi_Host *shpnt); + +static void cmd_init(struct Scsi_Host *shpnt); +static void cmd_run(struct Scsi_Host *shpnt); +static void cmd_end(struct Scsi_Host *shpnt); + +static void datai_init(struct Scsi_Host *shpnt); +static void datai_run(struct Scsi_Host *shpnt); +static void datai_end(struct Scsi_Host *shpnt); + +static void datao_init(struct Scsi_Host *shpnt); +static void datao_run(struct Scsi_Host *shpnt); +static void datao_end(struct Scsi_Host *shpnt); + +static void status_run(struct Scsi_Host *shpnt); + +static void msgi_run(struct Scsi_Host *shpnt); +static void msgi_end(struct Scsi_Host *shpnt); + +static void parerr_run(struct Scsi_Host *shpnt); +static void rsti_run(struct Scsi_Host *shpnt); + +static void complete(struct Scsi_Host *shpnt); + +/* + * driver states + * + */ +static struct { + char *name; + void (*init)(struct Scsi_Host *); + void (*run)(struct Scsi_Host *); + void (*end)(struct Scsi_Host *); + int spio; +} states[] = { + { "idle", 0, 0, 0, 0}, + { "unknown", 0, 0, 0, 0}, + { "seldo", 0, seldo_run, 0, 0}, + { "seldi", 0, seldi_run, 0, 0}, + { "selto", 0, selto_run, 0, 0}, + { "busfree", 0, busfree_run, 0, 0}, + { "msgo", msgo_init, msgo_run, msgo_end, 1}, + { "cmd", cmd_init, cmd_run, cmd_end, 1}, + { "msgi", 0, msgi_run, msgi_end, 1}, + { "status", 0, status_run, 0, 1}, + { "datai", datai_init, datai_run, datai_end, 0}, + { "datao", datao_init, datao_run, datao_end, 0}, + { "parerr", 0, parerr_run, 0, 0}, + { "rsti", 0, rsti_run, 0, 0}, +}; + +/* setup & interrupt */ +static void intr(int irq, void *dev_id, struct pt_regs *); +static void reset_ports(struct Scsi_Host *shpnt); +static void aha152x_error(struct Scsi_Host *shpnt, char *msg); +static void done(struct Scsi_Host *shpnt, int error); +static int checksetup(struct aha152x_setup *setup); + +/* diagnostics */ static void disp_ports(struct Scsi_Host *shpnt); static void show_command(Scsi_Cmnd * ptr); static void show_queues(struct Scsi_Host *shpnt); static void disp_enintr(struct Scsi_Host *shpnt); -#if defined(DEBUG_RACE) -static void enter_driver(const char *); -static void leave_driver(const char *); -#endif - -/* possible i/o addresses for the AIC-6260 */ -static unsigned short ports[] = -{ - 0x340, /* default first */ - 0x140 -}; +/* possible i/o addresses for the AIC-6260; default first */ +static unsigned short ports[] = { 0x340, 0x140 }; #define PORT_COUNT (sizeof(ports) / sizeof(unsigned short)) #if !defined(SKIP_BIOSTEST) -/* possible locations for the Adaptec BIOS */ +/* possible locations for the Adaptec BIOS; defaults first */ static unsigned int addresses[] = { 0xdc000, /* default first */ @@ -562,71 +677,52 @@ static struct signature { int sig_offset; int sig_length; } signatures[] = - { - { - "Adaptec AHA-1520 BIOS", 0x102e, 21 - }, /* Adaptec 152x */ - { - "Adaptec AHA-1520B", 0x0b, 19 - }, /* Adaptec 152x rev B */ - { - "Adaptec ASW-B626 BIOS", 0x1029, 21 - }, /* on-board controller */ - { - "Adaptec BIOS: ASW-B626", 0x0f, 22 - }, /* on-board controller */ - { - "Adaptec ASW-B626 S2", 0x2e6c, 19 - }, /* on-board controller */ - { - "Adaptec BIOS:AIC-6360", 0xc, 21 - }, /* on-board controller */ - { - "ScsiPro SP-360 BIOS", 0x2873, 19 - }, /* ScsiPro-Controller */ - { - "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 - }, /* Gigabyte Local-Bus-SCSI */ - { - "Adaptec BIOS:AVA-282X", 0xc, 21 - }, /* Adaptec 282x */ - { - "Adaptec IBM Dock II SCSI", 0x2edd, 24 - }, /* IBM Thinkpad Dock II */ - { - "Adaptec BIOS:AHA-1532P", 0x1c, 22 - }, /* IBM Thinkpad Dock II SCSI */ - { - "DTC3520A Host Adapter BIOS", 0x318a, 26 - }, /* DTC 3520A ISA SCSI */ + { "Adaptec AHA-1520 BIOS", 0x102e, 21 }, + /* Adaptec 152x */ + { "Adaptec AHA-1520B", 0x000b, 19 }, + /* Adaptec 152x rev B */ + { "Adaptec ASW-B626 BIOS", 0x1029, 21 }, + /* on-board controller */ + { "Adaptec BIOS: ASW-B626", 0x000f, 22 }, + /* on-board controller */ + { "Adaptec ASW-B626 S2", 0x2e6c, 19 }, + /* on-board controller */ + { "Adaptec BIOS:AIC-6360", 0x000c, 21 }, + /* on-board controller */ + { "ScsiPro SP-360 BIOS", 0x2873, 19 }, + /* ScsiPro-Controller */ + { "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 }, + /* Gigabyte Local-Bus-SCSI */ + { "Adaptec BIOS:AVA-282X", 0x000c, 21 }, + /* Adaptec 282x */ + { "Adaptec IBM Dock II SCSI", 0x2edd, 24 }, + /* IBM Thinkpad Dock II */ + { "Adaptec BIOS:AHA-1532P", 0x001c, 22 }, + /* IBM Thinkpad Dock II SCSI */ + { "DTC3520A Host Adapter BIOS", 0x318a, 26 }, + /* DTC 3520A ISA SCSI */ }; #define SIGNATURE_COUNT (sizeof(signatures) / sizeof(struct signature)) #endif -static void do_pause(unsigned amount) -{ /* Pause for amount*10 milliseconds */ - unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */ - - while (time_before(jiffies, the_time)) - barrier(); -} - /* * queue services: + * */ -static inline void append_SC(Scsi_Cmnd ** SC, Scsi_Cmnd * new_SC) +static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC) { Scsi_Cmnd *end; - new_SC->host_scribble = (unsigned char *) NULL; + SCNEXT(new_SC) = NULL; if (!*SC) *SC = new_SC; else { - for (end = *SC; end->host_scribble; end = (Scsi_Cmnd *) end->host_scribble); - end->host_scribble = (unsigned char *) new_SC; + for (end = *SC; SCNEXT(end); end = SCNEXT(end)) + ; + SCNEXT(end) = new_SC; } } @@ -635,135 +731,113 @@ static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd ** SC) Scsi_Cmnd *ptr; ptr = *SC; - if (ptr) - *SC = (Scsi_Cmnd *) (*SC)->host_scribble; + if (ptr) { + *SC = SCNEXT(*SC); + SCNEXT(ptr)=NULL; + } return ptr; } -static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd ** SC, int target, int lun) +static inline Scsi_Cmnd *remove_lun_SC(Scsi_Cmnd ** SC, int target, int lun) { Scsi_Cmnd *ptr, *prev; for (ptr = *SC, prev = NULL; ptr && ((ptr->target != target) || (ptr->lun != lun)); - prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble); + prev = ptr, ptr = SCNEXT(ptr)) + ; if (ptr) { if (prev) - prev->host_scribble = ptr->host_scribble; + SCNEXT(prev) = SCNEXT(ptr); else - *SC = (Scsi_Cmnd *) ptr->host_scribble; - } - return ptr; -} + *SC = SCNEXT(ptr); -/* - * read inbound byte and wait for ACK to get low - */ -static void make_acklow(struct Scsi_Host *shpnt) -{ - SETPORT(SXFRCTL0, CH1 | SPIOEN); - GETPORT(SCSIDAT); - SETPORT(SXFRCTL0, CH1); + SCNEXT(ptr)=NULL; + } - while (TESTHI(SCSISIG, ACKI)) - barrier(); + return ptr; } -/* - * detect current phase more reliable: - * phase is valid, when the target asserts REQ after we've deasserted ACK. - * - * return value is a valid phase or an error code. - * - * errorcodes: - * P_BUSFREE BUS FREE phase detected - * P_PARITY parity error in DATA phase - */ -static int getphase(struct Scsi_Host *shpnt) +static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp) { - int phase, sstat1; - - while (1) { - do { - while (!((sstat1 = GETPORT(SSTAT1)) & (BUSFREE | SCSIRSTI | REQINIT))) - barrier(); - if (sstat1 & BUSFREE) - return P_BUSFREE; - if (sstat1 & SCSIRSTI) { - printk("aha152x: RESET IN\n"); - SETPORT(SSTAT1, SCSIRSTI); - } - } while (TESTHI(SCSISIG, ACKI) || TESTLO(SSTAT1, REQINIT)); - - SETPORT(SSTAT1, CLRSCSIPERR); + Scsi_Cmnd *ptr, *prev; - phase = GETPORT(SCSISIG) & P_MASK; + for (ptr = *SC, prev = NULL; + ptr && SCp!=ptr; + prev = ptr, ptr = SCNEXT(ptr)) + ; - if (TESTHI(SSTAT1, SCSIPERR)) { - if ((phase & (CDO | MSGO)) == 0) /* DATA phase */ - return P_PARITY; + if (ptr) { + if (prev) + SCNEXT(prev) = SCNEXT(ptr); + else + *SC = SCNEXT(ptr); - make_acklow(shpnt); - } else - return phase; + SCNEXT(ptr)=NULL; } + + return ptr; } -#ifdef PCMCIA +#if defined(PCMCIA) || !defined(MODULE) void aha152x_setup(char *str, int *ints) { - if (setup_count > 2) - panic("aha152x: you can only configure up to two controllers\n"); - - setup[setup_count].conf = str; - setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340; - setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11; - setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7; - setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1; - setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1; - setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 0 /* FIXME: 1 */ ; - setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT; - setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0; -#ifdef DEBUG_AHA152X - setup[setup_count].debug = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT; + if(setup_count>2) { + printk(KERN_ERR "aha152x: you can only configure up to two controllers\n"); + return; + } + + setup[setup_count].conf = str; + setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340; + setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11; + setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7; + setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1; + setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1; + setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 1; + setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT; + setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0; +#if defined(AHA152X_DEBUG) + setup[setup_count].debug = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT; if (ints[0] > 9) { - printk("aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>" + printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>" "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>[,<DEBUG>]]]]]]]]\n"); #else - if (ints[0] > 8) { - printk("aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>" + if (ints[0] > 8) { /*}*/ + printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>" "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n"); #endif - } else + return; + } else { setup_count++; + return; + } } -#endif /* PCMCIA */ +#endif -#ifndef MODULE -static int __init do_aha152x_setup (char * str) +#if !defined(MODULE) +static int __init do_setup(char *str) { - if (setup_count > 2) { - printk(KERN_ERR"aha152x: you can only configure up to two -controllers\n"); - return 0; - } - setup[setup_count].conf = str; - get_option(&str,&setup[setup_count].io_port); - get_option(&str,&setup[setup_count].irq); - get_option(&str,&setup[setup_count].scsiid); - get_option(&str,&setup[setup_count].reconnect); - - setup_count++; - return 1; +#if defined(AHA152X_DEBUG) + int ints[11]; +#else + int ints[10]; +#endif + int count=setup_count; + + get_options(str, sizeof(ints)/sizeof(int), ints); + aha152x_setup(str,ints); + + return count<setup_count; } -__setup("aha152x=",do_aha152x_setup); +__setup("aha152x=", do_setup); #endif - + /* * Test, if port_base is valid. + * */ static int aha152x_porttest(int io_port) { @@ -777,24 +851,48 @@ static int aha152x_porttest(int io_port) SETPORT(io_port + O_STACK, i); SETPORT(io_port + O_DMACNTRL1, 0); /* reset stack pointer */ - for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++); + for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++) + ; return (i == 16); } -int aha152x_checksetup(struct aha152x_setup *setup) +static int tc1550_porttest(int io_port) { int i; -#ifndef PCMCIA - for (i = 0; i < PORT_COUNT && (setup->io_port != ports[i]); i++); + if (check_region(io_port, IO_RANGE)) + return 0; + + SETPORT(io_port + O_TC_DMACNTRL1, 0); /* reset stack pointer */ + for (i = 0; i < 16; i++) + SETPORT(io_port + O_STACK, i); + + SETPORT(io_port + O_TC_DMACNTRL1, 0); /* reset stack pointer */ + for (i = 0; i < 16 && GETPORT(io_port + O_TC_STACK) == i; i++) + ; + + return (i == 16); +} + +static int checksetup(struct aha152x_setup *setup) +{ + int i; + +#if !defined(PCMCIA) + for (i = 0; i < PORT_COUNT && (setup->io_port != ports[i]); i++) + ; if (i == PORT_COUNT) return 0; #endif - if (!aha152x_porttest(setup->io_port)) - return 0; + if(aha152x_porttest(setup->io_port)) { + setup->tc1550=0; + } else if(tc1550_porttest(setup->io_port)) { + setup->tc1550=1; + } else + return 0; if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX)) return 0; @@ -818,12 +916,12 @@ int aha152x_checksetup(struct aha152x_setup *setup) return 1; } -void aha152x_swintr(int irqno, void *dev_id, struct pt_regs *regs) +static void swintr(int irqno, void *dev_id, struct pt_regs *regs) { struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN]; if (!shpnt) - panic("aha152x: catched software interrupt for unknown controller.\n"); + printk(KERN_ERR "aha152x%d: catched software interrupt for unknown controller.\n", HOSTNO); HOSTDATA(shpnt)->swint++; } @@ -835,29 +933,28 @@ int aha152x_detect(Scsi_Host_Template * tpnt) #if defined(AUTOCONF) aha152x_config conf; #endif - - tpnt->proc_name = "aha152x"; + tpnt->proc_name = "aha152x"; for (i = 0; i < IRQS; i++) aha152x_host[i] = (struct Scsi_Host *) NULL; if (setup_count) { - printk("aha152x: processing commandline: "); + printk(KERN_INFO "aha152x: processing commandline: "); for (i = 0; i < setup_count; i++) - if (!aha152x_checksetup(&setup[i])) { - printk("\naha152x: %s\n", setup[i].conf); - printk("aha152x: invalid line (controller=%d)\n", i + 1); + if (!checksetup(&setup[i])) { + printk(KERN_ERR "\naha152x: %s\n", setup[i].conf); + printk(KERN_ERR "aha152x: invalid line\n"); } printk("ok\n"); } -#ifdef SETUP0 +#if defined(SETUP0) if (setup_count < 2) { struct aha152x_setup override = SETUP0; if (setup_count == 0 || (override.io_port != setup[0].io_port)) - if (!aha152x_checksetup(&override)) { - printk("\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", + if (!checksetup(&override)) { + printk(KERN_ERR "\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", override.io_port, override.irq, override.scsiid, @@ -871,13 +968,13 @@ int aha152x_detect(Scsi_Host_Template * tpnt) } #endif -#ifdef SETUP1 +#if defined(SETUP1) if (setup_count < 2) { struct aha152x_setup override = SETUP1; if (setup_count == 0 || (override.io_port != setup[0].io_port)) - if (!aha152x_checksetup(&override)) { - printk("\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", + if (!checksetup(&override)) { + printk(KERN_ERR "\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", override.io_port, override.irq, override.scsiid, @@ -892,23 +989,39 @@ int aha152x_detect(Scsi_Host_Template * tpnt) #endif #if defined(MODULE) - if (setup_count < 2 && aha152x[0] != 0) { - setup[setup_count].conf = ""; - setup[setup_count].io_port = aha152x[0]; - setup[setup_count].irq = aha152x[1]; - setup[setup_count].scsiid = aha152x[2]; - setup[setup_count].reconnect = aha152x[3]; - setup[setup_count].parity = aha152x[4]; - setup[setup_count].synchronous = aha152x[5]; - setup[setup_count].delay = aha152x[6]; - setup[setup_count].ext_trans = aha152x[7]; -#ifdef DEBUG_AHA152X - setup[setup_count].debug = aha152x[8]; + if (setup_count<2 && (aha152x[0]!=0 || io[0]!=0 || irq[0]!=0)) { + if(aha152x[0]!=0) { + setup[setup_count].conf = ""; + setup[setup_count].io_port = aha152x[0]; + setup[setup_count].irq = aha152x[1]; + setup[setup_count].scsiid = aha152x[2]; + setup[setup_count].reconnect = aha152x[3]; + setup[setup_count].parity = aha152x[4]; + setup[setup_count].synchronous = aha152x[5]; + setup[setup_count].delay = aha152x[6]; + setup[setup_count].ext_trans = aha152x[7]; +#if defined(AHA152X_DEBUG) + setup[setup_count].debug = aha152x[8]; +#endif + } else if(io[0]!=0 || irq[0]!=0) { + if(io[0]!=0) setup[setup_count].io_port = io[0]; + if(irq[0]!=0) setup[setup_count].irq = irq[0]; + + setup[setup_count].scsiid = scsiid[0]; + setup[setup_count].reconnect = reconnect[0]; + setup[setup_count].parity = parity[0]; + setup[setup_count].synchronous = sync[0]; + setup[setup_count].delay = delay[0]; + setup[setup_count].ext_trans = exttrans[0]; +#if defined(AHA152X_DEBUG) + setup[setup_count].debug = debug[0]; #endif - if (aha152x_checksetup(&setup[setup_count])) + } + + if (checksetup(&setup[setup_count])) setup_count++; else - printk("\naha152x: invalid module argument aha152x=0x%x,%d,%d,%d,%d,%d,%d,%d\n", + 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", setup[setup_count].io_port, setup[setup_count].irq, setup[setup_count].scsiid, @@ -918,23 +1031,39 @@ int aha152x_detect(Scsi_Host_Template * tpnt) setup[setup_count].delay, setup[setup_count].ext_trans); } - if (setup_count < 2 && aha152x1[0] != 0) { - setup[setup_count].conf = ""; - setup[setup_count].io_port = aha152x1[0]; - setup[setup_count].irq = aha152x1[1]; - setup[setup_count].scsiid = aha152x1[2]; - setup[setup_count].reconnect = aha152x1[3]; - setup[setup_count].parity = aha152x1[4]; - setup[setup_count].synchronous = aha152x1[5]; - setup[setup_count].delay = aha152x1[6]; - setup[setup_count].ext_trans = aha152x1[7]; -#ifdef DEBUG_AHA152X - setup[setup_count].debug = aha152x1[8]; + + if (setup_count < 2 && (aha152x1[0]!=0 || io[1]!=0 || irq[1]!=0)) { + if(aha152x1[0]!=0) { + setup[setup_count].conf = ""; + setup[setup_count].io_port = aha152x1[0]; + setup[setup_count].irq = aha152x1[1]; + setup[setup_count].scsiid = aha152x1[2]; + setup[setup_count].reconnect = aha152x1[3]; + setup[setup_count].parity = aha152x1[4]; + setup[setup_count].synchronous = aha152x1[5]; + setup[setup_count].delay = aha152x1[6]; + setup[setup_count].ext_trans = aha152x1[7]; +#if defined(AHA152X_DEBUG) + setup[setup_count].debug = aha152x1[8]; +#endif + } else if(io[1]!=0 || irq[1]!=0) { + if(io[1]!=0) setup[setup_count].io_port = io[1]; + if(irq[1]!=0) setup[setup_count].irq = irq[1]; + + setup[setup_count].scsiid = scsiid[1]; + setup[setup_count].reconnect = reconnect[1]; + setup[setup_count].parity = parity[1]; + setup[setup_count].synchronous = sync[1]; + setup[setup_count].delay = delay[1]; + setup[setup_count].ext_trans = exttrans[1]; +#if defined(AHA152X_DEBUG) + setup[setup_count].debug = debug[1]; #endif - if (aha152x_checksetup(&setup[setup_count])) + } + if (checksetup(&setup[setup_count])) setup_count++; else - printk("\naha152x: invalid module argument aha152x1=0x%x,%d,%d,%d,%d,%d,%d,%d\n", + 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", setup[setup_count].io_port, setup[setup_count].irq, setup[setup_count].scsiid, @@ -953,14 +1082,14 @@ int aha152x_detect(Scsi_Host_Template * tpnt) for (i = 0; i < ADDRESS_COUNT && !ok; i++) for (j = 0; (j < SIGNATURE_COUNT) && !ok; j++) ok = isa_check_signature(addresses[i] + signatures[j].sig_offset, - signatures[j].signature, signatures[j].sig_length); + signatures[j].signature, signatures[j].sig_length); if (!ok && setup_count == 0) return 0; - printk("aha152x: BIOS test: passed, "); + printk(KERN_INFO "aha152x: BIOS test: passed, "); #else - printk("aha152x: "); + printk(KERN_INFO "aha152x: "); #endif /* !SKIP_BIOSTEST */ ok = 0; @@ -971,6 +1100,26 @@ int aha152x_detect(Scsi_Host_Template * tpnt) if (aha152x_porttest(ports[i])) { ok++; setup[setup_count].io_port = ports[i]; + setup[setup_count].tc1550 = 0; + + conf.cf_port = + (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB); + + setup[setup_count].irq = IRQ_MIN + conf.cf_irq; + setup[setup_count].scsiid = conf.cf_id; + setup[setup_count].reconnect = conf.cf_tardisc; + setup[setup_count].parity = !conf.cf_parity; + setup[setup_count].synchronous = conf.cf_syncneg; + setup[setup_count].delay = DELAY_DEFAULT; + setup[setup_count].ext_trans = 0; +#if defined(AHA152X_DEBUG) + setup[setup_count].debug = DEBUG_DEFAULT; +#endif + setup_count++; + } else if (tc1550_porttest(ports[i])) { + ok++; + setup[setup_count].io_port = ports[i]; + setup[setup_count].tc1550 = 1; conf.cf_port = (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB); @@ -979,10 +1128,10 @@ int aha152x_detect(Scsi_Host_Template * tpnt) setup[setup_count].scsiid = conf.cf_id; setup[setup_count].reconnect = conf.cf_tardisc; setup[setup_count].parity = !conf.cf_parity; - setup[setup_count].synchronous = 0 /* FIXME: conf.cf_syncneg */ ; + setup[setup_count].synchronous = conf.cf_syncneg; setup[setup_count].delay = DELAY_DEFAULT; setup[setup_count].ext_trans = 0; -#ifdef DEBUG_AHA152X +#if defined(AHA152X_DEBUG) setup[setup_count].debug = DEBUG_DEFAULT; #endif setup_count++; @@ -996,40 +1145,75 @@ int aha152x_detect(Scsi_Host_Template * tpnt) printk("detected %d controller(s)\n", setup_count); - for (i = 0; i < setup_count; i++) { + for (i=0; i<setup_count; i++) { struct Scsi_Host *shpnt; - unsigned long int the_time; - shpnt = aha152x_host[setup[i].irq - IRQ_MIN] = + aha152x_host[setup[i].irq - IRQ_MIN] = shpnt = scsi_register(tpnt, sizeof(struct aha152x_hostdata)); + + if(!shpnt) { + printk(KERN_ERR "aha152x: scsi_register failed\n"); + continue; + } + registered_count++; - shpnt->io_port = setup[i].io_port; + shpnt->io_port = setup[i].io_port; shpnt->n_io_port = IO_RANGE; - shpnt->irq = setup[i].irq; - - ISSUE_SC = (Scsi_Cmnd *) NULL; - CURRENT_SC = (Scsi_Cmnd *) NULL; - DISCONNECTED_SC = (Scsi_Cmnd *) NULL; - - HOSTDATA(shpnt)->reconnect = setup[i].reconnect; - HOSTDATA(shpnt)->parity = setup[i].parity; - HOSTDATA(shpnt)->synchronous = setup[i].synchronous; - HOSTDATA(shpnt)->delay = setup[i].delay; - HOSTDATA(shpnt)->ext_trans = setup[i].ext_trans; -#ifdef DEBUG_AHA152X + shpnt->irq = setup[i].irq; + + if(!setup[i].tc1550) { + HOSTIOPORT0 = setup[i].io_port; + HOSTIOPORT1 = setup[i].io_port; + } else { + HOSTIOPORT0 = setup[i].io_port+0x10; + HOSTIOPORT1 = setup[i].io_port-0x10; + } + + ISSUE_SC = 0; + CURRENT_SC = 0; + DONE_SC = 0; + DISCONNECTED_SC = 0; + + QLOCK = SPIN_LOCK_UNLOCKED; + + STATE = 0; + PREVSTATE = 0; + LASTSTATE = 0; + + MSGILEN = 0; + MSGOLEN = 0; + + RECONNECT = setup[i].reconnect; + SYNCHRONOUS = setup[i].synchronous; + PARITY = setup[i].parity; + DELAY = setup[i].delay; + EXT_TRANS = setup[i].ext_trans; +#if defined(AHA152X_DEBUG) HOSTDATA(shpnt)->debug = setup[i].debug; #endif - - HOSTDATA(shpnt)->aborting = 0; - HOSTDATA(shpnt)->abortion_complete = 0; - HOSTDATA(shpnt)->abort_result = 0; + HOSTDATA(shpnt)->in_intr = 0; HOSTDATA(shpnt)->commands = 0; - HOSTDATA(shpnt)->message_len = 0; +#if defined(AHA152X_STAT) + HOSTDATA(shpnt)->total_commands=0; + HOSTDATA(shpnt)->disconnections=0; + HOSTDATA(shpnt)->busfree_without_any_action=0; + HOSTDATA(shpnt)->busfree_without_old_command=0; + HOSTDATA(shpnt)->busfree_without_new_command=0; + HOSTDATA(shpnt)->busfree_without_done_command=0; + HOSTDATA(shpnt)->busfree_with_check_condition=0; + for (j = idle; j<maxstate; j++) { + HOSTDATA(shpnt)->count[j]=0; + HOSTDATA(shpnt)->count_trans[j]=0; + HOSTDATA(shpnt)->time[j]=0; + } +#endif - for (j = 0; j < 8; j++) + for (j = 0; j < 8; j++) { HOSTDATA(shpnt)->syncrate[j] = 0; + HOSTDATA(shpnt)->syncneg[j] = 0; + } SETPORT(SCSIID, setup[i].scsiid << 4); shpnt->this_id = setup[i].scsiid; @@ -1037,59 +1221,73 @@ int aha152x_detect(Scsi_Host_Template * tpnt) if (setup[i].reconnect) shpnt->can_queue = AHA152X_MAXQUEUE; - /* RESET OUT */ - SETBITS(SCSISEQ, SCSIRSTO); - do_pause(30); - CLRBITS(SCSISEQ, SCSIRSTO); - do_pause(setup[i].delay); - - aha152x_reset_ports(shpnt); +#if 0 + if(!shpnt->hostt->use_new_eh_code) { +#endif + /* RESET OUT */ + printk("aha152x: resetting bus...\n"); + SETPORT(SCSISEQ, SCSIRSTO); + mdelay(256); + SETPORT(SCSISEQ, 0); + mdelay(DELAY); +#if 0 + } +#endif - printk("aha152x%d: vital data: PORTBASE=0x%03lx, IRQ=%d, SCSI ID=%d," - " reconnect=%s, parity=%s, synchronous=%s, delay=%d, extended translation=%s\n", - i, - shpnt->io_port, + reset_ports(shpnt); + + printk(KERN_INFO + "aha152x%d%s: " + "vital data: rev=%x, " + "io=0x%03lx (0x%03lx/0x%03lx), " + "irq=%d, " + "scsiid=%d, " + "reconnect=%s, " + "parity=%s, " + "synchronous=%s, " + "delay=%d, " + "extended translation=%s\n", + HOSTNO, setup[i].tc1550 ? " (tc1550 mode)" : "", + GETPORT(REV) & 0x7, + shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1, shpnt->irq, shpnt->this_id, - HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled", - HOSTDATA(shpnt)->parity ? "enabled" : "disabled", - HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled", - HOSTDATA(shpnt)->delay, - HOSTDATA(shpnt)->ext_trans ? "enabled" : "disabled"); + RECONNECT ? "enabled" : "disabled", + PARITY ? "enabled" : "disabled", + SYNCHRONOUS ? "enabled" : "disabled", + DELAY, + EXT_TRANS ? "enabled" : "disabled"); - request_region(shpnt->io_port, IO_RANGE, "aha152x"); /* Register */ + request_region(shpnt->io_port, IO_RANGE, "aha152x"); /* not expecting any interrupts */ SETPORT(SIMODE0, 0); SETPORT(SIMODE1, 0); - SETBITS(DMACNTRL0, INTEN); - - ok = request_irq(shpnt->irq, aha152x_swintr, SA_INTERRUPT, "aha152x", shpnt); + ok = request_irq(shpnt->irq, swintr, SA_INTERRUPT, "aha152x", shpnt); if (ok < 0) { - if (ok == -EINVAL) - printk("aha152x%d: bad IRQ %d.\n", i, shpnt->irq); - else if (ok == -EBUSY) - printk("aha152x%d: IRQ %d already in use.\n", i, shpnt->irq); + if (ok==-EINVAL) + printk(KERN_ERR "aha152x%d: bad IRQ %d.\n", HOSTNO, shpnt->irq); + else if(ok==-EBUSY) + printk(KERN_ERR "aha152x%d: IRQ %d already in use.\n", HOSTNO, shpnt->irq); else - printk("\naha152x%d: Unexpected error code %d on requesting IRQ %d.\n", i, ok, shpnt->irq); - printk("aha152x: driver needs an IRQ.\n"); + printk(KERN_ERR "aha152x%d: Unexpected error code %d on requesting IRQ %d.\n", HOSTNO, ok, shpnt->irq); + + printk(KERN_ERR "aha152x%d: driver needs an IRQ.\n", HOSTNO); scsi_unregister(shpnt); registered_count--; release_region(shpnt->io_port, IO_RANGE); - shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0; + aha152x_host[shpnt->irq - IRQ_MIN] = shpnt = 0; continue; } HOSTDATA(shpnt)->swint = 0; - printk("aha152x: trying software interrupt, "); - SETBITS(DMACNTRL0, SWINT); - - the_time = jiffies + 100; - while (!HOSTDATA(shpnt)->swint && time_before(jiffies, the_time)) - barrier(); - + printk(KERN_INFO "aha152x%d: trying software interrupt, ", HOSTNO); + SETPORT(DMACNTRL0, SWINT|INTEN); + spin_unlock_irq(&io_request_lock); + mdelay(1000); + spin_lock_irq(&io_request_lock); free_irq(shpnt->irq, shpnt); if (!HOSTDATA(shpnt)->swint) { @@ -1099,7 +1297,7 @@ int aha152x_detect(Scsi_Host_Template * tpnt) printk("failed.\n"); } - printk("aha152x: IRQ %d possibly wrong. Please verify.\n", shpnt->irq); + printk(KERN_ERR "aha152x%d: IRQ %d possibly wrong. Please verify.\n", HOSTNO, shpnt->irq); scsi_unregister(shpnt); registered_count--; @@ -1109,18 +1307,24 @@ int aha152x_detect(Scsi_Host_Template * tpnt) } printk("ok.\n"); - CLRBITS(DMACNTRL0, SWINT); + SETPORT(DMACNTRL0, INTEN); /* clear interrupts */ SETPORT(SSTAT0, 0x7f); SETPORT(SSTAT1, 0xef); - if (request_irq(shpnt->irq, aha152x_intr, SA_INTERRUPT, "aha152x", shpnt) < 0) { - printk("aha152x: failed to reassign interrupt.\n"); + if (request_irq(shpnt->irq, intr, SA_INTERRUPT, "aha152x", shpnt) < 0) { + printk(KERN_ERR "aha152x%d: failed to reassign interrupt.\n", HOSTNO); + + scsi_unregister(shpnt); + registered_count--; + release_region(shpnt->io_port, IO_RANGE); + shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0; + continue; } } - return (registered_count > 0); + return registered_count>0; } @@ -1128,41 +1332,89 @@ int aha152x_release(struct Scsi_Host *shpnt) { if (shpnt->irq) free_irq(shpnt->irq, shpnt); + if (shpnt->io_port) release_region(shpnt->io_port, IO_RANGE); + scsi_unregister(shpnt); + return 0; } +/* + * setup controller to generate interrupts depending + * on current state (lock has to be aquired) + * + */ +static int setup_expected_interrupts(struct Scsi_Host *shpnt) +{ + ASSERT_LOCK(&QLOCK,1); + + if(CURRENT_SC) { + CURRENT_SC->SCp.phase |= 1 << 16; + + if(CURRENT_SC->SCp.phase & selecting) { + DPRINTK(debug_intr, DEBUG_LEAD "expecting: (seldo) (seltimo) (seldi)\n", CMDINFO(CURRENT_SC)); + SETPORT(SSTAT1, SELTO); + SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); + SETPORT(SIMODE1, ENSELTIMO); + } else { + DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (busfree) %s\n", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.phase & spiordy ? "(spiordy)" : ""); + SETPORT(SIMODE0, (CURRENT_SC->SCp.phase & spiordy) ? ENSPIORDY : 0); + SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); + } + } else if(STATE==seldi) { + DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (identify)\n", CMDINFO(CURRENT_SC)); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); + } else { + DPRINTK(debug_intr, DEBUG_LEAD "expecting: %s %s\n", + CMDINFO(CURRENT_SC), + DISCONNECTED_SC ? "(reselection)" : "", + ISSUE_SC ? "(busfree)" : ""); + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0)); + } + + if(!HOSTDATA(shpnt)->in_intr) + SETBITS(DMACNTRL0, INTEN); + + return TESTHI(DMASTAT, INTSTAT); +} + + /* * Queue a command and setup interrupts for a free bus. */ -int aha152x_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) +int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int phase, Scsi_Cmnd *done_SC, void (*done)(Scsi_Cmnd *)) { struct Scsi_Host *shpnt = SCpnt->host; unsigned long flags; -#if defined(DEBUG_RACE) - enter_driver("queue"); -#else -#if defined(DEBUG_QUEUE) - if (HOSTDATA(shpnt)->debug & debug_queue) - printk("aha152x: queue(), "); -#endif -#endif - -#if defined(DEBUG_QUEUE) +#if defined(AHA152X_DEBUG) if (HOSTDATA(shpnt)->debug & debug_queue) { - printk("SCpnt (target = %d lun = %d cmnd = ", - SCpnt->target, SCpnt->lun); + printk(INFO_LEAD "queue: cmd_len=%d pieces=%d size=%u cmnd=", + CMDINFO(SCpnt), SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen); print_command(SCpnt->cmnd); - printk(", cmd_len=%d, pieces = %d size = %u), ", - SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen); - disp_ports(shpnt); } #endif - SCpnt->scsi_done = done; + SCpnt->scsi_done = done; + SCpnt->resid = SCpnt->request_bufflen; + SCpnt->SCp.phase = not_issued | phase; + SCpnt->SCp.Status = CHECK_CONDITION; + SCpnt->SCp.Message = 0; + SCpnt->SCp.have_data_in = 0; + SCpnt->SCp.sent_command = 0; + SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC); + if(!SCpnt->host_scribble) { + printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt)); + return FAILED; + } + + SCNEXT(SCpnt) = 0; + SCDONE(SCpnt) = done_SC; + SCSEM(SCpnt) = sem; /* setup scratch area SCp.ptr : buffer pointer @@ -1170,193 +1422,265 @@ int aha152x_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) SCp.buffer : next buffer SCp.buffers_residual : left buffers in list SCp.phase : current state of the command */ - SCpnt->SCp.phase = not_issued; if (SCpnt->use_sg) { - SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; - SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; - SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; + SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; } else { - SCpnt->SCp.ptr = (char *) SCpnt->request_buffer; - SCpnt->SCp.this_residual = SCpnt->request_bufflen; - SCpnt->SCp.buffer = NULL; + SCpnt->SCp.ptr = (char *) SCpnt->request_buffer; + SCpnt->SCp.this_residual = SCpnt->request_bufflen; + SCpnt->SCp.buffer = NULL; SCpnt->SCp.buffers_residual = 0; } - SCpnt->SCp.Status = CHECK_CONDITION; - SCpnt->SCp.Message = 0; - SCpnt->SCp.have_data_in = 0; - SCpnt->SCp.sent_command = 0; + DO_LOCK(flags); + +#if defined(AHA152X_STAT) + HOSTDATA(shpnt)->total_commands++; +#endif /* Turn led on, when this is the first command. */ - save_flags(flags); - cli(); HOSTDATA(shpnt)->commands++; - if (HOSTDATA(shpnt)->commands == 1) + if (HOSTDATA(shpnt)->commands==1) SETPORT(PORTA, 1); -#if defined(DEBUG_QUEUES) - if (HOSTDATA(shpnt)->debug & debug_queues) - printk("i+ (%d), ", HOSTDATA(shpnt)->commands); -#endif append_SC(&ISSUE_SC, SCpnt); - /* Enable bus free interrupt, when we aren't currently on the bus */ - if (!CURRENT_SC) { - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - } - restore_flags(flags); + if(!HOSTDATA(shpnt)->in_intr) + setup_expected_interrupts(shpnt); -#if defined(DEBUG_RACE) - leave_driver("queue"); -#endif + DO_UNLOCK(flags); return 0; } +int aha152x_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ + if(*SCpnt->cmnd == REQUEST_SENSE) { + SCpnt->result = 0; + done(SCpnt); + + return SUCCESS; + } + + return aha152x_internal_queue(SCpnt, 0, 0, 0, done); +} + + /* - * We only support commands in interrupt-driven fashion + * run a command + * */ +void internal_done(Scsi_Cmnd *SCpnt) +{ +#if 0 + struct Scsi_Host *shpnt = SCpnt->host; + + DPRINTK(debug_eh, INFO_LEAD "internal_done called\n", CMDINFO(SCpnt)); +#endif + if(SCSEM(SCpnt)) + up(SCSEM(SCpnt)); +} + int aha152x_command(Scsi_Cmnd * SCpnt) { - printk("aha152x: interrupt driven driver; use aha152x_queue()\n"); - return -1; + DECLARE_MUTEX_LOCKED(sem); + + aha152x_internal_queue(SCpnt, &sem, 0, 0, internal_done); + down(&sem); + + return SUCCESS; } /* - * Abort a queued command - * (commands that are on the bus can't be aborted easily) + * Abort a command + * */ -int aha152x_abort(Scsi_Cmnd * SCpnt) +int aha152x_abort(Scsi_Cmnd *SCpnt) { struct Scsi_Host *shpnt = SCpnt->host; + Scsi_Cmnd *ptr; unsigned long flags; - Scsi_Cmnd *ptr, *prev; - save_flags(flags); - cli(); + if(!shpnt) { + printk(ERR_LEAD "abort(%p): no host structure\n", CMDINFO(SCpnt), SCpnt); + return FAILED; + } -#if defined(DEBUG_ABORT) - if (HOSTDATA(shpnt)->debug & debug_abort) { - printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt); +#if defined(AHA152X_DEBUG) + if(HOSTDATA(shpnt)->debug & debug_eh) { + printk(DEBUG_LEAD "abort(%p)", CMDINFO(SCpnt), SCpnt); show_queues(shpnt); + mdelay(1000); } #endif - /* look for command in issue queue */ - for (ptr = ISSUE_SC, prev = NULL; - ptr && ptr != SCpnt; - prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble); + DO_LOCK(flags); - if (ptr) { - /* dequeue */ - if (prev) - prev->host_scribble = ptr->host_scribble; - else - ISSUE_SC = (Scsi_Cmnd *) ptr->host_scribble; + ptr=remove_SC(&ISSUE_SC, SCpnt); + + if(ptr) { + DPRINTK(debug_eh, DEBUG_LEAD "not yet issued - SUCCESS\n", CMDINFO(SCpnt)); HOSTDATA(shpnt)->commands--; + if (!HOSTDATA(shpnt)->commands) + SETPORT(PORTA, 0); + DO_UNLOCK(flags); - restore_flags(flags); + kfree(SCpnt->host_scribble); + SCpnt->host_scribble=0; - ptr->host_scribble = NULL; - ptr->result = DID_ABORT << 16; - spin_lock_irqsave(&io_request_lock, flags); - ptr->scsi_done(ptr); - spin_unlock_irqrestore(&io_request_lock, flags); + return SUCCESS; + } - return SCSI_ABORT_SUCCESS; - } - /* if the bus is busy or a command is currently processed, - we can't do anything more */ - if (TESTLO(SSTAT1, BUSFREE) || (CURRENT_SC && CURRENT_SC != SCpnt)) { - /* fail abortion, if bus is busy */ + DO_UNLOCK(flags); - if (!CURRENT_SC) - printk("bus busy w/o current command, "); + /* + * FIXME: + * for current command: queue ABORT for message out and raise ATN + * for disconnected command: pseudo SC with ABORT message or ABORT on reselection? + * + */ - restore_flags(flags); + printk(ERR_LEAD "cannot abort running or disconnected command\n", CMDINFO(SCpnt)); - return SCSI_ABORT_BUSY; - } - /* bus is free */ + return FAILED; +} - if (CURRENT_SC) { - HOSTDATA(shpnt)->commands--; +static void timer_expired(unsigned long p) +{ + struct semaphore *sem = (void *)p; - /* target entered bus free before COMMAND COMPLETE, nothing to abort */ - restore_flags(flags); - spin_lock_irqsave(&io_request_lock, flags); - CURRENT_SC->result = DID_ERROR << 16; - CURRENT_SC->scsi_done(CURRENT_SC); - CURRENT_SC = (Scsi_Cmnd *) NULL; - spin_unlock_irqrestore(&io_request_lock, flags); + printk(KERN_INFO "aha152x: timer expired\n"); + up(sem); +} - return SCSI_ABORT_SUCCESS; - } - /* look for command in disconnected queue */ - for (ptr = DISCONNECTED_SC, prev = NULL; - ptr && ptr != SCpnt; - prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble); +/* + * Reset a device + * + * FIXME: never seen this live. might lockup... + * + */ +int aha152x_device_reset(Scsi_Cmnd * SCpnt) +{ + struct Scsi_Host *shpnt = SCpnt->host; + DECLARE_MUTEX_LOCKED(sem); + struct timer_list timer; + Scsi_Cmnd cmnd; - if (!ptr) { - /* command wasn't found */ - printk("command not found\n"); - restore_flags(flags); +#if defined(AHA152X_DEBUG) + if(HOSTDATA(shpnt)->debug & debug_eh) { + printk(INFO_LEAD "aha152x_device_reset(%p)", CMDINFO(SCpnt), SCpnt); + show_queues(shpnt); + mdelay(1000); + } +#endif - return SCSI_ABORT_NOT_RUNNING; + if(CURRENT_SC==SCpnt) { + printk(ERR_LEAD "cannot reset current device\n", CMDINFO(SCpnt)); + return FAILED; } - if (!HOSTDATA(shpnt)->aborting) { - /* dequeue */ - if (prev) - prev->host_scribble = ptr->host_scribble; - else - DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble; - HOSTDATA(shpnt)->commands--; + cmnd.cmd_len = 0; + cmnd.host = SCpnt->host; + cmnd.target = SCpnt->target; + cmnd.lun = SCpnt->lun; + cmnd.use_sg = 0; + cmnd.request_buffer = 0; + cmnd.request_bufflen = 0; - /* set command current and initiate selection, - let the interrupt routine take care of the abortion */ - CURRENT_SC = ptr; - ptr->SCp.phase = in_selection | aborted; - SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); + init_timer(&timer); + timer.data = (unsigned long) &sem; + timer.expires = jiffies + 10000; /* 10s */ + timer.function = (void (*)(unsigned long)) timer_expired; + add_timer(&timer); - ADDMSG(ABORT); + aha152x_internal_queue(&cmnd, &sem, resetting, 0, internal_done); - /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ - SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); - SETPORT(SIMODE1, ENSELTIMO); + down(&sem); - /* Enable SELECTION OUT sequence */ - SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); + del_timer(&timer); - SETBITS(DMACNTRL0, INTEN); - HOSTDATA(shpnt)->abort_result = SCSI_ABORT_SUCCESS; - HOSTDATA(shpnt)->aborting++; - HOSTDATA(shpnt)->abortion_complete = 0; + if(cmnd.SCp.phase & resetted) { + return SUCCESS; + } else { + return FAILED; + } +} + +void free_hard_reset_SCs(struct Scsi_Host *shpnt, Scsi_Cmnd **SCs) +{ + Scsi_Cmnd *ptr; + unsigned long flags; - restore_flags(flags); + DO_LOCK(flags); - /* sleep until the abortion is complete */ - while (!HOSTDATA(shpnt)->abortion_complete) - barrier(); - HOSTDATA(shpnt)->aborting = 0; + ptr=*SCs; + while(ptr) { + Scsi_Cmnd *next = SCNEXT(ptr); - return HOSTDATA(shpnt)->abort_result; - } else { - /* we're already aborting a command */ - restore_flags(flags); + if (!ptr->device->soft_reset) { + DPRINTK(debug_eh, DEBUG_LEAD "disconnected command %p removed\n", CMDINFO(ptr), ptr); + remove_SC(SCs, ptr); + HOSTDATA(shpnt)->commands--; + kfree(ptr->host_scribble); + ptr->host_scribble=0; + } - return SCSI_ABORT_BUSY; + ptr = next; } + + DO_UNLOCK(flags); } /* + * Reset the bus + * + */ +int aha152x_bus_reset(Scsi_Cmnd *SCpnt) +{ + struct Scsi_Host *shpnt = SCpnt->host; + unsigned long flags; + +#if defined(AHA152X_DEBUG) + if(HOSTDATA(shpnt)->debug & debug_eh) { + printk(DEBUG_LEAD "aha152x_bus_reset(%p)", CMDINFO(SCpnt), SCpnt); + show_queues(shpnt); + mdelay(1000); + } +#endif + + free_hard_reset_SCs(shpnt, &ISSUE_SC); + free_hard_reset_SCs(shpnt, &DISCONNECTED_SC); + + DPRINTK(debug_eh, DEBUG_LEAD "resetting bus\n", CMDINFO(SCpnt)); + + SETPORT(SCSISEQ, SCSIRSTO); + mdelay(256); + SETPORT(SCSISEQ, 0); + mdelay(DELAY); + + DPRINTK(debug_eh, DEBUG_LEAD "bus reset returns\n", CMDINFO(SCpnt)); + + DO_LOCK(flags); + setup_expected_interrupts(shpnt); + if(HOSTDATA(shpnt)->commands==0) + SETPORT(PORTA, 0); + DO_UNLOCK(flags); + + return SUCCESS; +} + + +/* * Restore default values to the AIC-6260 registers and reset the fifos + * */ -static void aha152x_reset_ports(struct Scsi_Host *shpnt) +static void reset_ports(struct Scsi_Host *shpnt) { + unsigned long flags; + /* disable interrupts */ SETPORT(DMACNTRL0, RSTFIFO); @@ -1364,7 +1688,7 @@ static void aha152x_reset_ports(struct Scsi_Host *shpnt) SETPORT(SXFRCTL1, 0); SETPORT(SCSISIG, 0); - SETPORT(SCSIRATE, 0); + SETRATE(0); /* clear all interrupt conditions */ SETPORT(SSTAT0, 0x7f); @@ -1377,106 +1701,41 @@ static void aha152x_reset_ports(struct Scsi_Host *shpnt) SETPORT(BRSTCNTRL, 0xf1); - /* clear SCSI fifo and transfer count */ - SETPORT(SXFRCTL0, CH1 | CLRCH1 | CLRSTCNT); + /* clear SCSI fifos and transfer count */ + SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); SETPORT(SXFRCTL0, CH1); - /* enable interrupts */ - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + DO_LOCK(flags); + setup_expected_interrupts(shpnt); + DO_UNLOCK(flags); } /* - * Reset registers, reset a hanging bus and - * kill active and disconnected commands for target w/o soft reset + * Reset the host (bus and controller) + * */ -int aha152x_reset(Scsi_Cmnd * SCpnt, unsigned int unused) +int aha152x_host_reset(Scsi_Cmnd * SCpnt) { struct Scsi_Host *shpnt = SCpnt->host; - unsigned long flags; - Scsi_Cmnd *ptr, *prev, *next; - - aha152x_reset_ports(shpnt); - - /* Reset, if bus hangs */ - if (TESTLO(SSTAT1, BUSFREE)) { - CLRBITS(DMACNTRL0, INTEN); - -#if defined(DEBUG_RESET) - if (HOSTDATA(shpnt)->debug & debug_reset) { - printk("aha152x: reset(), bus not free: SCSI RESET OUT\n"); - show_queues(shpnt); - } -#endif - ptr = CURRENT_SC; - if (ptr && !ptr->device->soft_reset) { - ptr->host_scribble = NULL; - ptr->result = DID_RESET << 16; - ptr->scsi_done(CURRENT_SC); - CURRENT_SC = NULL; - } - save_flags(flags); - cli(); - prev = NULL; - ptr = DISCONNECTED_SC; - while (ptr) { - if (!ptr->device->soft_reset) { - if (prev) - prev->host_scribble = ptr->host_scribble; - else - DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble; - - next = (Scsi_Cmnd *) ptr->host_scribble; - - ptr->host_scribble = NULL; - ptr->result = DID_RESET << 16; - spin_lock_irqsave(&io_request_lock, flags); - ptr->scsi_done(ptr); - spin_unlock_irqrestore(&io_request_lock, flags); - - ptr = next; - } else { - prev = ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble; - } - } - restore_flags(flags); - -#if defined(DEBUG_RESET) - if (HOSTDATA(shpnt)->debug & debug_reset) { - printk("commands on targets w/ soft-resets:\n"); - show_queues(shpnt); - } -#endif + DPRINTK(debug_eh, DEBUG_LEAD "aha152x_host_reset(%p)\n", CMDINFO(SCpnt), SCpnt); - /* RESET OUT */ - SETPORT(SCSISEQ, SCSIRSTO); - do_pause(30); - SETPORT(SCSISEQ, 0); - do_pause(DELAY); + aha152x_bus_reset(SCpnt); - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + DPRINTK(debug_eh, DEBUG_LEAD "resetting ports\n", CMDINFO(SCpnt)); + reset_ports(SCpnt->host); - SETPORT(DMACNTRL0, INTEN); - } - return SCSI_RESET_SUCCESS; + return SUCCESS; } /* * Return the "logical geometry" + * */ int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array) { struct Scsi_Host *shpnt = disk->device->host; -#if defined(DEBUG_BIOSPARAM) - if (HOSTDATA(shpnt)->debug & debug_biosparam) - printk("aha152x_biosparam: dev=%s, size=%d, ", - kdevname(dev), disk->capacity); -#endif - /* try default translation */ info_array[0] = 64; info_array[1] = 32; @@ -1490,16 +1749,18 @@ int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array) if (scsicam_bios_param(disk, dev, info) < 0 || !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) { if (EXT_TRANS) { - printk("aha152x: unable to verify geometry for disk with >1GB.\n" - " using extended translation.\n"); + printk(KERN_NOTICE + "aha152x: unable to verify geometry for disk with >1GB.\n" + " using extended translation.\n"); info_array[0] = 255; info_array[1] = 63; info_array[2] = disk->capacity / (255 * 63); } else { - printk("aha152x: unable to verify geometry for disk with >1GB.\n" + printk(KERN_NOTICE + "aha152x: unable to verify geometry for disk with >1GB.\n" " Using default translation. Please verify yourself.\n" " Perhaps you need to enable extended translation in the driver.\n" - " See /usr/src/linux/drivers/scsi/aha152x.c for details.\n"); + " See /usr/src/linux/drivers/scsi/README.aha152x for details.\n"); } } else { info_array[0] = info[0]; @@ -1507,1158 +1768,1211 @@ int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array) info_array[2] = info[2]; if (info[0] == 255 && !EXT_TRANS) { - printk("aha152x: current partition table is using extended translation.\n" - " using it also, although it's not explicty enabled.\n"); + printk(KERN_NOTICE + "aha152x: current partition table is using extended translation.\n" + " using it also, although it's not explictly enabled.\n"); } } } -#if defined(DEBUG_BIOSPARAM) - if (HOSTDATA(shpnt)->debug & debug_biosparam) { - printk("bios geometry: head=%d, sec=%d, cyl=%d\n", - info_array[0], info_array[1], info_array[2]); - printk("WARNING: check, if the bios geometry is correct.\n"); - } -#endif return 0; } /* * Internal done function + * */ -void aha152x_done(struct Scsi_Host *shpnt, int error) +static void done(struct Scsi_Host *shpnt, int error) { - unsigned long flags; - Scsi_Cmnd *done_SC; - -#if defined(DEBUG_DONE) - if (HOSTDATA(shpnt)->debug & debug_done) { - printk("\naha152x: done(), "); - disp_ports(shpnt); - } -#endif - if (CURRENT_SC) { -#if defined(DEBUG_DONE) - if (HOSTDATA(shpnt)->debug & debug_done) - printk("done(%x), ", error); -#endif - - save_flags(flags); - cli(); - - done_SC = CURRENT_SC; - CURRENT_SC = NULL; + if(DONE_SC) + printk(ERR_LEAD "there's already a completed command %p - will cause abort\n", CMDINFO(CURRENT_SC), DONE_SC); - /* turn led off, when no commands are in the driver */ - HOSTDATA(shpnt)->commands--; - if (!HOSTDATA(shpnt)->commands) - SETPORT(PORTA, 0); /* turn led off */ - -#if defined(DEBUG_QUEUES) - if (HOSTDATA(shpnt)->debug & debug_queues) - printk("ok (%d), ", HOSTDATA(shpnt)->commands); -#endif - restore_flags(flags); - - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - -#if 0 -/* Why poll for the BUS FREE phase, when we have setup the interrupt!? */ -#if defined(DEBUG_PHASES) - if (HOSTDATA(shpnt)->debug & debug_phases) - printk("BUS FREE loop, "); -#endif - while (TESTLO(SSTAT1, BUSFREE)) - barrier(); -#if defined(DEBUG_PHASES) - if (HOSTDATA(shpnt)->debug & debug_phases) - printk("BUS FREE\n"); -#endif -#endif - - done_SC->result = error; - if (done_SC->scsi_done) { -#if defined(DEBUG_DONE) - if (HOSTDATA(shpnt)->debug & debug_done) - printk("calling scsi_done, "); -#endif - spin_lock_irqsave(&io_request_lock, flags); - done_SC->scsi_done(done_SC); - spin_unlock_irqrestore(&io_request_lock, flags); -#if defined(DEBUG_DONE) - if (HOSTDATA(shpnt)->debug & debug_done) - printk("done returned, "); -#endif - } else - panic("aha152x: current_SC->scsi_done() == NULL"); + DONE_SC = CURRENT_SC; + CURRENT_SC = 0; + DONE_SC->result = error; } else - aha152x_panic(shpnt, "done() called outside of command"); + printk(KERN_ERR "aha152x: done() called outside of command\n"); } - -static void aha152x_complete(struct Scsi_Host *); - static struct tq_struct aha152x_tq; /* - * Run service completions on the card with interrupts enabled. + * Run service completions on the card with interrupts enabled. + * */ - -static void aha152x_run(void) +static void run(void) { int i; for (i = 0; i < IRQS; i++) { struct Scsi_Host *shpnt = aha152x_host[i]; if (shpnt && HOSTDATA(shpnt)->service) { - HOSTDATA(shpnt)->service = 0; - aha152x_complete(shpnt); + HOSTDATA(shpnt)->service=0; + complete(shpnt); } } } /* - * Interrupts handler (main routine of the driver) + * Interrupts handler + * */ -static void aha152x_intr(int irqno, void *dev_id, struct pt_regs *regs) +static void intr(int irqno, void *dev_id, struct pt_regs *regs) { struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN]; -#if defined(DEBUG_RACE) - enter_driver("intr"); -#else -#if defined(DEBUG_INTR) - if (HOSTDATA(shpnt)->debug & debug_intr) - printk("\naha152x: intr(), "); -#endif -#endif - - if (!shpnt) - panic("aha152x: catched interrupt for unknown controller.\n"); + if (!shpnt) { + printk(KERN_ERR "aha152x: catched interrupt for unknown controller.\n"); + return; + } /* no more interrupts from the controller, while we're busy. INTEN is restored by the BH handler */ - CLRBITS(DMACNTRL0, INTEN); +#if 0 + /* check if there is already something to be + serviced; should not happen */ + if(HOSTDATA(shpnt)->service) { + printk(KERN_ERR "aha152x%d: lost interrupt (%d)\n", HOSTNO, HOSTDATA(shpnt)->service); + show_queues(shpnt); + } +#endif + /* Poke the BH handler */ - - HOSTDATA(shpnt)->service = 1; - aha152x_tq.routine = (void *) aha152x_run; + HOSTDATA(shpnt)->service++; + aha152x_tq.routine = (void *) run; queue_task(&aha152x_tq, &tq_immediate); mark_bh(IMMEDIATE_BH); } -static void aha152x_complete(struct Scsi_Host *shpnt) +/* + * busfree phase + * - handle completition/disconnection/error of current command + * - start selection for next command (if any) + */ +static void busfree_run(struct Scsi_Host *shpnt) { - unsigned int flags; - int done = 0, phase; + unsigned long flags; +#if defined(AHA152X_STAT) + int action=0; +#endif - /* disconnected target is trying to reconnect. - Only possible, if we have disconnected nexuses and - nothing is occupying the bus. - */ + SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); + SETPORT(SXFRCTL0, CH1); - if (TESTHI(SSTAT0, SELDI) && - DISCONNECTED_SC && - (!CURRENT_SC || (CURRENT_SC->SCp.phase & in_selection))) { - int identify_msg, target, i; - - /* Avoid conflicts when a target reconnects - while we are trying to connect to another. */ - if (CURRENT_SC) { -#if defined(DEBUG_QUEUES) - if (HOSTDATA(shpnt)->debug & debug_queues) - printk("i+, "); -#endif - save_flags(flags); - cli(); - append_SC(&ISSUE_SC, CURRENT_SC); - CURRENT_SC = NULL; - restore_flags(flags); - } - /* disable sequences */ - SETPORT(SCSISEQ, 0); - SETPORT(SSTAT0, CLRSELDI); - SETPORT(SSTAT1, CLRBUSFREE); - -#if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES) - if (HOSTDATA(shpnt)->debug & (debug_queues | debug_phases)) - printk("reselected, "); + SETPORT(SSTAT1, CLRBUSFREE); + + if(CURRENT_SC) { +#if defined(AHA152X_STAT) + action++; #endif + CURRENT_SC->SCp.phase &= ~syncneg; - i = GETPORT(SELID) & ~(1 << shpnt->this_id); - target = 0; + if(CURRENT_SC->SCp.phase & completed) { + /* target sent COMMAND COMPLETE */ + done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16)); - if (i == 0) - aha152x_panic(shpnt, "reconnecting target unknown"); + } else if(CURRENT_SC->SCp.phase & aborted) { + DPRINTK(debug_eh, DEBUG_LEAD "ABORT sent\n", CMDINFO(CURRENT_SC)); + done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_ABORT << 16)); - for (; (i & 1) == 0; target++, i >>= 1); + } else if(CURRENT_SC->SCp.phase & resetted) { + DPRINTK(debug_eh, DEBUG_LEAD "BUS DEVICE RESET sent\n", CMDINFO(CURRENT_SC)); + done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_RESET << 16)); -#if defined(DEBUG_QUEUES) - if (HOSTDATA(shpnt)->debug & debug_queues) - printk("SELID=%02x, target=%d, ", GETPORT(SELID), target); + } else if(CURRENT_SC->SCp.phase & disconnected) { + /* target sent DISCONNECT */ + DPRINTK(debug_selection, DEBUG_LEAD "target disconnected at %d/%d\n", + CMDINFO(CURRENT_SC), + CURRENT_SC->resid, + CURRENT_SC->request_bufflen); +#if defined(AHA152X_STAT) + HOSTDATA(shpnt)->disconnections++; #endif - SETPORT(SCSIID, (shpnt->this_id << OID_) | target); - SETPORT(SCSISEQ, ENRESELI); - - if (TESTLO(SSTAT0, SELDI)) - aha152x_panic(shpnt, "RESELI failed"); - - SETPORT(SCSIRATE, HOSTDATA(shpnt)->syncrate[target] & 0x7f); + append_SC(&DISCONNECTED_SC, CURRENT_SC); + CURRENT_SC->SCp.phase |= 1 << 16; + CURRENT_SC = 0; - SETPORT(SCSISIG, P_MSGI); - - /* Get identify message */ - if ((i = getphase(shpnt)) != P_MSGI) { - printk("target doesn't enter MSGI to identify (phase=%02x)\n", i); - aha152x_panic(shpnt, "unknown lun"); + } else { + done(shpnt, DID_ERROR << 16); } - SETPORT(SCSISEQ, 0); - - SETPORT(SXFRCTL0, CH1); +#if defined(AHA152X_STAT) + } else { + HOSTDATA(shpnt)->busfree_without_old_command++; +#endif + } - identify_msg = GETPORT(SCSIBUS); + DO_LOCK(flags); - if (!(identify_msg & IDENTIFY_BASE)) { - printk("target=%d, inbound message (%02x) != IDENTIFY\n", - target, identify_msg); - aha152x_panic(shpnt, "unknown lun"); - } -#if defined(DEBUG_QUEUES) - if (HOSTDATA(shpnt)->debug & debug_queues) - printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f); + if(DONE_SC) { +#if defined(AHA152X_STAT) + action++; #endif + if(SCDONE(DONE_SC)) { + Scsi_Cmnd *ptr=DONE_SC; + DONE_SC=SCDONE(DONE_SC); - save_flags(flags); - cli(); - -#if defined(DEBUG_QUEUES) - if (HOSTDATA(shpnt)->debug & debug_queues) - printk("d-, "); +#if 0 + if(HOSTDATA(shpnt)->debug & debug_eh) { + printk(ERR_LEAD "received sense: ", CMDINFO(ptr)); + print_sense("bh", DONE_SC); + } #endif - CURRENT_SC = remove_SC(&DISCONNECTED_SC, target, identify_msg & 0x3f); - if (!CURRENT_SC) { - printk("lun=%d, ", identify_msg & 0x3f); - aha152x_panic(shpnt, "no disconnected command for that lun"); - } - CURRENT_SC->SCp.phase &= ~disconnected; - restore_flags(flags); - - make_acklow(shpnt); - if (getphase(shpnt) != P_MSGI) { - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE); -#if defined(DEBUG_RACE) - leave_driver("(reselected) intr"); + HOSTDATA(shpnt)->commands--; + if (!HOSTDATA(shpnt)->commands) + SETPORT(PORTA, 0); /* turn led off */ + + kfree(ptr->host_scribble); + kfree(ptr); + } else if(DONE_SC->SCp.Status==0x02) { +#if defined(AHA152X_STAT) + HOSTDATA(shpnt)->busfree_with_check_condition++; #endif - SETBITS(DMACNTRL0, INTEN); - return; - } - } - /* Check, if we aren't busy with a command */ - if (!CURRENT_SC) { - /* bus is free to issue a queued command */ - if (TESTHI(SSTAT1, BUSFREE) && ISSUE_SC) { - save_flags(flags); - cli(); -#if defined(DEBUG_QUEUES) - if (HOSTDATA(shpnt)->debug & debug_queues) - printk("i-, "); +#if 0 + DPRINTK(debug_eh, ERR_LEAD "CHECK CONDITION found\n", CMDINFO(DONE_SC)); #endif - CURRENT_SC = remove_first_SC(&ISSUE_SC); - restore_flags(flags); -#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if (HOSTDATA(shpnt)->debug & (debug_intr | debug_selection | debug_phases)) - printk("issuing command, "); -#endif - CURRENT_SC->SCp.phase = in_selection; + if(!(DONE_SC->SCp.Status & not_issued)) { + Scsi_Cmnd *cmnd = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC); -#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if (HOSTDATA(shpnt)->debug & (debug_intr | debug_selection | debug_phases)) - printk("selecting %d, ", CURRENT_SC->target); -#endif - SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); + if(cmnd) { + Scsi_Cmnd *ptr=DONE_SC; + DONE_SC=0; - /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */ - SETPORT(SXFRCTL1, HOSTDATA(shpnt)->parity ? (ENSPCHK | ENSTIMER) : ENSTIMER); +#if 0 + DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr)); +#endif + + cmnd->cmnd[0] = REQUEST_SENSE; + cmnd->cmnd[1] = 0; + cmnd->cmnd[2] = 0; + cmnd->cmnd[3] = 0; + cmnd->cmnd[4] = sizeof(ptr->sense_buffer); + cmnd->cmnd[5] = 0; + cmnd->cmd_len = 6; + cmnd->host = ptr->host; + cmnd->target = ptr->target; + cmnd->lun = ptr->lun; + cmnd->use_sg = 0; + cmnd->request_buffer = ptr->sense_buffer; + cmnd->request_bufflen = sizeof(ptr->sense_buffer); + + DO_UNLOCK(flags); + aha152x_internal_queue(cmnd, 0, 0, ptr, internal_done); + DO_LOCK(flags); + } else { + printk(ERR_LEAD "allocation failed\n", CMDINFO(CURRENT_SC)); + if(cmnd) + kfree(cmnd); + } + } else { +#if 0 + DPRINTK(debug_eh, ERR_LEAD "command not issued - CHECK CONDITION ignored\n", CMDINFO(DONE_SC)); +#endif + } + } - /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ - SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); - SETPORT(SIMODE1, ENSELTIMO); + if(DONE_SC && DONE_SC->scsi_done) { + /* turn led off, when no commands are in the driver */ + HOSTDATA(shpnt)->commands--; + if (!HOSTDATA(shpnt)->commands) + SETPORT(PORTA, 0); /* turn led off */ - /* Enable SELECTION OUT sequence */ - SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); + kfree(DONE_SC->host_scribble); + DONE_SC->host_scribble=0; - } else { - /* No command we are busy with and no new to issue */ - printk("aha152x: ignoring spurious interrupt, nothing to do\n"); - if (TESTHI(DMACNTRL0, SWINT)) { - printk("aha152x: SWINT is set! Why?\n"); - CLRBITS(DMACNTRL0, SWINT); - } - show_queues(shpnt); + DO_UNLOCK(flags); + DPRINTK(debug_done, DEBUG_LEAD "calling scsi_done(%p)\n", CMDINFO(DONE_SC), DONE_SC); + DONE_SC->scsi_done(DONE_SC); + DPRINTK(debug_done, DEBUG_LEAD "scsi_done(%p) returned\n", CMDINFO(DONE_SC), DONE_SC); + DO_LOCK(flags); } -#if defined(DEBUG_RACE) - leave_driver("(selecting) intr"); + DONE_SC=0; +#if defined(AHA152X_STAT) + } else { + HOSTDATA(shpnt)->busfree_without_done_command++; #endif - SETBITS(DMACNTRL0, INTEN); - return; } - /* the bus is busy with something */ -#if defined(DEBUG_INTR) - if (HOSTDATA(shpnt)->debug & debug_intr) - disp_ports(shpnt); -#endif + if(ISSUE_SC) + CURRENT_SC = remove_first_SC(&ISSUE_SC); - /* we are waiting for the result of a selection attempt */ - if (CURRENT_SC->SCp.phase & in_selection) { - if (TESTLO(SSTAT1, SELTO)) { - /* no timeout */ - if (TESTHI(SSTAT0, SELDO)) { - /* clear BUS FREE interrupt */ - SETPORT(SSTAT1, CLRBUSFREE); + DO_UNLOCK(flags); - /* Disable SELECTION OUT sequence */ - CLRBITS(SCSISEQ, ENSELO | ENAUTOATNO); + if(CURRENT_SC) { +#if defined(AHA152X_STAT) + action++; +#endif + CURRENT_SC->SCp.phase |= selecting; - /* Disable SELECTION OUT DONE interrupt */ - CLRBITS(SIMODE0, ENSELDO); - CLRBITS(SIMODE1, ENSELTIMO); + DPRINTK(debug_selection, DEBUG_LEAD "selecting target\n", CMDINFO(CURRENT_SC)); - if (TESTLO(SSTAT0, SELDO)) { - printk("aha152x: passing bus free condition\n"); + /* clear selection timeout */ + SETPORT(SSTAT1, SELTO); -#if defined(DEBUG_RACE) - leave_driver("(passing bus free) intr"); + SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); + SETPORT(SXFRCTL1, (PARITY ? ENSPCHK : 0 ) | ENSTIMER); + SETPORT(SCSISEQ, ENSELO | ENAUTOATNO | (DISCONNECTED_SC ? ENRESELI : 0)); + } else { +#if defined(AHA152X_STAT) + HOSTDATA(shpnt)->busfree_without_new_command++; #endif - SETBITS(DMACNTRL0, INTEN); - - if (CURRENT_SC->SCp.phase & aborted) { - HOSTDATA(shpnt)->abort_result = SCSI_ABORT_ERROR; - HOSTDATA(shpnt)->abortion_complete++; - } - aha152x_done(shpnt, DID_NO_CONNECT << 16); + SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0); + } - return; - } -#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases)) - printk("SELDO (SELID=%x), ", GETPORT(SELID)); +#if defined(AHA152X_STAT) + if(!action) + HOSTDATA(shpnt)->busfree_without_any_action++; #endif +} - /* selection was done */ - SETPORT(SSTAT0, CLRSELDO); +/* + * Selection done (OUT) + * - queue IDENTIFY message and SDTR to selected target for message out + * (ATN asserted automagically via ENAUTOATNO in busfree()) + */ +static void seldo_run(struct Scsi_Host *shpnt) +{ + SETPORT(SCSISIG, 0); + SETPORT(SSTAT1, CLRBUSFREE); + SETPORT(SSTAT1, CLRPHASECHG); -#if defined(DEBUG_ABORT) - if ((HOSTDATA(shpnt)->debug & debug_abort) && (CURRENT_SC->SCp.phase & aborted)) - printk("(ABORT) target selected, "); -#endif + CURRENT_SC->SCp.phase &= ~(selecting|not_issued); - CURRENT_SC->SCp.phase &= ~in_selection; - CURRENT_SC->SCp.phase |= in_other; + SETPORT(SCSISEQ, 0); - ADDMSG(IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun)); + if (TESTLO(SSTAT0, SELDO)) { + printk(ERR_LEAD "aha152x: passing bus free condition\n", CMDINFO(CURRENT_SC)); + done(shpnt, DID_NO_CONNECT << 16); + return; + } - if (!(SYNCRATE & 0x80) && HOSTDATA(shpnt)->synchronous) { - ADDMSG(EXTENDED_MESSAGE); - ADDMSG(3); - ADDMSG(EXTENDED_SDTR); - ADDMSG(50); - ADDMSG(8); + SETPORT(SSTAT0, CLRSELDO); + + ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->lun)); + + if (CURRENT_SC->SCp.phase & aborting) { + ADDMSGO(ABORT); + } else if (CURRENT_SC->SCp.phase & resetting) { + ADDMSGO(BUS_DEVICE_RESET); + } else if (SYNCNEG==0 && SYNCHRONOUS) { + CURRENT_SC->SCp.phase |= syncneg; + ADDMSGO(EXTENDED_MESSAGE); + ADDMSGO(3); + ADDMSGO(EXTENDED_SDTR); + ADDMSGO(50); /* 200ns */ + ADDMSGO(8); /* 8 byte req/ack offset */ + + SYNCNEG=1; /* negotiation in progress */ + } - printk("outbound SDTR: "); - print_msg(&MSG(MSGLEN - 5)); + SETRATE(SYNCRATE); +} - SYNCRATE = 0x80; - CURRENT_SC->SCp.phase |= in_sync; - } -#if defined(DEBUG_RACE) - leave_driver("(SELDO) intr"); -#endif - SETPORT(SCSIRATE, SYNCRATE & 0x7f); +/* + * Selection timeout + * - return command to mid-level with failure cause + * + */ +static void selto_run(struct Scsi_Host *shpnt) +{ + SETPORT(SCSISEQ, 0); + SETPORT(SSTAT1, CLRSELTIMO); - SETPORT(SCSISIG, P_MSGO); + DPRINTK(debug_selection, DEBUG_LEAD "selection timeout\n", CMDINFO(CURRENT_SC)); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENREQINIT | ENBUSFREE); - SETBITS(DMACNTRL0, INTEN); + if(!CURRENT_SC) { + DPRINTK(debug_selection, DEBUG_LEAD "!CURRENT_SC\n", CMDINFO(CURRENT_SC)); + return; + } - return; - } else - aha152x_panic(shpnt, "neither timeout nor selection\007"); - } else { -#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases)) - printk("SELTO, "); -#endif - /* end selection attempt */ - CLRBITS(SCSISEQ, ENSELO | ENAUTOATNO); + CURRENT_SC->SCp.phase &= ~selecting; - /* timeout */ - SETPORT(SSTAT1, CLRSELTIMO); + if (CURRENT_SC->SCp.phase & aborted) { + DPRINTK(debug_selection, DEBUG_LEAD "aborted\n", CMDINFO(CURRENT_SC)); + done(shpnt, DID_ABORT << 16); + } else if (TESTLO(SSTAT0, SELINGO)) { + DPRINTK(debug_selection, DEBUG_LEAD "arbitration not won\n", CMDINFO(CURRENT_SC)); + done(shpnt, DID_BUS_BUSY << 16); + } else { + /* ARBITRATION won, but SELECTION failed */ + DPRINTK(debug_selection, DEBUG_LEAD "selection failed\n", CMDINFO(CURRENT_SC)); + done(shpnt, DID_NO_CONNECT << 16); + } +} - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - SETBITS(DMACNTRL0, INTEN); -#if defined(DEBUG_RACE) - leave_driver("(SELTO) intr"); -#endif +/* + * Selection in done + * - put current command back to issue queue + * (reconnection of a disconnected nexus instead + * of successful selection out) + * + */ +static void seldi_run(struct Scsi_Host *shpnt) +{ + int selid; + int target; + unsigned long flags; - if (CURRENT_SC->SCp.phase & aborted) { -#if defined(DEBUG_ABORT) - if (HOSTDATA(shpnt)->debug & debug_abort) - printk("(ABORT) selection timeout, "); -#endif - HOSTDATA(shpnt)->abort_result = SCSI_ABORT_ERROR; - HOSTDATA(shpnt)->abortion_complete++; - } - if (TESTLO(SSTAT0, SELINGO)) - /* ARBITRATION not won */ - aha152x_done(shpnt, DID_BUS_BUSY << 16); - else - /* ARBITRATION won, but SELECTION failed */ - aha152x_done(shpnt, DID_NO_CONNECT << 16); + SETPORT(SCSISIG, 0); + SETPORT(SSTAT0, CLRSELDI); + SETPORT(SSTAT1, CLRBUSFREE); + SETPORT(SSTAT1, CLRPHASECHG); - return; - } + if(CURRENT_SC) { + if(!(CURRENT_SC->SCp.phase & not_issued)) + printk(ERR_LEAD "command should not have been issued yet\n", CMDINFO(CURRENT_SC)); + + DPRINTK(debug_selection, ERR_LEAD "command requeued - reselection\n", CMDINFO(CURRENT_SC)); + + DO_LOCK(flags); + append_SC(&ISSUE_SC, CURRENT_SC); + DO_UNLOCK(flags); + + CURRENT_SC = 0; } - /* enable interrupt, when target leaves current phase */ - phase = getphase(shpnt); - if (!(phase & ~P_MASK)) /* "real" phase */ - SETPORT(SCSISIG, phase); - SETPORT(SSTAT1, CLRPHASECHG); - CURRENT_SC->SCp.phase = - (CURRENT_SC->SCp.phase & ~((P_MASK | 1) << 16)) | (phase << 16); - - /* information transfer phase */ - switch (phase) { - case P_MSGO: /* MESSAGE OUT */ - { - int i, identify = 0, abort = 0; - -#if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES) - if (HOSTDATA(shpnt)->debug & (debug_intr | debug_msgo | debug_phases)) - printk("MESSAGE OUT, "); -#endif - if (MSGLEN == 0) { - ADDMSG(MESSAGE_REJECT); -#if defined(DEBUG_MSGO) - if (HOSTDATA(shpnt)->debug & debug_msgo) - printk("unexpected MESSAGE OUT phase; rejecting, "); -#endif - } - CLRBITS(SXFRCTL0, ENDMA); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE); + if(!DISCONNECTED_SC) { + DPRINTK(debug_selection, DEBUG_LEAD "unexpected SELDI ", CMDINFO(CURRENT_SC)); + return; + } - /* wait for data latch to become ready or a phase change */ - while (TESTLO(DMASTAT, INTSTAT)) - barrier(); + RECONN_TARGET=-1; -#if defined(DEBUG_MSGO) - if (HOSTDATA(shpnt)->debug & debug_msgo) { - int i; + selid = GETPORT(SELID) & ~(1 << shpnt->this_id); - printk("messages ("); - for (i = 0; i < MSGLEN; i += print_msg(&MSG(i)), printk(" ")); - printk("), "); - } -#endif + if (selid==0) { + printk("aha152x%d: target id unknown (%02x)\n", HOSTNO, selid); + return; + } - for (i = 0; i < MSGLEN && TESTLO(SSTAT1, PHASEMIS); i++) { -#if defined(DEBUG_MSGO) - if (HOSTDATA(shpnt)->debug & debug_msgo) - printk("%x ", MSG(i)); -#endif - if (i == MSGLEN - 1) { - /* Leave MESSAGE OUT after transfer */ - SETPORT(SSTAT1, CLRATNO); - } - SETPORT(SCSIDAT, MSG(i)); + for(target=7; !(selid & (1 << target)); target--) + ; - make_acklow(shpnt); - getphase(shpnt); + if(selid & ~(1 << target)) { + printk("aha152x%d: multiple targets reconnected (%02x)\n", + HOSTNO, selid); + } - if (MSG(i) == IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun)) - identify++; - if (MSG(i) == ABORT) - abort++; + SETPORT(SCSIID, (shpnt->this_id << OID_) | target); + SETPORT(SCSISEQ, 0); - } + SETRATE(HOSTDATA(shpnt)->syncrate[target]); - MSGLEN = 0; + RECONN_TARGET=target; + DPRINTK(debug_selection, DEBUG_LEAD "target %d reselected (%02x).\n", CMDINFO(CURRENT_SC), target, selid); +} + +/* + * message in phase + * - handle initial message after reconnection to identify + * reconnecting nexus + * - queue command on DISCONNECTED_SC on DISCONNECT message + * - set completed flag on COMMAND COMPLETE + * (other completition code moved to busfree_run) + * - handle response to SDTR + * - clear synchronous transfer agreements on BUS RESET + * + * FIXME: what about SAVE POINTERS, RESTORE POINTERS? + * + */ +static void msgi_run(struct Scsi_Host *shpnt) +{ + for(;;) { + int sstat1 = GETPORT(SSTAT1); - if (identify) - CURRENT_SC->SCp.phase |= sent_ident; + if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT)) + return; - if (abort) { - /* revive abort(); abort() enables interrupts */ - HOSTDATA(shpnt)->abort_result = SCSI_ABORT_SUCCESS; - HOSTDATA(shpnt)->abortion_complete++; + if(TESTLO(SSTAT0,SPIORDY)) { + DPRINTK(debug_msgi, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC)); + return; + } - CURRENT_SC->SCp.phase &= ~(P_MASK << 16); + ADDMSGI(GETPORT(SCSIDAT)); - /* exit */ - SETBITS(DMACNTRL0, INTEN); -#if defined(DEBUG_RACE) - leave_driver("(ABORT) intr"); +#if defined(AHA152X_DEBUG) + if (HOSTDATA(shpnt)->debug & debug_msgi) { + printk(INFO_LEAD "inbound message %02x ", CMDINFO(CURRENT_SC), MSGI(0)); + print_msg(&MSGI(0)); + printk("\n"); + } #endif - aha152x_done(shpnt, DID_ABORT << 16); - return; + if(!CURRENT_SC) { + if(LASTSTATE!=seldi) { + printk(KERN_ERR "aha152x%d: message in w/o current command not after reselection\n", HOSTNO); } - } - break; - case P_CMD: /* COMMAND phase */ -#if defined(DEBUG_INTR) || defined(DEBUG_CMD) || defined(DEBUG_PHASES) - if (HOSTDATA(shpnt)->debug & (debug_intr | debug_cmd | debug_phases)) - printk("COMMAND, "); -#endif - if (!(CURRENT_SC->SCp.sent_command)) { - int i; + /* + * Handle reselection + */ + if(!(MSGI(0) & IDENTIFY_BASE)) { + printk(KERN_ERR "aha152x%d: target didn't identify after reselection\n", HOSTNO); + continue; + } - CLRBITS(SXFRCTL0, ENDMA); + CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE); + if (!CURRENT_SC) { + show_queues(shpnt); + printk(KERN_ERR "aha152x%d: no disconnected command for target %d/%d\n", HOSTNO, RECONN_TARGET, MSGI(0) & 0x3f); + continue; + } - /* wait for data latch to become ready or a phase change */ - while (TESTLO(DMASTAT, INTSTAT)) - barrier(); + DPRINTK(debug_msgi, DEBUG_LEAD "target reconnected\n", CMDINFO(CURRENT_SC)); - for (i = 0; i < CURRENT_SC->cmd_len && TESTLO(SSTAT1, PHASEMIS); i++) { - SETPORT(SCSIDAT, CURRENT_SC->cmnd[i]); + CURRENT_SC->SCp.Message = MSGI(0); + CURRENT_SC->SCp.phase &= ~disconnected; - make_acklow(shpnt); - getphase(shpnt); - } + MSGILEN=0; - if (i < CURRENT_SC->cmd_len && TESTHI(SSTAT1, PHASEMIS)) - aha152x_panic(shpnt, "target left COMMAND"); + /* next message if any */ + continue; + } - CURRENT_SC->SCp.sent_command++; - } else - aha152x_panic(shpnt, "Nothing to send while in COMMAND"); - break; + CURRENT_SC->SCp.Message = MSGI(0); - case P_MSGI: /* MESSAGE IN phase */ - { - int start_sync = 0; + switch (MSGI(0)) { + case DISCONNECT: + if (!RECONNECT) + printk(WARN_LEAD "target was not allowed to disconnect\n", CMDINFO(CURRENT_SC)); -#if defined(DEBUG_INTR) || defined(DEBUG_MSGI) || defined(DEBUG_PHASES) - if (HOSTDATA(shpnt)->debug & (debug_intr | debug_msgi | debug_phases)) - printk("MESSAGE IN, "); -#endif - SETPORT(SXFRCTL0, CH1); + CURRENT_SC->SCp.phase |= disconnected; + break; - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENBUSFREE); + case COMMAND_COMPLETE: + if(CURRENT_SC->SCp.phase & completed) + DPRINTK(debug_msgi, DEBUG_LEAD "again COMMAND COMPLETE\n", CMDINFO(CURRENT_SC)); - while (phase == P_MSGI) { - CURRENT_SC->SCp.Message = GETPORT(SCSIDAT); - switch (CURRENT_SC->SCp.Message) { - case DISCONNECT: -#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES) - if (HOSTDATA(shpnt)->debug & (debug_msgi | debug_phases)) - printk("target disconnected, "); -#endif - CURRENT_SC->SCp.Message = 0; - CURRENT_SC->SCp.phase |= disconnected; - if (!HOSTDATA(shpnt)->reconnect) - aha152x_panic(shpnt, "target was not allowed to disconnect"); + CURRENT_SC->SCp.phase |= completed; + break; - break; + case MESSAGE_REJECT: + if (SYNCNEG==1) { + printk(INFO_LEAD "Synchronous Data Transfer Request was rejected\n", CMDINFO(CURRENT_SC)); + SYNCNEG=2; /* negotiation completed */ + } else + printk(INFO_LEAD "inbound message (MESSAGE REJECT)\n", CMDINFO(CURRENT_SC)); + break; - case COMMAND_COMPLETE: -#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES) - if (HOSTDATA(shpnt)->debug & (debug_msgi | debug_phases)) - printk("inbound message (COMMAND COMPLETE), "); -#endif - done++; - break; - - case MESSAGE_REJECT: - if (CURRENT_SC->SCp.phase & in_sync) { - CURRENT_SC->SCp.phase &= ~in_sync; - SYNCRATE = 0x80; - printk("synchronous rejected, "); - } else - printk("inbound message (MESSAGE REJECT), "); -#if defined(DEBUG_MSGI) - if (HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (MESSAGE REJECT), "); -#endif - break; + case SAVE_POINTERS: + break; - case SAVE_POINTERS: -#if defined(DEBUG_MSGI) - if (HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (SAVE DATA POINTERS), "); -#endif - break; + case RESTORE_POINTERS: + break; - case RESTORE_POINTERS: -#if defined(DEBUG_MSGI) - if (HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (RESTORE DATA POINTERS), "); -#endif - break; + case EXTENDED_MESSAGE: + if(MSGILEN<2 || MSGILEN<MSGI(1)+2) { + /* not yet completed */ + continue; + } - case EXTENDED_MESSAGE: - { - char buffer[16]; - int i; + switch (MSGI(2)) { + case EXTENDED_SDTR: + { + long ticks; -#if defined(DEBUG_MSGI) - if (HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (EXTENDED MESSAGE), "); -#endif - make_acklow(shpnt); - if (getphase(shpnt) != P_MSGI) - break; + if (MSGI(1) != 3) { + printk(ERR_LEAD "SDTR message length!=3\n", CMDINFO(CURRENT_SC)); + break; + } - buffer[0] = EXTENDED_MESSAGE; - buffer[1] = GETPORT(SCSIDAT); + if (!HOSTDATA(shpnt)->synchronous) + break; - for (i = 0; i < buffer[1] && - (make_acklow(shpnt), getphase(shpnt) == P_MSGI); i++) - buffer[2 + i] = GETPORT(SCSIDAT); + printk(INFO_LEAD, CMDINFO(CURRENT_SC)); + print_msg(&MSGI(0)); + printk("\n"); -#if defined(DEBUG_MSGI) - if (HOSTDATA(shpnt)->debug & debug_msgi) - print_msg(buffer); -#endif + ticks = (MSGI(3) * 4 + 49) / 50; - switch (buffer[2]) { - case EXTENDED_SDTR: - { - long ticks; + if (syncneg) { + /* negotiation in progress */ + if (ticks > 9 || MSGI(4) < 1 || MSGI(4) > 8) { + ADDMSGO(MESSAGE_REJECT); + printk(INFO_LEAD "received Synchronous Data Transfer Request invalid - rejected\n", CMDINFO(CURRENT_SC)); + break; + } + + SYNCRATE |= ((ticks - 2) << 4) + MSGI(4); + } else if (ticks <= 9 && MSGI(4) >= 1) { + ADDMSGO(EXTENDED_MESSAGE); + ADDMSGO(3); + ADDMSGO(EXTENDED_SDTR); + if (ticks < 4) { + ticks = 4; + ADDMSGO(50); + } else + ADDMSGO(MSGI(3)); + + if (MSGI(4) > 8) + MSGI(4) = 8; + + ADDMSGO(MSGI(4)); + + SYNCRATE |= ((ticks - 2) << 4) + MSGI(4); + } else { + /* requested SDTR is too slow, do it asynchronously */ + printk(INFO_LEAD "Synchronous Data Transfer Request too slow - Rejecting\n", CMDINFO(CURRENT_SC)); + ADDMSGO(MESSAGE_REJECT); + } - if (buffer[1] != 3) - aha152x_panic(shpnt, "SDTR message length != 3"); + SYNCNEG=2; /* negotiation completed */ + SETRATE(SYNCRATE); + } + break; - if (!HOSTDATA(shpnt)->synchronous) - break; + case BUS_DEVICE_RESET: + { + int i; - printk("inbound SDTR: "); - print_msg(buffer); + for(i=0; i<8; i++) { + HOSTDATA(shpnt)->syncrate[i]=0; + HOSTDATA(shpnt)->syncneg[i]=0; + } - ticks = (buffer[3] * 4 + 49) / 50; + } + break; + + case EXTENDED_MODIFY_DATA_POINTER: + case EXTENDED_EXTENDED_IDENTIFY: + case EXTENDED_WDTR: + default: + ADDMSGO(MESSAGE_REJECT); + break; + } + break; + } - if (CURRENT_SC->SCp.phase & in_sync) { - /* we initiated SDTR */ - if (ticks > 9 || buffer[4] < 1 || buffer[4] > 8) - aha152x_panic(shpnt, "received SDTR invalid"); + MSGILEN=0; + } +} - SYNCRATE |= ((ticks - 2) << 4) + buffer[4]; - } else if (ticks <= 9 && buffer[4] >= 1) { - if (buffer[4] > 8) - buffer[4] = 8; +static void msgi_end(struct Scsi_Host *shpnt) +{ + if(MSGILEN>0) + printk(WARN_LEAD "target left before message completed (%d)\n", CMDINFO(CURRENT_SC), MSGILEN); - ADDMSG(EXTENDED_MESSAGE); - ADDMSG(3); - ADDMSG(EXTENDED_SDTR); - if (ticks < 4) { - ticks = 4; - ADDMSG(50); - } else - ADDMSG(buffer[3]); + if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE)) { + DPRINTK(debug_msgi, DEBUG_LEAD "msgo pending\n", CMDINFO(CURRENT_SC)); + SETPORT(SCSISIG, P_MSGI | SIG_ATNO); + } +} - ADDMSG(buffer[4]); +/* + * message out phase + * + */ +static void msgo_init(struct Scsi_Host *shpnt) +{ + if(MSGOLEN==0) { + if((CURRENT_SC->SCp.phase & syncneg) && SYNCNEG==2 && SYNCRATE==0) { + ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->lun)); + } else { + printk(INFO_LEAD "unexpected MESSAGE OUT phase; rejecting\n", CMDINFO(CURRENT_SC)); + ADDMSGO(MESSAGE_REJECT); + } + } - printk("outbound SDTR: "); - print_msg(&MSG(MSGLEN - 5)); +#if defined(AHA152X_DEBUG) + if(HOSTDATA(shpnt)->debug & debug_msgo) { + int i; - CURRENT_SC->SCp.phase |= in_sync; + printk(DEBUG_LEAD "messages( ", CMDINFO(CURRENT_SC)); + for (i=0; i<MSGOLEN; i+=print_msg(&MSGO(i)), printk(" ")) + ; + printk(")\n"); + } +#endif +} - SYNCRATE |= ((ticks - 2) << 4) + buffer[4]; +/* + * message out phase + * + */ +static void msgo_run(struct Scsi_Host *shpnt) +{ + if(MSGO_I==MSGOLEN) + DPRINTK(debug_msgo, DEBUG_LEAD "messages all sent (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO_I, MSGOLEN); - start_sync++; - } else { - /* requested SDTR is too slow, do it asynchronously */ - ADDMSG(MESSAGE_REJECT); - SYNCRATE = 0; - } + while(MSGO_I<MSGOLEN) { + DPRINTK(debug_msgo, DEBUG_LEAD "message byte %02x (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO(MSGO_I), MSGO_I, MSGOLEN); - SETPORT(SCSIRATE, SYNCRATE & 0x7f); - } - break; + if(TESTLO(SSTAT0, SPIORDY)) { + DPRINTK(debug_msgo, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC)); + return; + } - case EXTENDED_MODIFY_DATA_POINTER: - case EXTENDED_EXTENDED_IDENTIFY: - case EXTENDED_WDTR: - default: - ADDMSG(MESSAGE_REJECT); - break; - } - } - break; + if (MSGO_I==MSGOLEN-1) { + /* Leave MESSAGE OUT after transfer */ + SETPORT(SSTAT1, CLRATNO); + } - default: - printk("unsupported inbound message %x, ", CURRENT_SC->SCp.Message); - break; - } + if (MSGO(MSGO_I) & IDENTIFY_BASE) + CURRENT_SC->SCp.phase |= identified; - make_acklow(shpnt); - phase = getphase(shpnt); - } + if (MSGO(MSGO_I)==ABORT) + CURRENT_SC->SCp.phase |= aborted; - if (start_sync) - CURRENT_SC->SCp.phase |= in_sync; - else - CURRENT_SC->SCp.phase &= ~in_sync; + if (MSGO(MSGO_I)==BUS_DEVICE_RESET) + CURRENT_SC->SCp.phase |= resetted; - if (MSGLEN > 0) - SETPORT(SCSISIG, P_MSGI | ATNO); + SETPORT(SCSIDAT, MSGO(MSGO_I++)); + } +} - /* clear SCSI fifo on BUSFREE */ - if (phase == P_BUSFREE) - SETPORT(SXFRCTL0, CH1 | CLRCH1); +static void msgo_end(struct Scsi_Host *shpnt) +{ + if(MSGO_I<MSGOLEN) + printk(ERR_LEAD "message sent incompletely (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO_I, MSGOLEN); + + MSGO_I = 0; + MSGOLEN = 0; +} + +/* + * command phase + * + */ +static void cmd_init(struct Scsi_Host *shpnt) +{ + if (CURRENT_SC->SCp.sent_command) { + printk(ERR_LEAD "command already sent\n", CMDINFO(CURRENT_SC)); + done(shpnt, DID_ERROR << 16); + return; + } - if (CURRENT_SC->SCp.phase & disconnected) { - save_flags(flags); - cli(); -#if defined(DEBUG_QUEUES) - if (HOSTDATA(shpnt)->debug & debug_queues) - printk("d+, "); +#if defined(AHA152X_DEBUG) + if (HOSTDATA(shpnt)->debug & debug_cmd) { + printk(DEBUG_LEAD "cmd_init: ", CMDINFO(CURRENT_SC)); + print_command(CURRENT_SC->cmnd); + } #endif - append_SC(&DISCONNECTED_SC, CURRENT_SC); - CURRENT_SC->SCp.phase |= 1 << 16; - CURRENT_SC = NULL; - restore_flags(flags); - SETBITS(SCSISEQ, ENRESELI); + CMD_I=0; +} - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); +/* + * command phase + * + */ +static void cmd_run(struct Scsi_Host *shpnt) +{ + if(CMD_I==CURRENT_SC->cmd_len) { + DPRINTK(debug_cmd, DEBUG_LEAD "command already completely sent (%d/%d)", CMDINFO(CURRENT_SC), CMD_I, CURRENT_SC->cmd_len); + disp_ports(shpnt); + } - SETBITS(DMACNTRL0, INTEN); + while(CMD_I<CURRENT_SC->cmd_len) { + DPRINTK(debug_cmd, DEBUG_LEAD "command byte %02x (%d/%d)\n", CMDINFO(CURRENT_SC), CURRENT_SC->cmnd[CMD_I], CMD_I, CURRENT_SC->cmd_len); - return; - } + if(TESTLO(SSTAT0, SPIORDY)) { + DPRINTK(debug_cmd, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC)); + return; } - break; - case P_STATUS: /* STATUS IN phase */ -#if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - if (HOSTDATA(shpnt)->debug & (debug_status | debug_intr | debug_phases)) - printk("STATUS, "); -#endif - SETPORT(SXFRCTL0, CH1); + SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]); + } +} - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENREQINIT | ENBUSFREE); +static void cmd_end(struct Scsi_Host *shpnt) +{ + if(CMD_I<CURRENT_SC->cmd_len) + printk(ERR_LEAD "command sent incompletely (%d/%d)\n", CMDINFO(CURRENT_SC), CMD_I, CURRENT_SC->cmd_len); + else + CURRENT_SC->SCp.sent_command++; +} - if (TESTHI(SSTAT1, PHASEMIS)) - printk("aha152x: passing STATUS phase"); +/* + * status phase + * + */ +static void status_run(struct Scsi_Host *shpnt) +{ + if(TESTLO(SSTAT0,SPIORDY)) { + DPRINTK(debug_status, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC)); + return; + } - CURRENT_SC->SCp.Status = GETPORT(SCSIBUS); - make_acklow(shpnt); - getphase(shpnt); + CURRENT_SC->SCp.Status = GETPORT(SCSIDAT); -#if defined(DEBUG_STATUS) - if (HOSTDATA(shpnt)->debug & debug_status) { - printk("inbound status "); - print_status(CURRENT_SC->SCp.Status); - printk(", "); - } +#if defined(AHA152X_DEBUG) + if (HOSTDATA(shpnt)->debug & debug_status) { + printk(DEBUG_LEAD "inbound status %02x ", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.Status); + print_status(CURRENT_SC->SCp.Status); + printk("\n"); + } #endif - break; +} - case P_DATAI: /* DATA IN phase */ - { - int fifodata, data_count, done; +/* + * data in phase + * + */ +static void datai_init(struct Scsi_Host *shpnt) +{ + SETPORT(DMACNTRL0, RSTFIFO); + SETPORT(DMACNTRL0, RSTFIFO|ENDMA); -#if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - if (HOSTDATA(shpnt)->debug & (debug_datai | debug_intr | debug_phases)) - printk("DATA IN, "); -#endif + SETPORT(SXFRCTL0, CH1|CLRSTCNT); + SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); -#if 0 - if (GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL | SFCNT)) - printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n", - GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL | SFCNT)); -#endif + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE); - /* reset host fifo */ - SETPORT(DMACNTRL0, RSTFIFO); - SETPORT(DMACNTRL0, RSTFIFO | ENDMA); + DATA_LEN=0; + DPRINTK(debug_datai, + DEBUG_LEAD "datai_init: request_bufflen=%d resid=%d\n", + CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid); +} - SETPORT(SXFRCTL0, CH1 | SCSIEN | DMAEN); +static void datai_run(struct Scsi_Host *shpnt) +{ + unsigned int the_time; + int fifodata, data_count; - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE); + /* + * loop while the phase persists or the fifos are not empty + * + */ + while(TESTLO(DMASTAT, INTSTAT) || TESTLO(DMASTAT, DFIFOEMP) || TESTLO(SSTAT2, SEMPTY)) { + /* FIXME: maybe this should be done by setting up + * STCNT to trigger ENSWRAP interrupt, instead of + * polling for DFIFOFULL + */ + the_time=jiffies + 100; + while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time)) + barrier(); - /* done is set when the FIFO is empty after the target left DATA IN */ - done = 0; + if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) { + printk(ERR_LEAD "datai timeout", CMDINFO(CURRENT_SC)); + disp_ports(shpnt); + break; + } - /* while the target stays in DATA to transfer data */ - while (!done) { -#if defined(DEBUG_DATAI) - if (HOSTDATA(shpnt)->debug & debug_datai) - printk("expecting data, "); -#endif - /* wait for PHASEMIS or full FIFO */ - while (TESTLO(DMASTAT, DFIFOFULL | INTSTAT)) - barrier(); + if(TESTHI(DMASTAT, DFIFOFULL)) { + fifodata = 128; + } else { + the_time=jiffies + 100; + while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time)) + barrier(); -#if defined(DEBUG_DATAI) - if (HOSTDATA(shpnt)->debug & debug_datai) - printk("ok, "); -#endif + if(TESTLO(SSTAT2, SEMPTY)) { + printk(ERR_LEAD "datai sempty timeout", CMDINFO(CURRENT_SC)); + disp_ports(shpnt); + break; + } - if (TESTHI(DMASTAT, DFIFOFULL)) - fifodata = GETPORT(FIFOSTAT); - else { - /* wait for SCSI fifo to get empty */ - while (TESTLO(SSTAT2, SEMPTY)) - barrier(); - - /* rest of data in FIFO */ - fifodata = GETPORT(FIFOSTAT); -#if defined(DEBUG_DATAI) - if (HOSTDATA(shpnt)->debug & debug_datai) - printk("last transfer, "); -#endif - done = 1; - } + fifodata = GETPORT(FIFOSTAT); + } -#if defined(DEBUG_DATAI) - if (HOSTDATA(shpnt)->debug & debug_datai) - printk("fifodata=%d, ", fifodata); -#endif + while(fifodata>0 && CURRENT_SC->SCp.this_residual>0) { + data_count = fifodata>CURRENT_SC->SCp.this_residual ? + CURRENT_SC->SCp.this_residual : + fifodata; + fifodata -= data_count; + + if(data_count & 1) { + DPRINTK(debug_datai, DEBUG_LEAD "8bit\n", CMDINFO(CURRENT_SC)); + SETPORT(DMACNTRL0, ENDMA|_8BIT); + *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT); + CURRENT_SC->SCp.this_residual--; + DATA_LEN++; + SETPORT(DMACNTRL0, ENDMA); + } + + if(data_count > 1) { + DPRINTK(debug_datai, DEBUG_LEAD "16bit(%d)\n", CMDINFO(CURRENT_SC), data_count); + data_count >>= 1; + insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); + CURRENT_SC->SCp.ptr += 2 * data_count; + CURRENT_SC->SCp.this_residual -= 2 * data_count; + DATA_LEN += 2 * data_count; + } + + if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) { + /* advance to next buffer */ + CURRENT_SC->SCp.buffers_residual--; + CURRENT_SC->SCp.buffer++; + CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address; + CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; + } + } + + if(fifodata>0 && CURRENT_SC->SCp.this_residual==0) { + printk(ERR_LEAD "no buffers left for %d(%d) bytes (data overrun!?)\n", CMDINFO(CURRENT_SC), fifodata, GETPORT(FIFOSTAT)); + break; + } + } - while (fifodata && CURRENT_SC->SCp.this_residual) { - data_count = fifodata; + if(TESTLO(DMASTAT, INTSTAT) || + TESTLO(DMASTAT, DFIFOEMP) || + TESTLO(SSTAT2, SEMPTY) || + GETPORT(FIFOSTAT)>0) { + /* + * something went wrong, if there's something left in the fifos + * or the phase didn't change + */ + printk(ERR_LEAD "fifos should be empty and phase should have changed\n", CMDINFO(CURRENT_SC)); + disp_ports(shpnt); + } - /* limit data transfer to size of first sg buffer */ - if (data_count > CURRENT_SC->SCp.this_residual) - data_count = CURRENT_SC->SCp.this_residual; + if(DATA_LEN!=GETSTCNT()) { + printk(ERR_LEAD + "manual transfer count differs from automatic (count=%d;stcnt=%d;diff=%d;fifostat=%d)", + CMDINFO(CURRENT_SC), DATA_LEN, GETSTCNT(), GETSTCNT()-DATA_LEN, GETPORT(FIFOSTAT)); + disp_ports(shpnt); + mdelay(10000); + } +} - fifodata -= data_count; +static void datai_end(struct Scsi_Host *shpnt) +{ + CURRENT_SC->resid -= GETSTCNT(); -#if defined(DEBUG_DATAI) - if (HOSTDATA(shpnt)->debug & debug_datai) - printk("data_count=%d, ", data_count); -#endif + DPRINTK(debug_datai, + DEBUG_LEAD "datai_end: request_bufflen=%d resid=%d stcnt=%d\n", + CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid, GETSTCNT()); - if (data_count & 1) { - /* get a single byte in byte mode */ - SETBITS(DMACNTRL0, _8BIT); - *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT); - CURRENT_SC->SCp.this_residual--; - } - if (data_count > 1) { - CLRBITS(DMACNTRL0, _8BIT); - data_count >>= 1; /* Number of words */ - insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); -#if defined(DEBUG_DATAI) - if (HOSTDATA(shpnt)->debug & debug_datai) - /* show what comes with the last transfer */ - if (done) { -#if 0 - int i; - unsigned char *data; -#endif + SETPORT(SXFRCTL0, CH1|CLRSTCNT); + SETPORT(DMACNTRL0, 0); +} - printk("data on last transfer (%d bytes) ", - 2 * data_count); -#if 0 - printk("data on last transfer (%d bytes: ", - 2 * data_count); - data = (unsigned char *) CURRENT_SC->SCp.ptr; - for (i = 0; i < 2 * data_count; i++) - printk("%2x ", *data++); - printk("), "); -#endif - } -#endif - CURRENT_SC->SCp.ptr += 2 * data_count; - CURRENT_SC->SCp.this_residual -= 2 * data_count; - } - /* if this buffer is full and there are more buffers left */ - if (!CURRENT_SC->SCp.this_residual && - CURRENT_SC->SCp.buffers_residual) { - /* advance to next buffer */ - CURRENT_SC->SCp.buffers_residual--; - CURRENT_SC->SCp.buffer++; - CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address; - CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; - } - } +/* + * data out phase + * + */ +static void datao_init(struct Scsi_Host *shpnt) +{ + SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO); + SETPORT(DMACNTRL0, WRITE_READ | ENDMA); - /* - * FIFO should be empty - */ - if (fifodata > 0) { - printk("aha152x: more data than expected (%d bytes)\n", - GETPORT(FIFOSTAT)); - SETBITS(DMACNTRL0, _8BIT); - printk("aha152x: data ("); - while (fifodata--) - printk("%2x ", GETPORT(DATAPORT)); - printk(")\n"); - } -#if defined(DEBUG_DATAI) - if (HOSTDATA(shpnt)->debug & debug_datai) - if (!fifodata) - printk("fifo empty, "); - else - printk("something left in fifo, "); -#endif - } + SETPORT(SXFRCTL0, CH1|CLRSTCNT); + SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); -#if defined(DEBUG_DATAI) - if ((HOSTDATA(shpnt)->debug & debug_datai) && - (CURRENT_SC->SCp.buffers_residual || - CURRENT_SC->SCp.this_residual)) - printk("left buffers (buffers=%d, bytes=%d), ", - CURRENT_SC->SCp.buffers_residual, CURRENT_SC->SCp.this_residual); -#endif - /* transfer can be considered ended, when SCSIEN reads back zero */ - CLRBITS(SXFRCTL0, SCSIEN | DMAEN); - while (TESTHI(SXFRCTL0, SCSIEN)) - barrier(); - CLRBITS(DMACNTRL0, ENDMA); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE ); -#if defined(DEBUG_DATAI) || defined(DEBUG_INTR) - if (HOSTDATA(shpnt)->debug & (debug_datai | debug_intr)) - printk("got %d bytes, ", GETSTCNT()); -#endif + DATA_LEN = CURRENT_SC->resid; + + DPRINTK(debug_datao, + DEBUG_LEAD "datao_init: request_bufflen=%d; resid=%d\n", + CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid); +} - CURRENT_SC->SCp.have_data_in++; +static void datao_run(struct Scsi_Host *shpnt) +{ + unsigned int the_time; + int data_count; + + /* until phase changes or all data sent */ + while(TESTLO(DMASTAT, INTSTAT) && CURRENT_SC->SCp.this_residual>0) { + data_count = 128; + if(data_count > CURRENT_SC->SCp.this_residual) + data_count=CURRENT_SC->SCp.this_residual; + + if(TESTLO(DMASTAT, DFIFOEMP)) { + printk(ERR_LEAD "datao fifo not empty (%d)", CMDINFO(CURRENT_SC), GETPORT(FIFOSTAT)); + disp_ports(shpnt); + break; } - break; - case P_DATAO: /* DATA OUT phase */ - { - int data_count; + if(data_count & 1) { + SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT); + SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++); + CURRENT_SC->SCp.this_residual--; + CURRENT_SC->resid--; + SETPORT(DMACNTRL0,WRITE_READ|ENDMA); + } -#if defined(DEBUG_DATAO) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - if (HOSTDATA(shpnt)->debug & (debug_datao | debug_intr | debug_phases)) - printk("DATA OUT, "); -#endif -#if defined(DEBUG_DATAO) - if (HOSTDATA(shpnt)->debug & debug_datao) - printk("got data to send (bytes=%d, buffers=%d), ", - CURRENT_SC->SCp.this_residual, - CURRENT_SC->SCp.buffers_residual); -#endif + if(data_count > 1) { + data_count >>= 1; + outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); + CURRENT_SC->SCp.ptr += 2 * data_count; + CURRENT_SC->SCp.this_residual -= 2 * data_count; + CURRENT_SC->resid -= 2 * data_count; + } + + if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) { + /* advance to next buffer */ + CURRENT_SC->SCp.buffers_residual--; + CURRENT_SC->SCp.buffer++; + CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address; + CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; + } - if (GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL | SFCNT)) { - printk("%d(%d) left in FIFO, ", - GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL | SFCNT)); - aha152x_panic(shpnt, "FIFO should be empty"); - } - SETPORT(SXFRCTL0, CH1 | CLRSTCNT | CLRCH1); - SETPORT(SXFRCTL0, SCSIEN | DMAEN | CH1); - - SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO); - SETPORT(DMACNTRL0, ENDMA | WRITE_READ); - - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE); - - /* while current buffer is not empty or - there are more buffers to transfer */ - while (TESTLO(SSTAT1, PHASEMIS) && - (CURRENT_SC->SCp.this_residual || - CURRENT_SC->SCp.buffers_residual)) { -#if defined(DEBUG_DATAO) - if (HOSTDATA(shpnt)->debug & debug_datao) - printk("sending data (left: bytes=%d, buffers=%d), waiting, ", - CURRENT_SC->SCp.this_residual, - CURRENT_SC->SCp.buffers_residual); -#endif - /* transfer rest of buffer, but max. 128 byte */ - data_count = - CURRENT_SC->SCp.this_residual > 128 ? - 128 : CURRENT_SC->SCp.this_residual; - -#if defined(DEBUG_DATAO) - if (HOSTDATA(shpnt)->debug & debug_datao) - printk("data_count=%d, ", data_count); -#endif + the_time=jiffies+100; + while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time)) + barrier(); - if (data_count & 1) { - /* put a single byte in byte mode */ - SETBITS(DMACNTRL0, _8BIT); - SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++); - CURRENT_SC->SCp.this_residual--; - } - if (data_count > 1) { - CLRBITS(DMACNTRL0, _8BIT); - data_count >>= 1; /* number of words */ - outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); - CURRENT_SC->SCp.ptr += 2 * data_count; - CURRENT_SC->SCp.this_residual -= 2 * data_count; - } - /* wait for FIFO to get empty */ - while (TESTLO(DMASTAT, DFIFOEMP | INTSTAT)) - barrier(); - -#if defined(DEBUG_DATAO) - if (HOSTDATA(shpnt)->debug & debug_datao) - printk("fifo (%d bytes), transfered (%d bytes), ", - GETPORT(FIFOSTAT), GETSTCNT()); -#endif + if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) { + printk(ERR_LEAD "dataout timeout", CMDINFO(CURRENT_SC)); + disp_ports(shpnt); + break; + } + } +} - /* if this buffer is empty and there are more buffers left */ - if (TESTLO(SSTAT1, PHASEMIS) && - !CURRENT_SC->SCp.this_residual && - CURRENT_SC->SCp.buffers_residual) { - /* advance to next buffer */ - CURRENT_SC->SCp.buffers_residual--; - CURRENT_SC->SCp.buffer++; - CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address; - CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; - } - } +static void datao_end(struct Scsi_Host *shpnt) +{ + if(TESTLO(DMASTAT, DFIFOEMP)) { + int data_count = (DATA_LEN - CURRENT_SC->resid) - GETSTCNT(); + + DPRINTK(debug_datao, DEBUG_LEAD "datao: %d bytes to resend (%d written, %d transfered)\n", + CMDINFO(CURRENT_SC), + data_count, + DATA_LEN-CURRENT_SC->resid, + GETSTCNT()); + + CURRENT_SC->resid += data_count; + + data_count -= CURRENT_SC->SCp.ptr - CURRENT_SC->SCp.buffer->address; + while(data_count>0) { + CURRENT_SC->SCp.buffer--; + CURRENT_SC->SCp.buffers_residual++; + data_count -= CURRENT_SC->SCp.buffer->length; + } + CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address - data_count; + CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length + data_count; + } - if (CURRENT_SC->SCp.this_residual || CURRENT_SC->SCp.buffers_residual) { - /* target leaves DATA OUT for an other phase (perhaps disconnect) */ - - /* data in fifos has to be resend */ - data_count = GETPORT(SSTAT2) & (SFULL | SFCNT); - - data_count += GETPORT(FIFOSTAT); - CURRENT_SC->SCp.ptr -= data_count; - CURRENT_SC->SCp.this_residual += data_count; -#if defined(DEBUG_DATAO) - if (HOSTDATA(shpnt)->debug & debug_datao) - printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), " - "transfer incomplete, resetting fifo, ", - CURRENT_SC->SCp.this_residual, - CURRENT_SC->SCp.buffers_residual, - data_count); -#endif - SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO); - CLRBITS(SXFRCTL0, SCSIEN | DMAEN); - CLRBITS(DMACNTRL0, ENDMA); - } else { -#if defined(DEBUG_DATAO) - if (HOSTDATA(shpnt)->debug & debug_datao) - printk("waiting for SCSI fifo to get empty, "); -#endif - /* wait for SCSI fifo to get empty */ - while (TESTLO(SSTAT2, SEMPTY)) - barrier(); -#if defined(DEBUG_DATAO) - if (HOSTDATA(shpnt)->debug & debug_datao) - printk("ok, left data (bytes=%d, buffers=%d) ", - CURRENT_SC->SCp.this_residual, - CURRENT_SC->SCp.buffers_residual); -#endif - CLRBITS(SXFRCTL0, SCSIEN | DMAEN); + DPRINTK(debug_datao, DEBUG_LEAD "datao_end: request_bufflen=%d; resid=%d; stcnt=%d\n", + CMDINFO(CURRENT_SC), + CURRENT_SC->request_bufflen, + CURRENT_SC->resid, + GETSTCNT()); - /* transfer can be considered ended, when SCSIEN reads back zero */ - while (TESTHI(SXFRCTL0, SCSIEN)) - barrier(); + SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); + SETPORT(SXFRCTL0, CH1); - CLRBITS(DMACNTRL0, ENDMA); - } + SETPORT(DMACNTRL0, 0); +} -#if defined(DEBUG_DATAO) || defined(DEBUG_INTR) - if (HOSTDATA(shpnt)->debug & (debug_datao | debug_intr)) - printk("sent %d data bytes, ", GETSTCNT()); -#endif +/* + * figure out what state we're in + * + */ +static int update_state(struct Scsi_Host *shpnt) +{ + int dataphase=0; + unsigned int stat0 = GETPORT(SSTAT0); + unsigned int stat1 = GETPORT(SSTAT1); + + PREVSTATE = STATE; + STATE=unknown; + + if(stat1 & SCSIRSTI) { + STATE=rsti; + SETPORT(SCSISEQ,0); + SETPORT(SSTAT1,SCSIRSTI); + } else if(stat0 & SELDI && PREVSTATE==busfree) { + STATE=seldi; + } else if(stat0 & SELDO && CURRENT_SC && (CURRENT_SC->SCp.phase & selecting)) { + STATE=seldo; + } else if(stat1 & SELTO) { + STATE=selto; + } else if(stat1 & BUSFREE) { + STATE=busfree; + SETPORT(SSTAT1,BUSFREE); + } else if(stat1 & SCSIPERR) { + STATE=parerr; + SETPORT(SSTAT1,SCSIPERR); + } else if(stat1 & REQINIT) { + switch(GETPORT(SCSISIG) & P_MASK) { + case P_MSGI: STATE=msgi; break; + case P_MSGO: STATE=msgo; break; + case P_DATAO: STATE=datao; break; + case P_DATAI: STATE=datai; break; + case P_STATUS: STATE=status; break; + case P_CMD: STATE=cmd; break; } - break; - - case P_BUSFREE: /* BUSFREE */ -#if defined(DEBUG_RACE) - leave_driver("(BUSFREE) intr"); -#endif -#if defined(DEBUG_PHASES) - if (HOSTDATA(shpnt)->debug & debug_phases) - printk("unexpected BUS FREE, "); -#endif - CURRENT_SC->SCp.phase &= ~(P_MASK << 16); + dataphase=1; + } - aha152x_done(shpnt, DID_ERROR << 16); /* Don't know any better */ - return; - break; + if((stat0 & SELDI) && STATE!=seldi && !dataphase) { + printk(INFO_LEAD "reselection missed?", CMDINFO(CURRENT_SC)); + disp_ports(shpnt); + } - case P_PARITY: /* parity error in DATA phase */ -#if defined(DEBUG_RACE) - leave_driver("(DID_PARITY) intr"); -#endif - printk("PARITY error in DATA phase, "); + if(STATE!=PREVSTATE) { + LASTSTATE=PREVSTATE; + } - CURRENT_SC->SCp.phase &= ~(P_MASK << 16); + return dataphase; +} - SETBITS(DMACNTRL0, INTEN); - aha152x_done(shpnt, DID_PARITY << 16); - return; - break; +/* + * handle parity error + * + * FIXME: in which phase? + * + */ +static void parerr_run(struct Scsi_Host *shpnt) +{ + printk(ERR_LEAD "parity error\n", CMDINFO(CURRENT_SC)); + done(shpnt, DID_PARITY << 16); +} - default: - printk("aha152x: unexpected phase\n"); - break; - } +/* + * handle reset in + * + */ +static void rsti_run(struct Scsi_Host *shpnt) +{ + Scsi_Cmnd *ptr; - if (done) { -#if defined(DEBUG_INTR) - if (HOSTDATA(shpnt)->debug & debug_intr) - printk("command done.\n"); -#endif -#if defined(DEBUG_RACE) - leave_driver("(done) intr"); -#endif + printk(KERN_NOTICE "aha152x%d: scsi reset in\n", HOSTNO); + + ptr=DISCONNECTED_SC; + while(ptr) { + Scsi_Cmnd *next = SCNEXT(ptr); - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0); + if (!ptr->device->soft_reset) { + remove_SC(&DISCONNECTED_SC, ptr); - SETBITS(DMACNTRL0, INTEN); + kfree(ptr->host_scribble); + ptr->host_scribble=0; - aha152x_done(shpnt, - (CURRENT_SC->SCp.Status & 0xff) - | ((CURRENT_SC->SCp.Message & 0xff) << 8) - | (DID_OK << 16)); + ptr->result = DID_RESET << 16; + ptr->scsi_done(ptr); + } -#if defined(DEBUG_RACE) - printk("done returned (DID_OK: Status=%x; Message=%x).\n", - CURRENT_SC->SCp.Status, CURRENT_SC->SCp.Message); -#endif - return; + ptr = next; } - if (CURRENT_SC) - CURRENT_SC->SCp.phase |= 1 << 16; - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE); -#if defined(DEBUG_INTR) - if (HOSTDATA(shpnt)->debug & debug_intr) - disp_enintr(shpnt); -#endif -#if defined(DEBUG_RACE) - leave_driver("(PHASEEND) intr"); -#endif + if(CURRENT_SC && !CURRENT_SC->device->soft_reset) + done(shpnt, DID_RESET << 16 ); +} + + +/* + * bottom-half handler + * + */ +static void complete(struct Scsi_Host *shpnt) +{ + int dataphase; + unsigned long flags; + int pending; + + DO_LOCK(flags); + if(HOSTDATA(shpnt)->in_intr!=0) + aha152x_error(shpnt, "bottom-half already running!?"); + HOSTDATA(shpnt)->in_intr++; + DO_UNLOCK(flags); + + /* + * loop while there are interrupt conditions pending + * + */ + do { + unsigned long start = jiffies; + dataphase=update_state(shpnt); + + DPRINTK(debug_phases, LEAD "start %s %s(%s)\n", CMDINFO(CURRENT_SC), states[STATE].name, states[PREVSTATE].name, states[LASTSTATE].name); + + /* + * end previous state + * + */ + if(PREVSTATE!=STATE && states[PREVSTATE].end) + states[PREVSTATE].end(shpnt); + + /* + * disable SPIO mode if previous phase used it + * and this one doesn't + * + */ + if(states[PREVSTATE].spio && !states[STATE].spio) { + SETPORT(SXFRCTL0, CH1); + SETPORT(DMACNTRL0, 0); + if(CURRENT_SC) + CURRENT_SC->SCp.phase &= ~spiordy; + } + /* + * accept current dataphase phase + * + */ + if(dataphase) { + SETPORT(SSTAT0, REQINIT); + SETPORT(SCSISIG, GETPORT(SCSISIG) & P_MASK); + SETPORT(SSTAT1, PHASECHG); + } + + /* + * enable SPIO mode if previous didn't use it + * and this one does + * + */ + if(!states[PREVSTATE].spio && states[STATE].spio) { + SETPORT(DMACNTRL0, 0); + SETPORT(SXFRCTL0, CH1|SPIOEN); + if(CURRENT_SC) + CURRENT_SC->SCp.phase |= spiordy; + } + + /* + * initialize for new state + * + */ + if(PREVSTATE!=STATE && states[STATE].init) + states[STATE].init(shpnt); + + /* + * handle current state + * + */ + if(states[STATE].run) + states[STATE].run(shpnt); + else + printk(ERR_LEAD "unexpected state (%x)\n", CMDINFO(CURRENT_SC), STATE); + + /* + * setup controller to interrupt on + * the next expected condition and + * loop if it's already there + * + */ + DO_LOCK(flags); + pending=setup_expected_interrupts(shpnt); +#if defined(AHA152X_STAT) + HOSTDATA(shpnt)->count[STATE]++; + if(PREVSTATE!=STATE) + HOSTDATA(shpnt)->count_trans[STATE]++; + HOSTDATA(shpnt)->time[STATE] += jiffies-start; +#endif + DO_UNLOCK(flags); + + DPRINTK(debug_phases, LEAD "end %s %s(%s)\n", CMDINFO(CURRENT_SC), states[STATE].name, states[PREVSTATE].name, states[LASTSTATE].name); + } while(pending); + + /* + * enable interrupts and leave bottom-half + * + */ + DO_LOCK(flags); + HOSTDATA(shpnt)->in_intr--; SETBITS(DMACNTRL0, INTEN); - return; + DO_UNLOCK(flags); } + /* - * Dump the current driver status and panic... + * Dump the current driver status and panic */ -static void aha152x_panic(struct Scsi_Host *shpnt, char *msg) +static void aha152x_error(struct Scsi_Host *shpnt, char *msg) { - printk("\naha152x: %s\n", msg); + printk(KERN_EMERG "\naha152x%d: %s\n", HOSTNO, msg); show_queues(shpnt); - panic("aha152x panic"); + panic("aha152x panic\n"); } /* @@ -2666,18 +2980,16 @@ static void aha152x_panic(struct Scsi_Host *shpnt, char *msg) */ static void disp_ports(struct Scsi_Host *shpnt) { -#ifdef DEBUG_AHA152X +#if defined(AHA152X_DEBUG) int s; -#ifdef SKIP_PORTS - if (HOSTDATA(shpnt)->debug & debug_skipports) - return; -#endif - - printk("\n%s: ", CURRENT_SC ? "on bus" : "waiting"); + printk("\n%s: %s(%s) ", + CURRENT_SC ? "busy" : "waiting", + states[STATE].name, + states[PREVSTATE].name); s = GETPORT(SCSISEQ); - printk("SCSISEQ ("); + printk("SCSISEQ( "); if (s & TEMODEO) printk("TARGET MODE "); if (s & ENSELO) @@ -2696,7 +3008,7 @@ static void disp_ports(struct Scsi_Host *shpnt) printk("SCSIRSTO "); printk(");"); - printk(" SCSISIG ("); + printk(" SCSISIG("); s = GETPORT(SCSISIG); switch (s & P_MASK) { case P_DATAO: @@ -2726,7 +3038,7 @@ static void disp_ports(struct Scsi_Host *shpnt) printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); - printk("SSTAT ("); + printk("SSTAT( "); s = GETPORT(SSTAT0); if (s & TARGET) printk("TARGET "); @@ -2765,7 +3077,7 @@ static void disp_ports(struct Scsi_Host *shpnt) printk("); "); - printk("SSTAT ("); + printk("SSTAT( "); s = GETPORT(SSTAT0) & GETPORT(SIMODE0); @@ -2806,7 +3118,7 @@ static void disp_ports(struct Scsi_Host *shpnt) printk("REQINIT "); printk("); "); - printk("SXFRCTL0 ("); + printk("SXFRCTL0( "); s = GETPORT(SXFRCTL0); if (s & SCSIEN) @@ -2823,24 +3135,26 @@ static void disp_ports(struct Scsi_Host *shpnt) printk("CLRCH1 "); printk("); "); - printk("SIGNAL ("); + printk("SIGNAL( "); s = GETPORT(SCSISIG); - if (s & ATNI) + if (s & SIG_ATNI) printk("ATNI "); - if (s & SELI) + if (s & SIG_SELI) printk("SELI "); - if (s & BSYI) + if (s & SIG_BSYI) printk("BSYI "); - if (s & REQI) + if (s & SIG_REQI) printk("REQI "); - if (s & ACKI) + if (s & SIG_ACKI) printk("ACKI "); printk("); "); printk("SELID (%02x), ", GETPORT(SELID)); - printk("SSTAT2 ("); + printk("STCNT (%d), ", GETSTCNT()); + + printk("SSTAT2( "); s = GETPORT(SSTAT2); if (s & SOFFSET) @@ -2854,7 +3168,7 @@ static void disp_ports(struct Scsi_Host *shpnt) s = GETPORT(SSTAT3); printk("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f); - printk("SSTAT4 ("); + printk("SSTAT4( "); s = GETPORT(SSTAT4); if (s & SYNCERR) printk("SYNCERR "); @@ -2864,7 +3178,7 @@ static void disp_ports(struct Scsi_Host *shpnt) printk("FRERR "); printk("); "); - printk("DMACNTRL0 ("); + printk("DMACNTRL0( "); s = GETPORT(DMACNTRL0); printk("%s ", s & _8BIT ? "8BIT" : "16BIT"); printk("%s ", s & DMA ? "DMA" : "PIO"); @@ -2879,7 +3193,7 @@ static void disp_ports(struct Scsi_Host *shpnt) printk("SWINT "); printk("); "); - printk("DMASTAT ("); + printk("DMASTAT( "); s = GETPORT(DMASTAT); if (s & ATDONE) printk("ATDONE "); @@ -2889,9 +3203,7 @@ static void disp_ports(struct Scsi_Host *shpnt) printk("DFIFOFULL "); if (s & DFIFOEMP) printk("DFIFOEMP "); - printk(")"); - - printk("\n"); + printk(")\n"); #endif } @@ -2902,7 +3214,7 @@ static void disp_enintr(struct Scsi_Host *shpnt) { int s; - printk("enabled interrupts ("); + printk(KERN_DEBUG "enabled interrupts ( "); s = GETPORT(SIMODE0); if (s & ENSELDO) @@ -2938,100 +3250,38 @@ static void disp_enintr(struct Scsi_Host *shpnt) printk(")\n"); } -#if defined(DEBUG_RACE) - -static const char *should_leave; -static int in_driver = 0; - -/* - * Only one routine can be in the driver at once. - */ -static void enter_driver(const char *func) -{ - unsigned long flags; - - save_flags(flags); - cli(); - printk("aha152x: entering %s() (%x)\n", func, jiffies); - if (in_driver) { - printk("%s should leave first.\n", should_leave); - panic("aha152x: already in driver\n"); - } - in_driver++; - should_leave = func; - restore_flags(flags); -} - -static void leave_driver(const char *func) -{ - unsigned long flags; - - save_flags(flags); - cli(); - printk("\naha152x: leaving %s() (%x)\n", func, jiffies); - if (!in_driver) { - printk("aha152x: %s already left.\n", should_leave); - panic("aha152x: %s already left driver.\n"); - } - in_driver--; - should_leave = func; - restore_flags(flags); -} -#endif - /* * Show the command data of a command */ -static void show_command(Scsi_Cmnd * ptr) +static void show_command(Scsi_Cmnd *ptr) { - printk("0x%08x: target=%d; lun=%d; cmnd=(", + printk(KERN_DEBUG "0x%08x: target=%d; lun=%d; cmnd=(", (unsigned int) ptr, ptr->target, ptr->lun); print_command(ptr->cmnd); - printk("); residual=%d; buffers=%d; phase |", - ptr->SCp.this_residual, ptr->SCp.buffers_residual); + printk(KERN_DEBUG "); request_bufflen=%d; resid=%d; phase |", + ptr->request_bufflen, ptr->resid); if (ptr->SCp.phase & not_issued) printk("not issued|"); - if (ptr->SCp.phase & in_selection) - printk("in selection|"); + if (ptr->SCp.phase & selecting) + printk("selecting|"); + if (ptr->SCp.phase & identified) + printk("identified|"); if (ptr->SCp.phase & disconnected) printk("disconnected|"); + if (ptr->SCp.phase & completed) + printk("completed|"); + if (ptr->SCp.phase & spiordy) + printk("spiordy|"); + if (ptr->SCp.phase & syncneg) + printk("syncneg|"); if (ptr->SCp.phase & aborted) printk("aborted|"); - if (ptr->SCp.phase & sent_ident) - printk("send_ident|"); - if (ptr->SCp.phase & in_other) { - printk("; in other("); - switch ((ptr->SCp.phase >> 16) & P_MASK) { - case P_DATAO: - printk("DATA OUT"); - break; - case P_DATAI: - printk("DATA IN"); - break; - case P_CMD: - printk("COMMAND"); - break; - case P_STATUS: - printk("STATUS"); - break; - case P_MSGO: - printk("MESSAGE OUT"); - break; - case P_MSGI: - printk("MESSAGE IN"); - break; - default: - printk("*illegal*"); - break; - } - printk(")"); - if (ptr->SCp.phase & (1 << 16)) - printk("; phaseend"); - } - printk("; next=0x%08x\n", (unsigned int) ptr->host_scribble); + if (ptr->SCp.phase & resetted) + printk("resetted|"); + printk("; next=0x%p\n", SCNEXT(ptr)); } /* @@ -3039,33 +3289,27 @@ static void show_command(Scsi_Cmnd * ptr) */ static void show_queues(struct Scsi_Host *shpnt) { - unsigned long flags; Scsi_Cmnd *ptr; + unsigned long flags; - save_flags(flags); - cli(); - printk("QUEUE STATUS:\nissue_SC:\n"); - for (ptr = ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + DO_LOCK(flags); + printk(KERN_DEBUG "\nqueue status:\nissue_SC:\n"); + for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr)) show_command(ptr); + DO_UNLOCK(flags); - printk("current_SC:\n"); + printk(KERN_DEBUG "current_SC:\n"); if (CURRENT_SC) show_command(CURRENT_SC); else - printk("none\n"); + printk(KERN_DEBUG "none\n"); - printk("disconnected_SC:\n"); - for (ptr = DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + printk(KERN_DEBUG "disconnected_SC:\n"); + for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr)) show_command(ptr); disp_ports(shpnt); disp_enintr(shpnt); - restore_flags(flags); -} - -int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt) -{ - return (-ENOSYS); /* Currently this is a no-op */ } #undef SPRINTF @@ -3082,49 +3326,26 @@ static int get_command(char *pos, Scsi_Cmnd * ptr) for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++) SPRINTF("0x%02x ", ptr->cmnd[i]); - SPRINTF("); residual=%d; buffers=%d; phase |", - ptr->SCp.this_residual, ptr->SCp.buffers_residual); + SPRINTF("); resid=%d; residual=%d; buffers=%d; phase |", + ptr->resid, ptr->SCp.this_residual, ptr->SCp.buffers_residual); if (ptr->SCp.phase & not_issued) SPRINTF("not issued|"); - if (ptr->SCp.phase & in_selection) - SPRINTF("in selection|"); + if (ptr->SCp.phase & selecting) + SPRINTF("selecting|"); if (ptr->SCp.phase & disconnected) SPRINTF("disconnected|"); if (ptr->SCp.phase & aborted) SPRINTF("aborted|"); - if (ptr->SCp.phase & sent_ident) - SPRINTF("send_ident|"); - if (ptr->SCp.phase & in_other) { - SPRINTF("; in other("); - switch ((ptr->SCp.phase >> 16) & P_MASK) { - case P_DATAO: - SPRINTF("DATA OUT"); - break; - case P_DATAI: - SPRINTF("DATA IN"); - break; - case P_CMD: - SPRINTF("COMMAND"); - break; - case P_STATUS: - SPRINTF("STATUS"); - break; - case P_MSGO: - SPRINTF("MESSAGE OUT"); - break; - case P_MSGI: - SPRINTF("MESSAGE IN"); - break; - default: - SPRINTF("*illegal*"); - break; - } - SPRINTF(")"); - if (ptr->SCp.phase & (1 << 16)) - SPRINTF("; phaseend"); - } - SPRINTF("; next=0x%08x\n", (unsigned int) ptr->host_scribble); + if (ptr->SCp.phase & identified) + SPRINTF("identified|"); + if (ptr->SCp.phase & completed) + SPRINTF("completed|"); + if (ptr->SCp.phase & spiordy) + SPRINTF("spiordy|"); + if (ptr->SCp.phase & syncneg) + SPRINTF("syncneg|"); + SPRINTF("; next=0x%p\n", SCNEXT(ptr)); return (pos - start); } @@ -3134,15 +3355,10 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos) char *start = pos; int s; -#ifdef SKIP_PORTS - if (HOSTDATA(shpnt)->debug & debug_skipports) - return; -#endif - - SPRINTF("\n%s: ", CURRENT_SC ? "on bus" : "waiting"); + SPRINTF("\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name); s = GETPORT(SCSISEQ); - SPRINTF("SCSISEQ ("); + SPRINTF("SCSISEQ( "); if (s & TEMODEO) SPRINTF("TARGET MODE "); if (s & ENSELO) @@ -3161,7 +3377,7 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos) SPRINTF("SCSIRSTO "); SPRINTF(");"); - SPRINTF(" SCSISIG ("); + SPRINTF(" SCSISIG("); s = GETPORT(SCSISIG); switch (s & P_MASK) { case P_DATAO: @@ -3191,7 +3407,7 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos) SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); - SPRINTF("SSTAT ("); + SPRINTF("SSTAT( "); s = GETPORT(SSTAT0); if (s & TARGET) SPRINTF("TARGET "); @@ -3230,7 +3446,7 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos) SPRINTF("); "); - SPRINTF("SSTAT ("); + SPRINTF("SSTAT( "); s = GETPORT(SSTAT0) & GETPORT(SIMODE0); @@ -3271,7 +3487,7 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos) SPRINTF("REQINIT "); SPRINTF("); "); - SPRINTF("SXFRCTL0 ("); + SPRINTF("SXFRCTL0( "); s = GETPORT(SXFRCTL0); if (s & SCSIEN) @@ -3288,24 +3504,26 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos) SPRINTF("CLRCH1 "); SPRINTF("); "); - SPRINTF("SIGNAL ("); + SPRINTF("SIGNAL( "); s = GETPORT(SCSISIG); - if (s & ATNI) + if (s & SIG_ATNI) SPRINTF("ATNI "); - if (s & SELI) + if (s & SIG_SELI) SPRINTF("SELI "); - if (s & BSYI) + if (s & SIG_BSYI) SPRINTF("BSYI "); - if (s & REQI) + if (s & SIG_REQI) SPRINTF("REQI "); - if (s & ACKI) + if (s & SIG_ACKI) SPRINTF("ACKI "); SPRINTF("); "); - SPRINTF("SELID (%02x), ", GETPORT(SELID)); + SPRINTF("SELID(%02x), ", GETPORT(SELID)); - SPRINTF("SSTAT2 ("); + SPRINTF("STCNT(%d), ", GETSTCNT()); + + SPRINTF("SSTAT2( "); s = GETPORT(SSTAT2); if (s & SOFFSET) @@ -3319,7 +3537,7 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos) s = GETPORT(SSTAT3); SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f); - SPRINTF("SSTAT4 ("); + SPRINTF("SSTAT4( "); s = GETPORT(SSTAT4); if (s & SYNCERR) SPRINTF("SYNCERR "); @@ -3329,7 +3547,7 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos) SPRINTF("FRERR "); SPRINTF("); "); - SPRINTF("DMACNTRL0 ("); + SPRINTF("DMACNTRL0( "); s = GETPORT(DMACNTRL0); SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT"); SPRINTF("%s ", s & DMA ? "DMA" : "PIO"); @@ -3344,7 +3562,7 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos) SPRINTF("SWINT "); SPRINTF("); "); - SPRINTF("DMASTAT ("); + SPRINTF("DMASTAT( "); s = GETPORT(DMASTAT); if (s & ATDONE) SPRINTF("ATDONE "); @@ -3354,9 +3572,9 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos) SPRINTF("DFIFOFULL "); if (s & DFIFOEMP) SPRINTF("DFIFOEMP "); - SPRINTF(")\n\n"); + SPRINTF(")\n"); - SPRINTF("enabled interrupts ("); + SPRINTF("enabled interrupts( "); s = GETPORT(SIMODE0); if (s & ENSELDO) @@ -3394,8 +3612,52 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos) return (pos - start); } +int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt) +{ + if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0) + return -EINVAL; + +#if defined(AHA152X_DEBUG) + if(length>14 && strncmp("debug ", buffer+8, 6)==0) { + int debug = HOSTDATA(shpnt)->debug; + + HOSTDATA(shpnt)->debug = simple_strtoul(buffer+14, NULL, 0); + + printk(KERN_INFO "aha152x%d: debugging options set to 0x%04x (were 0x%04x)\n", HOSTNO, HOSTDATA(shpnt)->debug, debug); + } else +#endif +#if defined(AHA152X_STAT) + if(length>13 && strncmp("reset", buffer+8, 5)==0) { + int i; + + HOSTDATA(shpnt)->total_commands=0; + HOSTDATA(shpnt)->disconnections=0; + HOSTDATA(shpnt)->busfree_without_any_action=0; + HOSTDATA(shpnt)->busfree_without_old_command=0; + HOSTDATA(shpnt)->busfree_without_new_command=0; + HOSTDATA(shpnt)->busfree_without_done_command=0; + HOSTDATA(shpnt)->busfree_with_check_condition=0; + for (i = idle; i<maxstate; i++) { + HOSTDATA(shpnt)->count[i]=0; + HOSTDATA(shpnt)->count_trans[i]=0; + HOSTDATA(shpnt)->time[i]=0; + } + + printk(KERN_INFO "aha152x%d: stats reseted.\n", HOSTNO); + + } else +#endif + { + return -EINVAL; + } + + + return length; +} + #undef SPRINTF -#define SPRINTF(args...) do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0) +#define SPRINTF(args...) \ + do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0) int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) @@ -3403,48 +3665,39 @@ int aha152x_proc_info(char *buffer, char **start, int i; char *pos = buffer; struct Scsi_Host *shpnt; - unsigned long flags; Scsi_Cmnd *ptr; + unsigned long flags; + int thislength; for (i = 0, shpnt = (struct Scsi_Host *) NULL; i < IRQS; i++) if (aha152x_host[i] && aha152x_host[i]->host_no == hostno) shpnt = aha152x_host[i]; if (!shpnt) - return (-ESRCH); + return -ESRCH; - if (inout) /* Has data been written to the file ? */ - return (aha152x_set_info(buffer, length, shpnt)); + DPRINTK(debug_procinfo, + KERN_DEBUG "aha152x_proc_info: buffer=%p offset=%ld length=%d hostno=%d inout=%d\n", + buffer, offset, length, hostno, inout); - SPRINTF(AHA152X_REVID "\n"); - save_flags(flags); - cli(); + if (inout) + return aha152x_set_info(buffer, length, shpnt); + + SPRINTF(AHA152X_REVID "\n"); SPRINTF("ioports 0x%04lx to 0x%04lx\n", shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1); SPRINTF("interrupt 0x%02x\n", shpnt->irq); SPRINTF("disconnection/reconnection %s\n", - HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled"); + RECONNECT ? "enabled" : "disabled"); SPRINTF("parity checking %s\n", - HOSTDATA(shpnt)->parity ? "enabled" : "disabled"); + PARITY ? "enabled" : "disabled"); SPRINTF("synchronous transfers %s\n", - HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled"); + SYNCHRONOUS ? "enabled" : "disabled"); SPRINTF("%d commands currently queued\n", HOSTDATA(shpnt)->commands); - if (HOSTDATA(shpnt)->synchronous) { -#if 0 - SPRINTF("synchronously operating targets (tick=%ld ns):\n", - 250000000 / loops_per_sec); - for (i = 0; i < 8; i++) - if (HOSTDATA(shpnt)->syncrate[i] & 0x7f) - SPRINTF("target %d: period %dT/%ldns; req/ack offset %d\n", - i, - (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2), - (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * - 250000000 / loops_per_sec, - HOSTDATA(shpnt)->syncrate[i] & 0x0f); -#else + if(SYNCHRONOUS) { SPRINTF("synchronously operating targets (tick=50 ns):\n"); for (i = 0; i < 8; i++) if (HOSTDATA(shpnt)->syncrate[i] & 0x7f) @@ -3453,14 +3706,14 @@ int aha152x_proc_info(char *buffer, char **start, (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2), (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50, HOSTDATA(shpnt)->syncrate[i] & 0x0f); -#endif } -#ifdef DEBUG_AHA152X -#define PDEBUG(flags,txt) if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt); +#if defined(AHA152X_DEBUG) +#define PDEBUG(flags,txt) \ + if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt); SPRINTF("enabled debugging options: "); - PDEBUG(debug_skipports, "skip ports"); + PDEBUG(debug_procinfo, "procinfo"); PDEBUG(debug_queue, "queue"); PDEBUG(debug_intr, "interrupt"); PDEBUG(debug_selection, "selection"); @@ -3470,23 +3723,22 @@ int aha152x_proc_info(char *buffer, char **start, PDEBUG(debug_cmd, "command"); PDEBUG(debug_datai, "data in"); PDEBUG(debug_datao, "data out"); - PDEBUG(debug_abort, "abort"); - PDEBUG(debug_done, "done"); - PDEBUG(debug_biosparam, "bios parameters"); + PDEBUG(debug_eh, "eh"); + PDEBUG(debug_locks, "locks"); PDEBUG(debug_phases, "phases"); - PDEBUG(debug_queues, "queues"); - PDEBUG(debug_reset, "reset"); SPRINTF("\n"); #endif SPRINTF("\nqueue status:\n"); + DO_LOCK(flags); if (ISSUE_SC) { SPRINTF("not yet issued commands:\n"); - for (ptr = ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr)) pos += get_command(pos, ptr); } else SPRINTF("no not yet issued commands\n"); + DO_UNLOCK(flags); if (CURRENT_SC) { SPRINTF("current command:\n"); @@ -3496,25 +3748,62 @@ int aha152x_proc_info(char *buffer, char **start, if (DISCONNECTED_SC) { SPRINTF("disconnected commands:\n"); - for (ptr = DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr)) pos += get_command(pos, ptr); } else SPRINTF("no disconnected commands\n"); - restore_flags(flags); - pos += get_ports(shpnt, pos); - *start = buffer + offset; - if (pos - buffer < offset) +#if defined(AHA152X_STAT) + SPRINTF("statistics:\n" + "total commands: %d\n" + "disconnections: %d\n" + "busfree with check condition: %d\n" + "busfree without old command: %d\n" + "busfree without new command: %d\n" + "busfree without done command: %d\n" + "busfree without any action: %d\n" + "state " + "transitions " + "count " + "time\n", + HOSTDATA(shpnt)->total_commands, + HOSTDATA(shpnt)->disconnections, + HOSTDATA(shpnt)->busfree_with_check_condition, + HOSTDATA(shpnt)->busfree_without_old_command, + HOSTDATA(shpnt)->busfree_without_new_command, + HOSTDATA(shpnt)->busfree_without_done_command, + HOSTDATA(shpnt)->busfree_without_any_action); + for(i=0; i<maxstate; i++) { + SPRINTF("%-10s %-12d %-12d %-12ld\n", + states[i].name, + HOSTDATA(shpnt)->count_trans[i], + HOSTDATA(shpnt)->count[i], + HOSTDATA(shpnt)->time[i]); + } +#endif + + DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: pos=%p\n", pos); + + thislength = pos - (buffer + offset); + DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: length=%d thislength=%d\n", length, thislength); + + if(thislength<0) { + DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: output too short\n"); + *start = 0; return 0; - else if (pos - buffer - offset < length) - return pos - buffer - offset; - else - return length; + } + + thislength = thislength<length ? thislength : length; + + DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: return %d\n", thislength); + + *start = buffer + offset; + return thislength < length ? thislength : length; } -#ifdef MODULE +#if defined(MODULE) /* Eventually this will go into an include file, but this will be later */ Scsi_Host_Template driver_template = AHA152X; |