patch-2.3.36 linux/drivers/scsi/aha152x.c
Next file: linux/drivers/scsi/aha152x.h
Previous file: linux/drivers/scsi/advansys.h
Back to the patch index
Back to the overall index
- Lines: 5108
- Date:
Wed Dec 29 17:16:30 1999
- Orig file:
v2.3.35/linux/drivers/scsi/aha152x.c
- Orig date:
Tue Nov 23 22:42:21 1999
diff -u --recursive --new-file v2.3.35/linux/drivers/scsi/aha152x.c linux/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)
+#if defined(AHA152X_DEBUG)
+#define DEBUG_DEFAULT debug_eh
-#endif
+#define DPRINTK(when,msgs...) \
+ do { if(HOSTDATA(shpnt)->debug & (when)) printk(msgs); } while(0)
-/* END OF DEFINES */
+#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 @@
#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 @@
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 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 */
+
+ spinlock_t lock;
+ /* host lock */
- int swint;
- int service;
+#if defined(AHA152X_DEBUG)
+ char *locker; /* which function has the lock */
+ int lockerl; /* where did it get it */
+
+ int debug; /* current debugging setting */
+#endif
+
+#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 message[256];
- int message_len;
+ 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 */
-#ifdef DEBUG_AHA152X
- int debug;
-#endif
+ 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 @@
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 @@
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");
+ 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] : 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;
+ 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 @@
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);
+}
+
+static int tc1550_porttest(int io_port)
+{
+ int 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);
}
-int aha152x_checksetup(struct aha152x_setup *setup)
+static int checksetup(struct aha152x_setup *setup)
{
int i;
-#ifndef PCMCIA
- for (i = 0; i < PORT_COUNT && (setup->io_port != ports[i]); 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 @@
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 @@
#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 @@
}
#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 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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;
+ 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 = (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
+ 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 @@
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);
-
- 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,
+#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
+
+ 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 @@
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,60 +1307,114 @@
}
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");
- }
- }
-
- return (registered_count > 0);
-}
-
+ 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;
+}
+
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 @@
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);
+
+ /*
+ * FIXME:
+ * for current command: queue ABORT for message out and raise ATN
+ * for disconnected command: pseudo SC with ABORT message or ABORT on reselection?
+ *
+ */
- if (!CURRENT_SC)
- printk("bus busy w/o current command, ");
+ printk(ERR_LEAD "cannot abort running or disconnected command\n", CMDINFO(SCpnt));
- restore_flags(flags);
+ return FAILED;
+}
- return SCSI_ABORT_BUSY;
- }
- /* bus is free */
+static void timer_expired(unsigned long p)
+{
+ struct semaphore *sem = (void *)p;
- if (CURRENT_SC) {
- HOSTDATA(shpnt)->commands--;
+ printk(KERN_INFO "aha152x: timer expired\n");
+ up(sem);
+}
- /* 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);
-
- 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);
-
- if (!ptr) {
- /* command wasn't found */
- printk("command not found\n");
- restore_flags(flags);
+/*
+ * 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 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 @@
SETPORT(SXFRCTL1, 0);
SETPORT(SCSISIG, 0);
- SETPORT(SCSIRATE, 0);
+ SETRATE(0);
/* clear all interrupt conditions */
SETPORT(SSTAT0, 0x7f);
@@ -1377,106 +1701,41 @@
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 @@
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 @@
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();
+ if(DONE_SC)
+ printk(ERR_LEAD "there's already a completed command %p - will cause abort\n", CMDINFO(CURRENT_SC), DONE_SC);
- done_SC = CURRENT_SC;
- CURRENT_SC = NULL;
-
- /* 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;
+ SETPORT(SSTAT1, CLRBUSFREE);
+
+ if(CURRENT_SC) {
+#if defined(AHA152X_STAT)
+ action++;
+#endif
+ CURRENT_SC->SCp.phase &= ~syncneg;
+
+ 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));
+
+ } 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));
+
+ } 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));
+
+ } 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
+ append_SC(&DISCONNECTED_SC, CURRENT_SC);
+ CURRENT_SC->SCp.phase |= 1 << 16;
+ CURRENT_SC = 0;
- /* 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);
+ } else {
+ done(shpnt, DID_ERROR << 16);
}
- /* 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, ");
+#if defined(AHA152X_STAT)
+ } else {
+ HOSTDATA(shpnt)->busfree_without_old_command++;
#endif
+ }
- i = GETPORT(SELID) & ~(1 << shpnt->this_id);
- target = 0;
+ DO_LOCK(flags);
- if (i == 0)
- aha152x_panic(shpnt, "reconnecting target unknown");
+ if(DONE_SC) {
+#if defined(AHA152X_STAT)
+ action++;
+#endif
+ if(SCDONE(DONE_SC)) {
+ Scsi_Cmnd *ptr=DONE_SC;
+ DONE_SC=SCDONE(DONE_SC);
- for (; (i & 1) == 0; target++, i >>= 1);
+#if 0
+ if(HOSTDATA(shpnt)->debug & debug_eh) {
+ printk(ERR_LEAD "received sense: ", CMDINFO(ptr));
+ print_sense("bh", DONE_SC);
+ }
+#endif
-#if defined(DEBUG_QUEUES)
- if (HOSTDATA(shpnt)->debug & debug_queues)
- printk("SELID=%02x, target=%d, ", GETPORT(SELID), target);
+ 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
+#if 0
+ DPRINTK(debug_eh, ERR_LEAD "CHECK CONDITION found\n", CMDINFO(DONE_SC));
#endif
- SETPORT(SCSIID, (shpnt->this_id << OID_) | target);
- SETPORT(SCSISEQ, ENRESELI);
- if (TESTLO(SSTAT0, SELDI))
- aha152x_panic(shpnt, "RESELI failed");
+ if(!(DONE_SC->SCp.Status & not_issued)) {
+ Scsi_Cmnd *cmnd = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
- SETPORT(SCSIRATE, HOSTDATA(shpnt)->syncrate[target] & 0x7f);
+ if(cmnd) {
+ Scsi_Cmnd *ptr=DONE_SC;
+ DONE_SC=0;
- SETPORT(SCSISIG, P_MSGI);
+#if 0
+ DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr));
+#endif
- /* 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");
+ 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
+ }
}
- SETPORT(SCSISEQ, 0);
-
- SETPORT(SXFRCTL0, CH1);
- identify_msg = GETPORT(SCSIBUS);
-
- if (!(identify_msg & IDENTIFY_BASE)) {
- printk("target=%d, inbound message (%02x) != IDENTIFY\n",
- target, identify_msg);
- aha152x_panic(shpnt, "unknown lun");
+ 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 */
+
+ kfree(DONE_SC->host_scribble);
+ DONE_SC->host_scribble=0;
+
+ 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_QUEUES)
- if (HOSTDATA(shpnt)->debug & debug_queues)
- printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f);
+
+ DONE_SC=0;
+#if defined(AHA152X_STAT)
+ } else {
+ HOSTDATA(shpnt)->busfree_without_done_command++;
#endif
+ }
+
+ if(ISSUE_SC)
+ CURRENT_SC = remove_first_SC(&ISSUE_SC);
- save_flags(flags);
- cli();
+ DO_UNLOCK(flags);
-#if defined(DEBUG_QUEUES)
- if (HOSTDATA(shpnt)->debug & debug_queues)
- printk("d-, ");
+ if(CURRENT_SC) {
+#if defined(AHA152X_STAT)
+ action++;
#endif
- CURRENT_SC = remove_SC(&DISCONNECTED_SC, target, identify_msg & 0x3f);
+ CURRENT_SC->SCp.phase |= selecting;
- 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);
+ DPRINTK(debug_selection, DEBUG_LEAD "selecting target\n", CMDINFO(CURRENT_SC));
- make_acklow(shpnt);
- if (getphase(shpnt) != P_MSGI) {
- SETPORT(SIMODE0, 0);
- SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
-#if defined(DEBUG_RACE)
- leave_driver("(reselected) intr");
+ /* clear selection timeout */
+ SETPORT(SSTAT1, SELTO);
+
+ 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);
- return;
- }
+ SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
}
- /* 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-, ");
-#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 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);
+
+#if defined(AHA152X_STAT)
+ if(!action)
+ HOSTDATA(shpnt)->busfree_without_any_action++;
#endif
- SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target);
+}
- /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */
- SETPORT(SXFRCTL1, HOSTDATA(shpnt)->parity ? (ENSPCHK | ENSTIMER) : ENSTIMER);
+/*
+ * 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);
- /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
- SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
- SETPORT(SIMODE1, ENSELTIMO);
+ CURRENT_SC->SCp.phase &= ~(selecting|not_issued);
- /* Enable SELECTION OUT sequence */
- SETBITS(SCSISEQ, ENSELO | ENAUTOATNO);
+ SETPORT(SCSISEQ, 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);
- }
+ if (TESTLO(SSTAT0, SELDO)) {
+ printk(ERR_LEAD "aha152x: passing bus free condition\n", CMDINFO(CURRENT_SC));
+ done(shpnt, DID_NO_CONNECT << 16);
+ return;
+ }
-#if defined(DEBUG_RACE)
- leave_driver("(selecting) intr");
-#endif
- SETBITS(DMACNTRL0, INTEN);
+ 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 */
+ }
+
+ SETRATE(SYNCRATE);
+}
+
+/*
+ * Selection timeout
+ * - return command to mid-level with failure cause
+ *
+ */
+static void selto_run(struct Scsi_Host *shpnt)
+{
+ SETPORT(SCSISEQ, 0);
+ SETPORT(SSTAT1, CLRSELTIMO);
+
+ DPRINTK(debug_selection, DEBUG_LEAD "selection timeout\n", CMDINFO(CURRENT_SC));
+
+ if(!CURRENT_SC) {
+ DPRINTK(debug_selection, DEBUG_LEAD "!CURRENT_SC\n", CMDINFO(CURRENT_SC));
return;
}
- /* the bus is busy with something */
-#if defined(DEBUG_INTR)
- if (HOSTDATA(shpnt)->debug & debug_intr)
- disp_ports(shpnt);
-#endif
+ CURRENT_SC->SCp.phase &= ~selecting;
- /* 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);
-
- /* Disable SELECTION OUT sequence */
- CLRBITS(SCSISEQ, ENSELO | ENAUTOATNO);
-
- /* Disable SELECTION OUT DONE interrupt */
- CLRBITS(SIMODE0, ENSELDO);
- CLRBITS(SIMODE1, ENSELTIMO);
-
- if (TESTLO(SSTAT0, SELDO)) {
- printk("aha152x: passing bus free condition\n");
-
-#if defined(DEBUG_RACE)
- leave_driver("(passing bus free) intr");
-#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);
+ 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);
+ }
+}
- return;
- }
-#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases))
- printk("SELDO (SELID=%x), ", GETPORT(SELID));
-#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;
- /* selection was done */
- SETPORT(SSTAT0, CLRSELDO);
+ SETPORT(SCSISIG, 0);
+ SETPORT(SSTAT0, CLRSELDI);
+ 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
+ if(CURRENT_SC) {
+ if(!(CURRENT_SC->SCp.phase & not_issued))
+ printk(ERR_LEAD "command should not have been issued yet\n", CMDINFO(CURRENT_SC));
- CURRENT_SC->SCp.phase &= ~in_selection;
- CURRENT_SC->SCp.phase |= in_other;
+ DPRINTK(debug_selection, ERR_LEAD "command requeued - reselection\n", CMDINFO(CURRENT_SC));
- ADDMSG(IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun));
+ DO_LOCK(flags);
+ append_SC(&ISSUE_SC, CURRENT_SC);
+ DO_UNLOCK(flags);
- if (!(SYNCRATE & 0x80) && HOSTDATA(shpnt)->synchronous) {
- ADDMSG(EXTENDED_MESSAGE);
- ADDMSG(3);
- ADDMSG(EXTENDED_SDTR);
- ADDMSG(50);
- ADDMSG(8);
+ CURRENT_SC = 0;
+ }
- printk("outbound SDTR: ");
- print_msg(&MSG(MSGLEN - 5));
+ if(!DISCONNECTED_SC) {
+ DPRINTK(debug_selection, DEBUG_LEAD "unexpected SELDI ", CMDINFO(CURRENT_SC));
+ return;
+ }
- SYNCRATE = 0x80;
- CURRENT_SC->SCp.phase |= in_sync;
- }
-#if defined(DEBUG_RACE)
- leave_driver("(SELDO) intr");
-#endif
- SETPORT(SCSIRATE, SYNCRATE & 0x7f);
+ RECONN_TARGET=-1;
- SETPORT(SCSISIG, P_MSGO);
+ selid = GETPORT(SELID) & ~(1 << shpnt->this_id);
- SETPORT(SIMODE0, 0);
- SETPORT(SIMODE1, ENREQINIT | ENBUSFREE);
- SETBITS(DMACNTRL0, INTEN);
+ if (selid==0) {
+ printk("aha152x%d: target id unknown (%02x)\n", HOSTNO, selid);
+ 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);
-
- /* timeout */
- SETPORT(SSTAT1, CLRSELTIMO);
-
- SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
- SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
- SETBITS(DMACNTRL0, INTEN);
-#if defined(DEBUG_RACE)
- leave_driver("(SELTO) intr");
-#endif
-
- 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);
+ for(target=7; !(selid & (1 << target)); target--)
+ ;
- return;
- }
+ if(selid & ~(1 << target)) {
+ printk("aha152x%d: multiple targets reconnected (%02x)\n",
+ HOSTNO, selid);
}
- /* 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, ");
+
+ SETPORT(SCSIID, (shpnt->this_id << OID_) | target);
+ SETPORT(SCSISEQ, 0);
+
+ SETRATE(HOSTDATA(shpnt)->syncrate[target]);
+
+ 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(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT))
+ return;
+
+ if(TESTLO(SSTAT0,SPIORDY)) {
+ DPRINTK(debug_msgi, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+ return;
+ }
+
+ ADDMSGI(GETPORT(SCSIDAT));
+
+#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
+
+ if(!CURRENT_SC) {
+ if(LASTSTATE!=seldi) {
+ printk(KERN_ERR "aha152x%d: message in w/o current command not after reselection\n", HOSTNO);
}
- CLRBITS(SXFRCTL0, ENDMA);
- SETPORT(SIMODE0, 0);
- SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE);
+ /*
+ * Handle reselection
+ */
+ if(!(MSGI(0) & IDENTIFY_BASE)) {
+ printk(KERN_ERR "aha152x%d: target didn't identify after reselection\n", HOSTNO);
+ continue;
+ }
- /* wait for data latch to become ready or a phase change */
- while (TESTLO(DMASTAT, INTSTAT))
- barrier();
+ CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f);
-#if defined(DEBUG_MSGO)
- if (HOSTDATA(shpnt)->debug & debug_msgo) {
- int i;
-
- printk("messages (");
- for (i = 0; i < MSGLEN; i += print_msg(&MSG(i)), printk(" "));
- printk("), ");
+ 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;
}
-#endif
- 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));
+ DPRINTK(debug_msgi, DEBUG_LEAD "target reconnected\n", CMDINFO(CURRENT_SC));
- make_acklow(shpnt);
- getphase(shpnt);
+ CURRENT_SC->SCp.Message = MSGI(0);
+ CURRENT_SC->SCp.phase &= ~disconnected;
- if (MSG(i) == IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun))
- identify++;
+ MSGILEN=0;
- if (MSG(i) == ABORT)
- abort++;
+ /* next message if any */
+ continue;
+ }
- }
+ CURRENT_SC->SCp.Message = MSGI(0);
- MSGLEN = 0;
+ switch (MSGI(0)) {
+ case DISCONNECT:
+ if (!RECONNECT)
+ printk(WARN_LEAD "target was not allowed to disconnect\n", CMDINFO(CURRENT_SC));
- if (identify)
- CURRENT_SC->SCp.phase |= sent_ident;
+ CURRENT_SC->SCp.phase |= disconnected;
+ break;
- if (abort) {
- /* revive abort(); abort() enables interrupts */
- HOSTDATA(shpnt)->abort_result = SCSI_ABORT_SUCCESS;
- HOSTDATA(shpnt)->abortion_complete++;
+ case COMMAND_COMPLETE:
+ if(CURRENT_SC->SCp.phase & completed)
+ DPRINTK(debug_msgi, DEBUG_LEAD "again COMMAND COMPLETE\n", CMDINFO(CURRENT_SC));
- CURRENT_SC->SCp.phase &= ~(P_MASK << 16);
+ CURRENT_SC->SCp.phase |= completed;
+ break;
- /* exit */
- SETBITS(DMACNTRL0, INTEN);
-#if defined(DEBUG_RACE)
- leave_driver("(ABORT) intr");
-#endif
- aha152x_done(shpnt, DID_ABORT << 16);
+ 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;
- return;
- }
- }
- break;
+ case SAVE_POINTERS:
+ 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;
+ case RESTORE_POINTERS:
+ break;
- CLRBITS(SXFRCTL0, ENDMA);
+ case EXTENDED_MESSAGE:
+ if(MSGILEN<2 || MSGILEN<MSGI(1)+2) {
+ /* not yet completed */
+ continue;
+ }
- SETPORT(SIMODE0, 0);
- SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE);
+ switch (MSGI(2)) {
+ case EXTENDED_SDTR:
+ {
+ long ticks;
+
+ if (MSGI(1) != 3) {
+ printk(ERR_LEAD "SDTR message length!=3\n", CMDINFO(CURRENT_SC));
+ break;
+ }
- /* wait for data latch to become ready or a phase change */
- while (TESTLO(DMASTAT, INTSTAT))
- barrier();
+ if (!HOSTDATA(shpnt)->synchronous)
+ break;
- for (i = 0; i < CURRENT_SC->cmd_len && TESTLO(SSTAT1, PHASEMIS); i++) {
- SETPORT(SCSIDAT, CURRENT_SC->cmnd[i]);
+ printk(INFO_LEAD, CMDINFO(CURRENT_SC));
+ print_msg(&MSGI(0));
+ printk("\n");
+
+ ticks = (MSGI(3) * 4 + 49) / 50;
+
+ 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);
+ }
- make_acklow(shpnt);
- getphase(shpnt);
- }
+ SYNCNEG=2; /* negotiation completed */
+ SETRATE(SYNCRATE);
+ }
+ break;
- if (i < CURRENT_SC->cmd_len && TESTHI(SSTAT1, PHASEMIS))
- aha152x_panic(shpnt, "target left COMMAND");
+ case BUS_DEVICE_RESET:
+ {
+ int i;
+
+ for(i=0; i<8; i++) {
+ HOSTDATA(shpnt)->syncrate[i]=0;
+ HOSTDATA(shpnt)->syncneg[i]=0;
+ }
- CURRENT_SC->SCp.sent_command++;
- } else
- aha152x_panic(shpnt, "Nothing to send while in COMMAND");
- break;
+ }
+ break;
- case P_MSGI: /* MESSAGE IN phase */
- {
- int start_sync = 0;
-
-#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);
+ case EXTENDED_MODIFY_DATA_POINTER:
+ case EXTENDED_EXTENDED_IDENTIFY:
+ case EXTENDED_WDTR:
+ default:
+ ADDMSGO(MESSAGE_REJECT);
+ break;
+ }
+ break;
+ }
- SETPORT(SIMODE0, 0);
- SETPORT(SIMODE1, ENBUSFREE);
+ MSGILEN=0;
+ }
+}
- 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");
-
- 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:
-#if defined(DEBUG_MSGI)
- if (HOSTDATA(shpnt)->debug & debug_msgi)
- printk("inbound message (SAVE DATA POINTERS), ");
-#endif
- 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:
- {
- char buffer[16];
- int i;
-
-#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;
+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);
+
+ if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE)) {
+ DPRINTK(debug_msgi, DEBUG_LEAD "msgo pending\n", CMDINFO(CURRENT_SC));
+ SETPORT(SCSISIG, P_MSGI | SIG_ATNO);
+ }
+}
- buffer[0] = EXTENDED_MESSAGE;
- buffer[1] = GETPORT(SCSIDAT);
+/*
+ * 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);
+ }
+ }
- for (i = 0; i < buffer[1] &&
- (make_acklow(shpnt), getphase(shpnt) == P_MSGI); i++)
- buffer[2 + i] = GETPORT(SCSIDAT);
+#if defined(AHA152X_DEBUG)
+ if(HOSTDATA(shpnt)->debug & debug_msgo) {
+ int i;
-#if defined(DEBUG_MSGI)
- if (HOSTDATA(shpnt)->debug & debug_msgi)
- print_msg(buffer);
+ printk(DEBUG_LEAD "messages( ", CMDINFO(CURRENT_SC));
+ for (i=0; i<MSGOLEN; i+=print_msg(&MSGO(i)), printk(" "))
+ ;
+ printk(")\n");
+ }
#endif
+}
- switch (buffer[2]) {
- case EXTENDED_SDTR:
- {
- long ticks;
-
- if (buffer[1] != 3)
- aha152x_panic(shpnt, "SDTR message length != 3");
+/*
+ * 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);
- if (!HOSTDATA(shpnt)->synchronous)
- break;
+ while(MSGO_I<MSGOLEN) {
+ DPRINTK(debug_msgo, DEBUG_LEAD "message byte %02x (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO(MSGO_I), MSGO_I, MSGOLEN);
- printk("inbound SDTR: ");
- print_msg(buffer);
+ if(TESTLO(SSTAT0, SPIORDY)) {
+ DPRINTK(debug_msgo, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+ return;
+ }
- ticks = (buffer[3] * 4 + 49) / 50;
+ if (MSGO_I==MSGOLEN-1) {
+ /* Leave MESSAGE OUT after transfer */
+ SETPORT(SSTAT1, CLRATNO);
+ }
- 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");
- SYNCRATE |= ((ticks - 2) << 4) + buffer[4];
- } else if (ticks <= 9 && buffer[4] >= 1) {
- if (buffer[4] > 8)
- buffer[4] = 8;
+ if (MSGO(MSGO_I) & IDENTIFY_BASE)
+ CURRENT_SC->SCp.phase |= identified;
- ADDMSG(EXTENDED_MESSAGE);
- ADDMSG(3);
- ADDMSG(EXTENDED_SDTR);
- if (ticks < 4) {
- ticks = 4;
- ADDMSG(50);
- } else
- ADDMSG(buffer[3]);
+ if (MSGO(MSGO_I)==ABORT)
+ CURRENT_SC->SCp.phase |= aborted;
- ADDMSG(buffer[4]);
+ if (MSGO(MSGO_I)==BUS_DEVICE_RESET)
+ CURRENT_SC->SCp.phase |= resetted;
- printk("outbound SDTR: ");
- print_msg(&MSG(MSGLEN - 5));
+ SETPORT(SCSIDAT, MSGO(MSGO_I++));
+ }
+}
- CURRENT_SC->SCp.phase |= in_sync;
+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;
+}
- SYNCRATE |= ((ticks - 2) << 4) + buffer[4];
+/*
+ * 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;
+ }
- start_sync++;
- } else {
- /* requested SDTR is too slow, do it asynchronously */
- ADDMSG(MESSAGE_REJECT);
- SYNCRATE = 0;
- }
+#if defined(AHA152X_DEBUG)
+ if (HOSTDATA(shpnt)->debug & debug_cmd) {
+ printk(DEBUG_LEAD "cmd_init: ", CMDINFO(CURRENT_SC));
+ print_command(CURRENT_SC->cmnd);
+ }
+#endif
- SETPORT(SCSIRATE, SYNCRATE & 0x7f);
- }
- break;
+ CMD_I=0;
+}
- case EXTENDED_MODIFY_DATA_POINTER:
- case EXTENDED_EXTENDED_IDENTIFY:
- case EXTENDED_WDTR:
- default:
- ADDMSG(MESSAGE_REJECT);
- break;
- }
- }
- break;
+/*
+ * 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);
+ }
- default:
- printk("unsupported inbound message %x, ", CURRENT_SC->SCp.Message);
- break;
+ 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);
- }
+ if(TESTLO(SSTAT0, SPIORDY)) {
+ DPRINTK(debug_cmd, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+ return;
+ }
- make_acklow(shpnt);
- phase = getphase(shpnt);
- }
+ SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]);
+ }
+}
- if (start_sync)
- CURRENT_SC->SCp.phase |= in_sync;
- else
- CURRENT_SC->SCp.phase &= ~in_sync;
+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 (MSGLEN > 0)
- SETPORT(SCSISIG, P_MSGI | ATNO);
+/*
+ * 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;
+ }
- /* clear SCSI fifo on BUSFREE */
- if (phase == P_BUSFREE)
- SETPORT(SXFRCTL0, CH1 | CLRCH1);
+ CURRENT_SC->SCp.Status = GETPORT(SCSIDAT);
- 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_status) {
+ printk(DEBUG_LEAD "inbound status %02x ", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.Status);
+ print_status(CURRENT_SC->SCp.Status);
+ printk("\n");
+ }
#endif
- append_SC(&DISCONNECTED_SC, CURRENT_SC);
- CURRENT_SC->SCp.phase |= 1 << 16;
- CURRENT_SC = NULL;
- restore_flags(flags);
-
- SETBITS(SCSISEQ, ENRESELI);
+}
- SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
- SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
+/*
+ * data in phase
+ *
+ */
+static void datai_init(struct Scsi_Host *shpnt)
+{
+ SETPORT(DMACNTRL0, RSTFIFO);
+ SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
- SETBITS(DMACNTRL0, INTEN);
+ SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+ SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
- return;
- }
- }
- break;
+ SETPORT(SIMODE0, 0);
+ SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE);
- 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);
+ 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(SIMODE0, 0);
- SETPORT(SIMODE1, ENREQINIT | ENBUSFREE);
+static void datai_run(struct Scsi_Host *shpnt)
+{
+ unsigned int the_time;
+ int fifodata, data_count;
- if (TESTHI(SSTAT1, PHASEMIS))
- printk("aha152x: passing STATUS phase");
+ /*
+ * 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();
- CURRENT_SC->SCp.Status = GETPORT(SCSIBUS);
- make_acklow(shpnt);
- getphase(shpnt);
-
-#if defined(DEBUG_STATUS)
- if (HOSTDATA(shpnt)->debug & debug_status) {
- printk("inbound status ");
- print_status(CURRENT_SC->SCp.Status);
- printk(", ");
+ if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) {
+ printk(ERR_LEAD "datai timeout", CMDINFO(CURRENT_SC));
+ disp_ports(shpnt);
+ break;
}
-#endif
- break;
- case P_DATAI: /* DATA IN phase */
- {
- int fifodata, data_count, done;
-
-#if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & (debug_datai | debug_intr | debug_phases))
- printk("DATA IN, ");
-#endif
+ if(TESTHI(DMASTAT, DFIFOFULL)) {
+ fifodata = 128;
+ } else {
+ the_time=jiffies + 100;
+ while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time))
+ barrier();
-#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
+ if(TESTLO(SSTAT2, SEMPTY)) {
+ printk(ERR_LEAD "datai sempty timeout", CMDINFO(CURRENT_SC));
+ disp_ports(shpnt);
+ break;
+ }
- /* reset host fifo */
- SETPORT(DMACNTRL0, RSTFIFO);
- SETPORT(DMACNTRL0, RSTFIFO | ENDMA);
+ fifodata = GETPORT(FIFOSTAT);
+ }
- SETPORT(SXFRCTL0, CH1 | SCSIEN | DMAEN);
+ 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;
+ }
+ }
- SETPORT(SIMODE0, 0);
- SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
+ 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;
+ }
+ }
- /* done is set when the FIFO is empty after the target left DATA IN */
- done = 0;
+ 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);
+ }
- /* 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(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);
+ }
+}
-#if defined(DEBUG_DATAI)
- if (HOSTDATA(shpnt)->debug & debug_datai)
- printk("ok, ");
-#endif
+static void datai_end(struct Scsi_Host *shpnt)
+{
+ CURRENT_SC->resid -= GETSTCNT();
- if (TESTHI(DMASTAT, DFIFOFULL))
- fifodata = GETPORT(FIFOSTAT);
- else {
- /* wait for SCSI fifo to get empty */
- while (TESTLO(SSTAT2, SEMPTY))
- barrier();
+ 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());
- /* rest of data in FIFO */
- fifodata = GETPORT(FIFOSTAT);
-#if defined(DEBUG_DATAI)
- if (HOSTDATA(shpnt)->debug & debug_datai)
- printk("last transfer, ");
-#endif
- done = 1;
- }
+ SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+ SETPORT(DMACNTRL0, 0);
+}
-#if defined(DEBUG_DATAI)
- if (HOSTDATA(shpnt)->debug & debug_datai)
- printk("fifodata=%d, ", fifodata);
-#endif
+/*
+ * data out phase
+ *
+ */
+static void datao_init(struct Scsi_Host *shpnt)
+{
+ SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
+ SETPORT(DMACNTRL0, WRITE_READ | ENDMA);
- while (fifodata && CURRENT_SC->SCp.this_residual) {
- data_count = fifodata;
+ SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+ SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
- /* limit data transfer to size of first sg buffer */
- if (data_count > CURRENT_SC->SCp.this_residual)
- data_count = CURRENT_SC->SCp.this_residual;
+ SETPORT(SIMODE0, 0);
+ SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE );
- fifodata -= data_count;
+ DATA_LEN = CURRENT_SC->resid;
-#if defined(DEBUG_DATAI)
- if (HOSTDATA(shpnt)->debug & debug_datai)
- printk("data_count=%d, ", data_count);
-#endif
+ DPRINTK(debug_datao,
+ DEBUG_LEAD "datao_init: request_bufflen=%d; resid=%d\n",
+ CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+}
- 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
+static void datao_run(struct Scsi_Host *shpnt)
+{
+ unsigned int the_time;
+ int data_count;
- 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;
- }
- }
+ /* 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;
- /*
- * 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
- }
+ if(TESTLO(DMASTAT, DFIFOEMP)) {
+ printk(ERR_LEAD "datao fifo not empty (%d)", CMDINFO(CURRENT_SC), GETPORT(FIFOSTAT));
+ disp_ports(shpnt);
+ break;
+ }
-#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);
+ 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(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 defined(DEBUG_DATAI) || defined(DEBUG_INTR)
- if (HOSTDATA(shpnt)->debug & (debug_datai | debug_intr))
- printk("got %d bytes, ", GETSTCNT());
-#endif
+ the_time=jiffies+100;
+ while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time))
+ barrier();
- CURRENT_SC->SCp.have_data_in++;
+ if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) {
+ printk(ERR_LEAD "dataout timeout", CMDINFO(CURRENT_SC));
+ disp_ports(shpnt);
+ break;
}
- break;
-
- case P_DATAO: /* DATA OUT phase */
- {
- int data_count;
-
-#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 (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);
+static void datao_end(struct Scsi_Host *shpnt)
+{
+ if(TESTLO(DMASTAT, DFIFOEMP)) {
+ int data_count = (DATA_LEN - CURRENT_SC->resid) - GETSTCNT();
- SETPORT(SIMODE0, 0);
- SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
+ 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());
- /* 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
-
- 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 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;
- }
- }
+ CURRENT_SC->resid += data_count;
- if (CURRENT_SC->SCp.this_residual || CURRENT_SC->SCp.buffers_residual) {
- /* target leaves DATA OUT for an other phase (perhaps disconnect) */
+ 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;
+ }
- /* data in fifos has to be resend */
- data_count = GETPORT(SSTAT2) & (SFULL | SFCNT);
+ 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());
- 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);
-
- /* 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;
+ dataphase=1;
+ }
- 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);
+ if((stat0 & SELDI) && STATE!=seldi && !dataphase) {
+ printk(INFO_LEAD "reselection missed?", CMDINFO(CURRENT_SC));
+ disp_ports(shpnt);
+ }
- aha152x_done(shpnt, DID_ERROR << 16); /* Don't know any better */
- return;
- break;
+ if(STATE!=PREVSTATE) {
+ LASTSTATE=PREVSTATE;
+ }
- case P_PARITY: /* parity error in DATA phase */
-#if defined(DEBUG_RACE)
- leave_driver("(DID_PARITY) intr");
-#endif
- printk("PARITY error in DATA phase, ");
+ return dataphase;
+}
- CURRENT_SC->SCp.phase &= ~(P_MASK << 16);
+/*
+ * 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);
+}
- SETBITS(DMACNTRL0, INTEN);
- aha152x_done(shpnt, DID_PARITY << 16);
- return;
- break;
+/*
+ * handle reset in
+ *
+ */
+static void rsti_run(struct Scsi_Host *shpnt)
+{
+ Scsi_Cmnd *ptr;
- default:
- printk("aha152x: unexpected phase\n");
- break;
- }
+ printk(KERN_NOTICE "aha152x%d: scsi reset in\n", HOSTNO);
+
+ ptr=DISCONNECTED_SC;
+ while(ptr) {
+ Scsi_Cmnd *next = SCNEXT(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
+ if (!ptr->device->soft_reset) {
+ remove_SC(&DISCONNECTED_SC, ptr);
- SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
- SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
- SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
+ kfree(ptr->host_scribble);
+ ptr->host_scribble=0;
- SETBITS(DMACNTRL0, INTEN);
+ ptr->result = DID_RESET << 16;
+ ptr->scsi_done(ptr);
+ }
- aha152x_done(shpnt,
- (CURRENT_SC->SCp.Status & 0xff)
- | ((CURRENT_SC->SCp.Message & 0xff) << 8)
- | (DID_OK << 16));
-
-#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 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 @@
printk("SCSIRSTO ");
printk(");");
- printk(" SCSISIG (");
+ printk(" SCSISIG(");
s = GETPORT(SCSISIG);
switch (s & P_MASK) {
case P_DATAO:
@@ -2726,7 +3038,7 @@
printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
- printk("SSTAT (");
+ printk("SSTAT( ");
s = GETPORT(SSTAT0);
if (s & TARGET)
printk("TARGET ");
@@ -2765,7 +3077,7 @@
printk("); ");
- printk("SSTAT (");
+ printk("SSTAT( ");
s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
@@ -2806,7 +3118,7 @@
printk("REQINIT ");
printk("); ");
- printk("SXFRCTL0 (");
+ printk("SXFRCTL0( ");
s = GETPORT(SXFRCTL0);
if (s & SCSIEN)
@@ -2823,24 +3135,26 @@
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 @@
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 @@
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 @@
printk("SWINT ");
printk("); ");
- printk("DMASTAT (");
+ printk("DMASTAT( ");
s = GETPORT(DMASTAT);
if (s & ATDONE)
printk("ATDONE ");
@@ -2889,9 +3203,7 @@
printk("DFIFOFULL ");
if (s & DFIFOEMP)
printk("DFIFOEMP ");
- printk(")");
-
- printk("\n");
+ printk(")\n");
#endif
}
@@ -2902,7 +3214,7 @@
{
int s;
- printk("enabled interrupts (");
+ printk(KERN_DEBUG "enabled interrupts ( ");
s = GETPORT(SIMODE0);
if (s & ENSELDO)
@@ -2938,100 +3250,38 @@
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_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 @@
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 @@
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 @@
SPRINTF("SCSIRSTO ");
SPRINTF(");");
- SPRINTF(" SCSISIG (");
+ SPRINTF(" SCSISIG(");
s = GETPORT(SCSISIG);
switch (s & P_MASK) {
case P_DATAO:
@@ -3191,7 +3407,7 @@
SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
- SPRINTF("SSTAT (");
+ SPRINTF("SSTAT( ");
s = GETPORT(SSTAT0);
if (s & TARGET)
SPRINTF("TARGET ");
@@ -3230,7 +3446,7 @@
SPRINTF("); ");
- SPRINTF("SSTAT (");
+ SPRINTF("SSTAT( ");
s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
@@ -3271,7 +3487,7 @@
SPRINTF("REQINIT ");
SPRINTF("); ");
- SPRINTF("SXFRCTL0 (");
+ SPRINTF("SXFRCTL0( ");
s = GETPORT(SXFRCTL0);
if (s & SCSIEN)
@@ -3288,24 +3504,26 @@
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("STCNT(%d), ", GETSTCNT());
- SPRINTF("SSTAT2 (");
+ SPRINTF("SSTAT2( ");
s = GETPORT(SSTAT2);
if (s & SOFFSET)
@@ -3319,7 +3537,7 @@
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 @@
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 @@
SPRINTF("SWINT ");
SPRINTF("); ");
- SPRINTF("DMASTAT (");
+ SPRINTF("DMASTAT( ");
s = GETPORT(DMASTAT);
if (s & ATDONE)
SPRINTF("ATDONE ");
@@ -3354,9 +3572,9 @@
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 @@
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 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 @@
(((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 @@
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 @@
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;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)