diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
commit | beb116954b9b7f3bb56412b2494b562f02b864b1 (patch) | |
tree | 120e997879884e1b9d93b265221b939d2ef1ade1 /drivers/scsi/aha152x.c | |
parent | 908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff) |
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'drivers/scsi/aha152x.c')
-rw-r--r-- | drivers/scsi/aha152x.c | 3745 |
1 files changed, 2199 insertions, 1546 deletions
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 21b33fe2f..78c089fd7 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -1,6 +1,6 @@ /* aha152x.c -- Adaptec AHA-152x driver - * Author: Juergen E. Fischer, fischer@server.et-inf.fho-emden.de - * Copyright 1993, 1994 Juergen E. Fischer + * 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 @@ -8,22 +8,56 @@ * which is * Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu) * - + * * 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 * Free Software Foundation; either version 2, or (at your option) any * later version. - + * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * $Id: aha152x.c,v 1.9 1995/03/18 09:20:24 root Exp root $ * - + * $Id: aha152x.c,v 1.18 1996/09/07 20:10:40 fischer Exp $ + * * $Log: aha152x.c,v $ + * Revision 1.18 1996/09/07 20:10:40 fischer + * - fixed can_queue handling (multiple outstanding commands working again) + * + * Revision 1.17 1996/08/17 16:05:14 fischer + * - biosparam improved + * - interrupt verification + * - updated documentation + * - cleanups + * + * Revision 1.16 1996/06/09 00:04:56 root + * - added configuration symbols for insmod (aha152x/aha152x1) + * + * Revision 1.15 1996/04/30 14:52:06 fischer + * - proc info fixed + * - support for extended translation for >1GB disks + * + * Revision 1.14 1996/01/17 15:11:20 fischer + * - fixed lockup in MESSAGE IN phase after reconnection + * + * Revision 1.13 1996/01/09 02:15:53 fischer + * - some cleanups + * - moved request_irq behind controller initialization + * (to avoid spurious interrupts) + * + * Revision 1.12 1995/12/16 12:26:07 fischer + * - barrier()s added + * - configurable RESET delay added + * + * Revision 1.11 1995/12/06 21:18:35 fischer + * - some minor updates + * + * Revision 1.10 1995/07/22 19:18:45 fischer + * - support for 2 controllers + * - started synchronous data transfers (not working yet) + * * Revision 1.9 1995/03/18 09:20:24 root * - patches for PCMCIA and modules * @@ -145,36 +179,122 @@ * Revision 0.0 1993/08/14 19:54:25 root * empty function bodies; detect() works. * - + * ************************************************************************** DESCRIPTION: - This is the Linux low-level SCSI driver for Adaptec AHA-1520/1522 - SCSI host adapters. + This is the Linux low-level SCSI driver for Adaptec AHA-1520/1522 SCSI + host adapters. - PER-DEFINE CONFIGURABLE OPTIONS: + CONFIGURATION ARGUMENTS: - AUTOCONF : use configuration the controller reports (only 152x) - IRQ : override interrupt channel (9,10,11 or 12) (default 11) - SCSI_ID : override scsiid of AIC-6260 (0-7) (default 7) - RECONNECT : override target dis-/reconnection/multiple outstanding commands (default on) - PARITY : override parity check (default on) - SKIP_BIOSTEST : Don't test for BIOS signature (AHA-1510 or disabled BIOS) - PORTBASE : Force port base. Don't try to probe + 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=<PORTBASE>[,<IRQ>[,<SCSI-ID>[,<RECONNECT>[,<PARITY>]]]] + 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 support under normal operation. - If you think that you need other values: contact me. + 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 adressing. 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 adressable 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: @@ -200,14 +320,19 @@ **************************************************************************/ -#ifdef MODULE -#include <linux/config.h> +#ifdef PCMCIA +#define MODULE +#endif + #include <linux/module.h> + +#ifdef PCMCIA +#undef MODULE #endif #include <linux/sched.h> #include <asm/io.h> -#include "../block/blk.h" +#include <linux/blk.h> #include "scsi.h" #include "sd.h" #include "hosts.h" @@ -217,35 +342,30 @@ #include <linux/string.h> #include <linux/wait.h> #include <linux/ioport.h> +#include <linux/proc_fs.h> #include "aha152x.h" +#include <linux/stat.h> + +#include <scsi/scsicam.h> + +struct proc_dir_entry proc_scsi_aha152x = { + PROC_SCSI_AHA152X, 7, "aha152x", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; /* DEFINES */ /* For PCMCIA cards, always use AUTOCONF */ #if defined(PCMCIA) || defined(MODULE) -#define AUTOCONF -#endif - -/* If auto configuration is disabled, IRQ, SCSI_ID and RECONNECT have to - be predefined */ #if !defined(AUTOCONF) -#if !defined(IRQ) -#error undefined IRQ; define AUTOCONF or IRQ -#endif -#if !defined(SCSI_ID) -#error undefined SCSI_ID; define AUTOCONF or SCSI_ID -#endif -#if !defined(RECONNECT) -#error undefined RECONNECT; define AUTOCONF or RECONNECT -#endif -#if !defined(PARITY) -#error undefined PARITY; define AUTOCONF or PARITY +#define AUTOCONF #endif #endif -/* I use this when I'm looking for weird bugs */ -#define DEBUG_TIMING +#if !defined(AUTOCONF) && !defined(SETUP0) +#error define AUTOCONF or SETUP0 +#endif #if defined(DEBUG_AHA152X) @@ -273,6 +393,7 @@ #if 0 #endif +#define DEBUG_SELECTION #define DEBUG_PHASES #define DEBUG_RESET #define DEBUG_ABORT @@ -283,66 +404,109 @@ /* END OF DEFINES */ +extern long loops_per_sec; + +#define DELAY_DEFAULT 100 + /* some additional "phases" for getphase() */ #define P_BUSFREE 1 #define P_PARITY 2 -static int port_base = 0; -static int this_host = 0; -static int can_disconnect = 0; -static int can_doparity = 0; -static int commands = 0; +/* possible irq range */ +#define IRQ_MIN 9 +#define IRQ_MAX 12 +#define IRQS IRQ_MAX-IRQ_MIN+1 -#ifdef DEBUG_AHA152X -unsigned int aha152x_debug = DEBUG_DEFAULT; +enum { + not_issued = 0x0001, + in_selection = 0x0002, + disconnected = 0x0004, + aborted = 0x0008, + sent_ident = 0x0010, + in_other = 0x0020, + in_sync = 0x0040, + sync_ok = 0x0080, +}; + +#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 }; +#else +int aha152x[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0 }; +int aha152x1[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0 }; +#endif #endif /* set by aha152x_setup according to the command line */ -static int setup_called = 0; -static int setup_portbase = 0; -static int setup_irq = 0; -static int setup_scsiid = 0; -static int setup_reconnect = 0; -static int setup_doparity = 0; - +static int setup_count=0; +static struct aha152x_setup { + int io_port; + int irq; + int scsiid; + int reconnect; + int parity; + int synchronous; + int delay; + int ext_trans; #ifdef DEBUG_AHA152X -static int setup_debug = 0; -#endif - -static char *setup_str = (char *)NULL; + int debug; +#endif + char *conf; +} setup[2]; + +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) + +struct aha152x_hostdata { + Scsi_Cmnd *issue_SC; + Scsi_Cmnd *current_SC; + Scsi_Cmnd *disconnected_SC; + int aborting; + int abortion_complete; + int abort_result; + int commands; + + int reconnect; + int parity; + int synchronous; + int delay; + int ext_trans; -enum { - not_issued = 0x01, - in_selection = 0x02, - disconnected = 0x04, - aborted = 0x08, - sent_ident = 0x10, - in_other = 0x20, -}; + int swint; -/* - * Command queues: - * issue_SC : commands that are queued to be issued - * current_SC : command that's currently using the bus - * disconnected_SC : commands that that have been disconnected - */ -static Scsi_Cmnd *issue_SC = NULL; -static Scsi_Cmnd *current_SC = NULL; -static Scsi_Cmnd *disconnected_SC = NULL; + unsigned char syncrate[8]; + + unsigned char message[256]; + int message_len; -static int aborting=0, abortion_complete=0, abort_result; +#ifdef DEBUG_AHA152X + int debug; +#endif +}; -void aha152x_intr( int irq, struct pt_regs * ); -void aha152x_done( int error ); -void aha152x_setup( char *str, int *ints ); +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(void); -static void aha152x_panic(char *msg); +static void aha152x_reset_ports(struct Scsi_Host *shpnt); +static void aha152x_panic(struct Scsi_Host *shpnt, char *msg); -static void disp_ports(void); +static void disp_ports(struct Scsi_Host *shpnt); static void show_command(Scsi_Cmnd *ptr); -static void show_queues(void); -static void disp_enintr(void); +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 *); @@ -355,36 +519,33 @@ static unsigned short ports[] = 0x340, /* default first */ 0x140 }; -#define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short )) - -/* possible interrupt channels */ -static unsigned short irqs[] = { 9, 10, 11, 12, 0 }; +#define PORT_COUNT (sizeof(ports) / sizeof(unsigned short)) #if !defined(SKIP_BIOSTEST) /* possible locations for the Adaptec BIOS */ -static void *addresses[] = +static unsigned int addresses[] = { - (void *) 0xdc000, /* default first */ - (void *) 0xc8000, - (void *) 0xcc000, - (void *) 0xd0000, - (void *) 0xd4000, - (void *) 0xd8000, - (void *) 0xe0000, - (void *) 0xf0000, - (void *) 0xeb800, /* VTech Platinum SMP */ + 0xdc000, /* default first */ + 0xc8000, + 0xcc000, + 0xd0000, + 0xd4000, + 0xd8000, + 0xe0000, + 0xeb800, /* VTech Platinum SMP */ + 0xf0000, }; -#define ADDRESS_COUNT (sizeof( addresses ) / sizeof( void * )) +#define ADDRESS_COUNT (sizeof(addresses) / sizeof(unsigned int)) /* signatures for various AIC-6[23]60 based controllers. - The point in detecting signatures is to avoid useless - and maybe harmful probes on ports. I'm not sure that - all listed boards pass auto-configuration. For those - which fail the BIOS signature is obsolete, because - user intervention to supply the configuration is - needed anyway. */ + The point in detecting signatures is to avoid useless and maybe + harmful probes on ports. I'm not sure that all listed boards pass + auto-configuration. For those which fail the BIOS signature is + obsolete, because user intervention to supply the configuration is + needed anyway. May be an information whether or not the BIOS supports + extended translation could be also useful here. */ static struct signature { - char *signature; + unsigned char *signature; int sig_offset; int sig_length; } signatures[] = @@ -394,42 +555,42 @@ static struct signature { { "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 with AIC-6360 */ + { "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 */ }; -#define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature )) +#define SIGNATURE_COUNT (sizeof(signatures) / sizeof(struct signature)) #endif -static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */ +static void do_pause(unsigned amount) /* Pause for amount*10 milliseconds */ { unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */ while (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; 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; - } + else { + for(end=*SC; end->host_scribble; end = (Scsi_Cmnd *) end->host_scribble) + ; + end->host_scribble = (unsigned char *) new_SC; + } } -static inline Scsi_Cmnd *remove_first_SC( Scsi_Cmnd **SC ) +static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd **SC) { Scsi_Cmnd *ptr; @@ -439,13 +600,13 @@ static inline Scsi_Cmnd *remove_first_SC( Scsi_Cmnd **SC ) return ptr; } -static inline Scsi_Cmnd *remove_SC( Scsi_Cmnd **SC, int target, int lun ) +static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, int target, int lun) { Scsi_Cmnd *ptr, *prev; - for( ptr=*SC, prev=NULL; + for(ptr=*SC, prev=NULL; ptr && ((ptr->target!=target) || (ptr->lun!=lun)); - prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble ) + prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble) ; if(ptr) @@ -453,20 +614,21 @@ static inline Scsi_Cmnd *remove_SC( Scsi_Cmnd **SC, int target, int lun ) prev->host_scribble = ptr->host_scribble; else *SC= (Scsi_Cmnd *) ptr->host_scribble; + return ptr; } /* * read inbound byte and wait for ACK to get low */ -static void make_acklow(void) +static void make_acklow(struct Scsi_Host *shpnt) { - SETPORT( SXFRCTL0, CH1|SPIOEN ); + SETPORT(SXFRCTL0, CH1|SPIOEN); GETPORT(SCSIDAT); - SETPORT( SXFRCTL0, CH1 ); + SETPORT(SXFRCTL0, CH1); - while( TESTHI( SCSISIG, ACKI ) ) - ; + while(TESTHI(SCSISIG, ACKI)) + barrier(); } /* @@ -479,322 +641,453 @@ static void make_acklow(void) * P_BUSFREE BUS FREE phase detected * P_PARITY parity error in DATA phase */ -static int getphase(void) +static int getphase(struct Scsi_Host *shpnt) { int phase, sstat1; - while( 1 ) - { - do - { - while( !( ( sstat1 = GETPORT( SSTAT1 ) ) & (BUSFREE|SCSIRSTI|REQINIT ) ) ) - ; - if( sstat1 & BUSFREE ) - return P_BUSFREE; - if( sstat1 & SCSIRSTI ) - { - /* IBM drive responds with RSTI to RSTO */ - printk("aha152x: RESET IN\n"); - SETPORT( SSTAT1, SCSIRSTI ); - } - } - while( TESTHI( SCSISIG, ACKI ) || TESTLO( SSTAT1, REQINIT ) ); + 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 ); + SETPORT(SSTAT1, CLRSCSIPERR); - phase = GETPORT( SCSISIG ) & P_MASK ; + phase = GETPORT(SCSISIG) & P_MASK ; - if( TESTHI( SSTAT1, SCSIPERR ) ) - { - if( (phase & (CDO|MSGO))==0 ) /* DATA phase */ - return P_PARITY; + if(TESTHI(SSTAT1, SCSIPERR)) { + if((phase & (CDO|MSGO))==0) /* DATA phase */ + return P_PARITY; - make_acklow(); - } - else - return phase; - } + make_acklow(shpnt); + } else + return phase; + } } /* called from init/main.c */ -void aha152x_setup( char *str, int *ints) +void aha152x_setup(char *str, int *ints) { - if(setup_called) - panic("aha152x: aha152x_setup called twice.\n"); - - setup_called=ints[0]; - setup_str=str; - - setup_portbase = ints[0] >= 1 ? ints[1] : 0x340; - setup_irq = ints[0] >= 2 ? ints[2] : 11; - setup_scsiid = ints[0] >= 3 ? ints[3] : 7; - setup_reconnect = ints[0] >= 4 ? ints[4] : 1; - setup_doparity = ints[0] >= 5 ? ints[5] : 1; + if(setup_count>2) + panic("aha152x: you can only configure up to two controllers\n"); + + setup[setup_count].conf = str; + setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340; + setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11; + setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7; + setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1; + setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1; + setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 0 /* FIXME: 1 */; + setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT; + setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0; #ifdef DEBUG_AHA152X - setup_debug = ints[0] >= 6 ? ints[6] : DEBUG_DEFAULT; + setup[setup_count].debug = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT; + if(ints[0]>9) { + printk("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>" + "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n"); #endif + } else + setup_count++; } /* - Test, if port_base is valid. + * Test, if port_base is valid. */ -static int aha152x_porttest(int port_base) +static int aha152x_porttest(int io_port) { int i; - if(check_region(port_base, 0x20)) + if(check_region(io_port, IO_RANGE)) return 0; - SETPORT( DMACNTRL1, 0 ); /* reset stack pointer */ + SETPORT(io_port+O_DMACNTRL1, 0); /* reset stack pointer */ for(i=0; i<16; i++) - SETPORT( STACK, i ); + SETPORT(io_port+O_STACK, i); - SETPORT( DMACNTRL1, 0 ); /* reset stack pointer */ - for(i=0; i<16 && GETPORT(STACK)==i; i++) + SETPORT(io_port+O_DMACNTRL1, 0); /* reset stack pointer */ + for(i=0; i<16 && GETPORT(io_port+O_STACK)==i; i++) ; return(i==16); } +int aha152x_checksetup(struct aha152x_setup *setup) +{ + int i; + +#ifndef 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(setup->irq<IRQ_MIN && setup->irq>IRQ_MAX) + return 0; + + if((setup->scsiid < 0) || (setup->scsiid > 7)) + return 0; + + if((setup->reconnect < 0) || (setup->reconnect > 1)) + return 0; + + if((setup->parity < 0) || (setup->parity > 1)) + return 0; + + if((setup->synchronous < 0) || (setup->synchronous > 1)) + return 0; + + if((setup->ext_trans < 0) || (setup->ext_trans > 1)) + return 0; + + + return 1; +} + +void aha152x_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"); + + HOSTDATA(shpnt)->swint++; +} + + int aha152x_detect(Scsi_Host_Template * tpnt) { - int i, ok; + int i, j, ok; #if defined(AUTOCONF) aha152x_config conf; #endif - int interrupt_level; - struct Scsi_Host *hreg; - if(setup_called) - { - printk("aha152x: processing commandline: "); + tpnt->proc_dir = &proc_scsi_aha152x; + + for(i=0; i<IRQS; i++) + aha152x_host[i] = (struct Scsi_Host *) NULL; + + if(setup_count) { + printk("aha152x: processing commandline: "); -#ifdef DEBUG_AHA152X - if(setup_called>6) -#else - if(setup_called>5) -#endif - { - printk("\naha152x: %s\n", setup_str ); -#ifdef DEBUG_AHA152X - printk("aha152x: usage: aha152x=<PORTBASE>[,<IRQ>[,<SCSI ID>[,<RECONNECT>[,<PARITY>[,<DEBUG>]]]]]\n"); -#else - printk("aha152x: usage: aha152x=<PORTBASE>[,<IRQ>[,<SCSI ID>[,<RECONNECT>[,<PARITY>]]]]\n"); -#endif - panic("aha152x panics in line %d", __LINE__); - } + 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); + } - port_base = setup_portbase; - interrupt_level = setup_irq; - this_host = setup_scsiid; - can_disconnect = setup_reconnect; - can_doparity = setup_doparity; -#ifdef DEBUG_AHA152X - aha152x_debug = setup_debug; + printk("ok\n"); + } + +#ifdef 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", + override.io_port, + override.irq, + override.scsiid, + override.reconnect, + override.parity, + override.synchronous, + override.delay, + override.ext_trans); + } else + setup[setup_count++] = override; + } #endif -#ifndef PCMCIA - for( i=0; i<PORT_COUNT && (port_base != ports[i]); i++) - ; - - if(i==PORT_COUNT) - { - printk("unknown portbase 0x%03x\n", port_base); - panic("aha152x panics in line %d", __LINE__); - } +#ifdef 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", + override.io_port, + override.irq, + override.scsiid, + override.reconnect, + override.parity, + override.synchronous, + override.delay, + override.ext_trans); + } else + setup[setup_count++] = override; + } #endif - if(!aha152x_porttest(port_base)) - { - printk("portbase 0x%03x fails probe\n", port_base); -#ifdef PCMCIA - return 0; -#else - panic("aha152x panics in line %d", __LINE__); +#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]; #endif - } + if(aha152x_checksetup(&setup[setup_count])) + setup_count++; + else + printk("\naha152x: invalid module argument aha152x=0x%x,%d,%d,%d,%d,%d,%d,%d\n", + setup[setup_count].io_port, + setup[setup_count].irq, + setup[setup_count].scsiid, + setup[setup_count].reconnect, + setup[setup_count].parity, + setup[setup_count].synchronous, + setup[setup_count].delay, + setup[setup_count].ext_trans); + } -#ifndef PCMCIA - i=0; - while(irqs[i] && (interrupt_level!=irqs[i])) - i++; - if(!irqs[i]) - { - printk("illegal IRQ %d\n", interrupt_level); - panic("aha152x panics in line %d", __LINE__); - } + 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]; #endif - - if( (this_host < 0) || (this_host > 7) ) - { - printk("illegal SCSI ID %d\n", this_host); - panic("aha152x panics in line %d", __LINE__); - } - - if( (can_disconnect < 0) || (can_disconnect > 1) ) - { - printk("reconnect %d should be 0 or 1\n", can_disconnect); - panic("aha152x panics in line %d", __LINE__); - } - - if( (can_doparity < 0) || (can_doparity > 1) ) - { - printk("parity %d should be 0 or 1\n", can_doparity); - panic("aha152x panics in line %d", __LINE__); - } - printk("ok\n"); - } - else - { + if(aha152x_checksetup(&setup[setup_count])) + setup_count++; + else + printk("\naha152x: invalid module argument aha152x1=0x%x,%d,%d,%d,%d,%d,%d,%d\n", + setup[setup_count].io_port, + setup[setup_count].irq, + setup[setup_count].scsiid, + setup[setup_count].reconnect, + setup[setup_count].parity, + setup[setup_count].synchronous, + setup[setup_count].delay, + setup[setup_count].ext_trans); + } +#endif + +#if defined(AUTOCONF) + if(setup_count<2) { #if !defined(SKIP_BIOSTEST) - int j; + ok=0; + for(i=0; i < ADDRESS_COUNT && !ok; i++) + for(j=0; (j < SIGNATURE_COUNT) && !ok; j++) + ok = check_signature(addresses[i]+signatures[j].sig_offset, + signatures[j].signature, signatures[j].sig_length); - ok=0; - for( i=0; i < ADDRESS_COUNT && !ok; i++) - for( j=0; (j < SIGNATURE_COUNT) && !ok; j++) - ok=!memcmp((void *) addresses[i]+signatures[j].sig_offset, - (void *) signatures[j].signature, - (int) signatures[j].sig_length); + if(!ok && setup_count==0) + return 0; - if(!ok) - return 0; - - printk("aha152x: BIOS test: passed, "); + printk("aha152x: BIOS test: passed, "); #else - printk("aha152x: "); + printk("aha152x: "); #endif /* !SKIP_BIOSTEST */ -#if !defined(PORTBASE) - printk("porttest: "); - for( i=0; i<PORT_COUNT && !aha152x_porttest(ports[i]); i++) - ; - - if(i==PORT_COUNT) - { - printk("failed\n"); - return 0; - } - else - port_base=ports[i]; - printk("ok, "); -#else - port_base=PORTBASE; -#endif /* !PORTBASE */ + ok=0; + for(i=0; i<PORT_COUNT && setup_count<2; i++) { + if((setup_count==1) && (setup[0].io_port == ports[i])) + continue; + + if(aha152x_porttest(ports[i])) { + ok++; + setup[setup_count].io_port = ports[i]; + + 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 = 0 /* FIXME: conf.cf_syncneg */; + setup[setup_count].delay = DELAY_DEFAULT; + setup[setup_count].ext_trans = 0; +#ifdef DEBUG_AHA152X + setup[setup_count].debug = DEBUG_DEFAULT; +#endif + setup_count++; + } + } -#if defined(AUTOCONF) + if(ok) + printk("auto configuration: ok, "); + } +#endif - conf.cf_port = (GETPORT(PORTA)<<8) + GETPORT(PORTB); + printk("detected %d controller(s)\n", setup_count); - interrupt_level = irqs[conf.cf_irq]; - this_host = conf.cf_id; - can_disconnect = conf.cf_tardisc; - can_doparity = !conf.cf_parity; + for(i=0; i<setup_count; i++) { + struct Scsi_Host *shpnt; + unsigned long int the_time; - printk("auto configuration: ok, "); + shpnt = aha152x_host[setup[i].irq-IRQ_MIN] = + scsi_register(tpnt, sizeof(struct aha152x_hostdata)); -#endif /* AUTOCONF */ + shpnt->io_port = setup[i].io_port; + shpnt->n_io_port = IO_RANGE; + shpnt->irq = setup[i].irq; -#if defined(IRQ) - interrupt_level = IRQ; -#endif + ISSUE_SC = (Scsi_Cmnd *) NULL; + CURRENT_SC = (Scsi_Cmnd *) NULL; + DISCONNECTED_SC = (Scsi_Cmnd *) NULL; -#if defined(SCSI_ID) - this_host = SCSI_ID; + 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 + HOSTDATA(shpnt)->debug = setup[i].debug; #endif -#if defined(RECONNECT) - can_disconnect=RECONNECT; -#endif + HOSTDATA(shpnt)->aborting = 0; + HOSTDATA(shpnt)->abortion_complete = 0; + HOSTDATA(shpnt)->abort_result = 0; + HOSTDATA(shpnt)->commands = 0; -#if defined(PARITY) - can_doparity=PARITY; -#endif - } + HOSTDATA(shpnt)->message_len = 0; - printk("detection complete\n"); + for(j=0; j<8; j++) + HOSTDATA(shpnt)->syncrate[j] = 0; - ok = request_irq(interrupt_level, aha152x_intr, SA_INTERRUPT, "aha152x"); + SETPORT(SCSIID, setup[i].scsiid << 4); + shpnt->this_id=setup[i].scsiid; - if(ok<0) - { + 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%03x, IRQ=%d, SCSI ID=%d," + " reconnect=%s, parity=%s, synchronous=%s, delay=%d, extended translation=%s\n", + i, + shpnt->io_port, + 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"); + + request_region(shpnt->io_port, IO_RANGE, "aha152x"); /* Register */ + + /* not expecting any interrupts */ + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, 0); + + SETBITS(DMACNTRL0, INTEN); + + ok = request_irq(shpnt->irq, aha152x_swintr, SA_INTERRUPT, "aha152x", NULL); + if(ok<0) { if(ok == -EINVAL) - { - printk("aha152x: bad IRQ %d.\n", interrupt_level); - printk(" Contact author.\n"); - } + 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); else - if( ok == -EBUSY) - printk( "aha152x: IRQ %d already in use. Configure another.\n", - interrupt_level); - else - { - printk( "\naha152x: Unexpected error code on requesting IRQ %d.\n", - interrupt_level); - printk(" Contact author.\n"); - } - panic("aha152x: driver needs an IRQ.\n"); + printk("\naha152x%d: Unexpected error code %d on requesting IRQ %d.\n", i, ok, shpnt->irq); + printk("aha152x: driver needs an IRQ.\n"); + + scsi_unregister(shpnt); + shpnt=aha152x_host[shpnt->irq-IRQ_MIN]=0; + continue; } - SETPORT( SCSIID, this_host << 4 ); - tpnt->this_id=this_host; - - if(can_disconnect) - tpnt->can_queue=AHA152X_MAXQUEUE; - - /* RESET OUT */ - SETBITS(SCSISEQ, SCSIRSTO ); - do_pause(30); - CLRBITS(SCSISEQ, SCSIRSTO ); - do_pause(60); - - aha152x_reset(NULL); - - printk("aha152x: vital data: PORTBASE=0x%03x, IRQ=%d, SCSI ID=%d, reconnect=%s, parity=%s\n", - port_base, - interrupt_level, - this_host, - can_disconnect ? "enabled" : "disabled", - can_doparity ? "enabled" : "disabled"); - - request_region(port_base, 0x20, "aha152x"); /* Register */ - - hreg = scsi_register(tpnt, 0); - hreg->io_port = port_base; - hreg->n_io_port = 0x20; - hreg->irq = interrupt_level; - - /* not expecting any interrupts */ - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, 0); + HOSTDATA(shpnt)->swint=0; - SETBITS( DMACNTRL0, INTEN); - return 1; + printk("aha152x: trying software interrupt, "); + SETBITS(DMACNTRL0, SWINT); + + the_time=jiffies+100; + while(!HOSTDATA(shpnt)->swint && jiffies<the_time) + barrier(); + + free_irq(shpnt->irq,0); + + if(!HOSTDATA(shpnt)->swint) { + if(TESTHI(DMASTAT, INTSTAT)) { + printk("lost.\n"); + } else { + printk("failed.\n"); + } + + printk("aha152x: IRQ %d possibly wrong. Please verify.\n", shpnt->irq); + + scsi_unregister(shpnt); + shpnt=aha152x_host[shpnt->irq-IRQ_MIN]=0; + continue; + } + + printk("ok.\n"); + + CLRBITS(DMACNTRL0, SWINT); + + /* clear interrupts */ + SETPORT(SSTAT0, 0x7f); + SETPORT(SSTAT1, 0xef); + + if(request_irq(shpnt->irq,aha152x_intr,SA_INTERRUPT,"aha152x",NULL)<0) { + printk("aha152x: failed to reassign interrupt.\n"); + } + } + + return (setup_count>0); } /* * Queue a command and setup interrupts for a free bus. */ -int aha152x_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) +int aha152x_queue(Scsi_Cmnd * SCpnt, 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(aha152x_debug & debug_queue) + if(HOSTDATA(shpnt)->debug & debug_queue) printk("aha152x: queue(), "); #endif #endif #if defined(DEBUG_QUEUE) - if(aha152x_debug & debug_queue) - { - printk( "SCpnt (target = %d lun = %d cmnd = ", SCpnt->target, SCpnt->lun); + if(HOSTDATA(shpnt)->debug & debug_queue) { + printk("SCpnt (target = %d lun = %d cmnd = ", + SCpnt->target, SCpnt->lun); print_command(SCpnt->cmnd); - printk( ", cmd_len=%d, pieces = %d size = %u), ", - SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen ); - disp_ports(); + printk(", cmd_len=%d, pieces = %d size = %u), ", + SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen); + disp_ports(shpnt); } #endif @@ -807,20 +1100,17 @@ int aha152x_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) 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.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.buffers_residual = 0; - } + 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.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.buffers_residual = 0; + } SCpnt->SCp.Status = CHECK_CONDITION; SCpnt->SCp.Message = 0; @@ -830,22 +1120,21 @@ int aha152x_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) /* Turn led on, when this is the first command. */ save_flags(flags); cli(); - commands++; - if(commands==1) - SETPORT( PORTA, 1 ); + HOSTDATA(shpnt)->commands++; + if(HOSTDATA(shpnt)->commands==1) + SETPORT(PORTA, 1); #if defined(DEBUG_QUEUES) - if(aha152x_debug & debug_queues) - printk("i+ (%d), ", commands ); + if(HOSTDATA(shpnt)->debug & debug_queues) + printk("i+ (%d), ", HOSTDATA(shpnt)->commands); #endif - append_SC( &issue_SC, SCpnt); + 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); - } + if(!CURRENT_SC) { + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + } restore_flags(flags); #if defined(DEBUG_RACE) @@ -856,11 +1145,11 @@ int aha152x_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) } /* - * We only support command in interrupt-driven fashion + * We only support commands in interrupt-driven fashion */ -int aha152x_command( Scsi_Cmnd *SCpnt ) +int aha152x_command(Scsi_Cmnd *SCpnt) { - printk( "aha152x: interrupt driven driver; use aha152x_queue()\n" ); + printk("aha152x: interrupt driven driver; use aha152x_queue()\n"); return -1; } @@ -868,8 +1157,9 @@ int aha152x_command( Scsi_Cmnd *SCpnt ) * Abort a queued command * (commands that are on the bus can't be aborted easily) */ -int aha152x_abort( Scsi_Cmnd *SCpnt) +int aha152x_abort(Scsi_Cmnd *SCpnt) { + struct Scsi_Host *shpnt = SCpnt->host; unsigned long flags; Scsi_Cmnd *ptr, *prev; @@ -877,118 +1167,126 @@ int aha152x_abort( Scsi_Cmnd *SCpnt) cli(); #if defined(DEBUG_ABORT) - if(aha152x_debug & debug_abort) - { - printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt ); - - show_queues(); + if(HOSTDATA(shpnt)->debug & debug_abort) { + printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt); + show_queues(shpnt); } #endif /* look for command in issue queue */ - for( ptr=issue_SC, prev=NULL; + for(ptr=ISSUE_SC, prev=NULL; ptr && ptr!=SCpnt; prev=ptr, ptr=(Scsi_Cmnd *) ptr->host_scribble) ; - if(ptr) - { - /* dequeue */ - if(prev) - prev->host_scribble = ptr->host_scribble; - else - issue_SC = (Scsi_Cmnd *) ptr->host_scribble; - restore_flags(flags); + if(ptr) { + /* dequeue */ + if(prev) + prev->host_scribble = ptr->host_scribble; + else + ISSUE_SC = (Scsi_Cmnd *) ptr->host_scribble; - ptr->host_scribble = NULL; - ptr->result = DID_ABORT << 16; - ptr->done(ptr); - return SCSI_ABORT_SUCCESS; - } + HOSTDATA(shpnt)->commands--; + + restore_flags(flags); + + ptr->host_scribble = NULL; + ptr->result = DID_ABORT << 16; + ptr->scsi_done(ptr); + + 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 */ + if (TESTLO(SSTAT1, BUSFREE) || (CURRENT_SC && CURRENT_SC!=SCpnt)) { + /* fail abortion, if bus is busy */ - if(!current_SC) - printk("bus busy w/o current command, "); + if(!CURRENT_SC) + printk("bus busy w/o current command, "); - restore_flags(flags); - return SCSI_ABORT_BUSY; - } + restore_flags(flags); + + return SCSI_ABORT_BUSY; + } /* bus is free */ - if(current_SC) - { + if(CURRENT_SC) { + HOSTDATA(shpnt)->commands--; + /* target entered bus free before COMMAND COMPLETE, nothing to abort */ restore_flags(flags); - current_SC->result = DID_ERROR << 16; - current_SC->done(current_SC); - current_SC = (Scsi_Cmnd *) NULL; + CURRENT_SC->result = DID_ERROR << 16; + CURRENT_SC->scsi_done(CURRENT_SC); + CURRENT_SC = (Scsi_Cmnd *) NULL; + return SCSI_ABORT_SUCCESS; } /* look for command in disconnected queue */ - for( ptr=disconnected_SC, prev=NULL; + for(ptr=DISCONNECTED_SC, prev=NULL; ptr && ptr!=SCpnt; prev=ptr, ptr=(Scsi_Cmnd *) ptr->host_scribble) ; - if(ptr) - if(!aborting) - { - /* dequeue */ - if(prev) - prev->host_scribble = ptr->host_scribble; - else - disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble; - - /* 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, (this_host << OID_) | current_SC->target ); - - /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ - SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) ); - SETPORT( SIMODE1, ENSELTIMO ); - - /* Enable SELECTION OUT sequence */ - SETBITS(SCSISEQ, ENSELO | ENAUTOATNO ); - - SETBITS( DMACNTRL0, INTEN ); - abort_result=SCSI_ABORT_SUCCESS; - aborting++; - abortion_complete=0; + if(!ptr) { + /* command wasn't found */ + printk("command not found\n"); + restore_flags(flags); - sti(); /* Hi Eric, guess what ;-) */ - - /* sleep until the abortion is complete */ - while(!abortion_complete) - barrier(); - aborting=0; - return abort_result; - } + return SCSI_ABORT_NOT_RUNNING; + } + + if(!HOSTDATA(shpnt)->aborting) { + /* dequeue */ + if(prev) + prev->host_scribble = ptr->host_scribble; else - { - /* we're already aborting a command */ - restore_flags(flags); - return SCSI_ABORT_BUSY; - } + DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble; - /* command wasn't found */ - printk("command not found\n"); - restore_flags(flags); - return SCSI_ABORT_NOT_RUNNING; + HOSTDATA(shpnt)->commands--; + + /* 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); + + ADDMSG(ABORT); + + /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ + SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); + SETPORT(SIMODE1, ENSELTIMO); + + /* Enable SELECTION OUT sequence */ + SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); + + SETBITS(DMACNTRL0, INTEN); + HOSTDATA(shpnt)->abort_result=SCSI_ABORT_SUCCESS; + HOSTDATA(shpnt)->aborting++; + HOSTDATA(shpnt)->abortion_complete=0; + + sti(); /* Hi Eric, guess what ;-) */ + + /* sleep until the abortion is complete */ + while(!HOSTDATA(shpnt)->abortion_complete) + barrier(); + HOSTDATA(shpnt)->aborting=0; + + return HOSTDATA(shpnt)->abort_result; + } else { + /* we're already aborting a command */ + restore_flags(flags); + + return SCSI_ABORT_BUSY; + } } /* * Restore default values to the AIC-6260 registers and reset the fifos */ -static void aha152x_reset_ports(void) +static void aha152x_reset_ports(struct Scsi_Host *shpnt) { /* disable interrupts */ SETPORT(DMACNTRL0, RSTFIFO); @@ -996,7 +1294,7 @@ static void aha152x_reset_ports(void) SETPORT(SCSISEQ, 0); SETPORT(SXFRCTL1, 0); - SETPORT( SCSISIG, 0); + SETPORT(SCSISIG, 0); SETPORT(SCSIRATE, 0); /* clear all interrupt conditions */ @@ -1015,89 +1313,83 @@ static void aha152x_reset_ports(void) SETPORT(SXFRCTL0, CH1); /* enable interrupts */ - SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 ); - SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0); + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); } /* * Reset registers, reset a hanging bus and * kill active and disconnected commands for target w/o soft reset */ -int aha152x_reset(Scsi_Cmnd * __unused) +int aha152x_reset(Scsi_Cmnd *SCpnt, unsigned int unused) { + struct Scsi_Host *shpnt = SCpnt->host; unsigned long flags; Scsi_Cmnd *ptr, *prev, *next; - aha152x_reset_ports(); + aha152x_reset_ports(shpnt); /* Reset, if bus hangs */ - if( TESTLO( SSTAT1, BUSFREE ) ) - { - CLRBITS( DMACNTRL0, INTEN ); + if(TESTLO(SSTAT1, BUSFREE)) { + CLRBITS(DMACNTRL0, INTEN); #if defined(DEBUG_RESET) - if(aha152x_debug & debug_reset) - { - printk("aha152x: reset(), bus not free: SCSI RESET OUT\n"); - show_queues(); - } + if(HOSTDATA(shpnt)->debug & debug_reset) { + printk("aha152x: reset(), bus not free: SCSI RESET OUT\n"); + show_queues(shpnt); + } #endif - if(current_SC && !current_SC->device->soft_reset) - { - current_SC->host_scribble = NULL; - current_SC->result = DID_RESET << 16; - current_SC->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; - ptr->done(ptr); + 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; + ptr->scsi_done(ptr); - ptr = next; - } - else - { - prev=ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble; - } - } - restore_flags(flags); - -#if defined( DEBUG_RESET ) - if(aha152x_debug & debug_reset) - { - printk("commands on targets w/ soft-resets:\n"); - show_queues(); - } -#endif - - /* RESET OUT */ - SETPORT(SCSISEQ, SCSIRSTO); - do_pause(30); - SETPORT(SCSISEQ, 0); - do_pause(60); - - SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 ); - SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0); - - SETPORT( DMACNTRL0, INTEN ); + 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 + + /* RESET OUT */ + SETPORT(SCSISEQ, SCSIRSTO); + do_pause(30); + SETPORT(SCSISEQ, 0); + do_pause(DELAY); + + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + + SETPORT(DMACNTRL0, INTEN); + } return SCSI_RESET_SUCCESS; } @@ -1105,24 +1397,54 @@ int aha152x_reset(Scsi_Cmnd * __unused) /* * Return the "logical geometry" */ -int aha152x_biosparam(Scsi_Disk * disk, int dev, int *info_array ) +int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array) { - int size = disk->capacity; + struct Scsi_Host *shpnt=disk->device->host; #if defined(DEBUG_BIOSPARAM) - if(aha152x_debug & debug_biosparam) - printk("aha152x_biosparam: dev=%x, size=%d, ", dev, size); + if(HOSTDATA(shpnt)->debug & debug_biosparam) + printk("aha152x_biosparam: dev=%s, size=%d, ", + kdevname(dev), disk->capacity); #endif - -/* I took this from other SCSI drivers, since it provides - the correct data for my devices. */ + + /* try default translation */ info_array[0]=64; info_array[1]=32; - info_array[2]=size>>11; + info_array[2]=disk->capacity / (64 * 32); + + /* for disks >1GB do some guessing */ + if(info_array[2]>=1024) { + int info[3]; + + /* try to figure out the geometry from the partition table */ + 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"); + 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" + " 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"); + } + } else { + info_array[0]=info[0]; + info_array[1]=info[1]; + 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"); + } + } + } #if defined(DEBUG_BIOSPARAM) - if(aha152x_debug & 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"); @@ -1135,82 +1457,81 @@ int aha152x_biosparam(Scsi_Disk * disk, int dev, int *info_array ) /* * Internal done function */ -void aha152x_done( int error ) +void aha152x_done(struct Scsi_Host *shpnt, int error) { unsigned long flags; Scsi_Cmnd *done_SC; #if defined(DEBUG_DONE) - if(aha152x_debug & debug_done) - { + if(HOSTDATA(shpnt)->debug & debug_done) { printk("\naha152x: done(), "); - disp_ports(); + disp_ports(shpnt); } #endif - if (current_SC) - { + if(CURRENT_SC) { #if defined(DEBUG_DONE) - if(aha152x_debug & debug_done) - printk("done(%x), ", error); + if(HOSTDATA(shpnt)->debug & debug_done) + printk("done(%x), ", error); #endif - save_flags(flags); - cli(); + save_flags(flags); + cli(); - done_SC = current_SC; - current_SC = NULL; + done_SC = CURRENT_SC; + CURRENT_SC = NULL; - /* turn led off, when no commands are in the driver */ - commands--; - if(!commands) - SETPORT( PORTA, 0 ); /* turn led off */ + /* 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(aha152x_debug & debug_queues) - printk("ok (%d), ", commands); + if(HOSTDATA(shpnt)->debug & debug_queues) + printk("ok (%d), ", HOSTDATA(shpnt)->commands); #endif - restore_flags(flags); + restore_flags(flags); - SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 ); - SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0); + 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(aha152x_debug & debug_phases) - printk("BUS FREE loop, "); + if(HOSTDATA(shpnt)->debug & debug_phases) + printk("BUS FREE loop, "); #endif - while( TESTLO( SSTAT1, BUSFREE ) ) - ; + while(TESTLO(SSTAT1, BUSFREE)) + barrier(); #if defined(DEBUG_PHASES) - if(aha152x_debug & debug_phases) - printk("BUS FREE\n"); + if(HOSTDATA(shpnt)->debug & debug_phases) + printk("BUS FREE\n"); +#endif #endif - done_SC->result = error; - if(done_SC->scsi_done) - { + done_SC->result = error; + if(done_SC->scsi_done) { #if defined(DEBUG_DONE) - if(aha152x_debug & debug_done) - printk("calling scsi_done, "); + if(HOSTDATA(shpnt)->debug & debug_done) + printk("calling scsi_done, "); #endif - done_SC->scsi_done( done_SC ); + done_SC->scsi_done(done_SC); #if defined(DEBUG_DONE) - if(aha152x_debug & debug_done) - printk("done returned, "); + if(HOSTDATA(shpnt)->debug & debug_done) + printk("done returned, "); #endif - } - else - panic( "aha152x: current_SC->scsi_done() == NULL" ); - } - else - aha152x_panic( "done() called outside of command" ); + } else + panic("aha152x: current_SC->scsi_done() == NULL"); + } else + aha152x_panic(shpnt, "done() called outside of command"); } /* * Interrupts handler (main routine of the driver) */ -void aha152x_intr( int irqno, struct pt_regs * regs ) +void aha152x_intr(int irqno, void *dev_id, struct pt_regs * regs) { + struct Scsi_Host *shpnt = aha152x_host[irqno-IRQ_MIN]; unsigned int flags; int done=0, phase; @@ -1218,1248 +1539,1209 @@ void aha152x_intr( int irqno, struct pt_regs * regs ) enter_driver("intr"); #else #if defined(DEBUG_INTR) - if(aha152x_debug & debug_intr) + if(HOSTDATA(shpnt)->debug & debug_intr) printk("\naha152x: intr(), "); #endif #endif - /* no more interrupts from the controller, while we busy. + if(!shpnt) + panic("aha152x: catched interrupt for unknown controller.\n"); + + /* no more interrupts from the controller, while we're busy. INTEN has to be restored, when we're ready to leave - intr(). To avoid race conditions we have to return + intr(). To avoid race conditions, we have to return immediately afterwards. */ - CLRBITS( DMACNTRL0, INTEN); + CLRBITS(DMACNTRL0, INTEN); sti(); /* Yes, sti() really needs to be here */ /* disconnected target is trying to reconnect. Only possible, if we have disconnected nexuses and nothing is occupying the bus. */ - if( TESTHI( SSTAT0, SELDI ) && - disconnected_SC && - ( !current_SC || ( current_SC->SCp.phase & in_selection ) ) - ) - { - int identify_msg, target, i; - - /* Avoid conflicts when a target reconnects - while we are trying to connect to another. */ - if(current_SC) - { + if(TESTHI(SSTAT0, SELDI) && + DISCONNECTED_SC && + (!CURRENT_SC || (CURRENT_SC->SCp.phase & in_selection)) ) { + int identify_msg, target, i; + + /* Avoid conflicts when a target reconnects + while we are trying to connect to another. */ + if(CURRENT_SC) { #if defined(DEBUG_QUEUES) - if(aha152x_debug & debug_queues) - printk("i+, "); -#endif - save_flags(flags); - cli(); - append_SC( &issue_SC, current_SC); - current_SC=NULL; - restore_flags(flags); - } + if(HOSTDATA(shpnt)->debug & debug_queues) + printk("i+, "); +#endif + save_flags(flags); + cli(); + append_SC(&ISSUE_SC, CURRENT_SC); + CURRENT_SC=NULL; + restore_flags(flags); + } - /* disable sequences */ - SETPORT( SCSISEQ, 0 ); - SETPORT( SSTAT0, CLRSELDI ); - SETPORT( SSTAT1, CLRBUSFREE ); + /* disable sequences */ + SETPORT(SCSISEQ, 0); + SETPORT(SSTAT0, CLRSELDI); + SETPORT(SSTAT1, CLRBUSFREE); #if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES) - if(aha152x_debug & (debug_queues|debug_phases)) - printk("reselected, "); + if(HOSTDATA(shpnt)->debug & (debug_queues|debug_phases)) + printk("reselected, "); #endif - i = GETPORT(SELID) & ~(1 << this_host); - target=0; - if(i) - for( ; (i & 1)==0; target++, i>>=1) - ; - else - aha152x_panic("reconnecting target unknown"); + i = GETPORT(SELID) & ~(1 << shpnt->this_id); + target=0; + + if(i==0) + aha152x_panic(shpnt, "reconnecting target unknown"); + + for(; (i & 1)==0; target++, i>>=1) + ; #if defined(DEBUG_QUEUES) - if(aha152x_debug & debug_queues) - printk("SELID=%02x, target=%d, ", GETPORT(SELID), target ); + if(HOSTDATA(shpnt)->debug & debug_queues) + printk("SELID=%02x, target=%d, ", GETPORT(SELID), target); #endif - SETPORT( SCSIID, (this_host << OID_) | target ); - SETPORT( SCSISEQ, ENRESELI ); + SETPORT(SCSIID, (shpnt->this_id << OID_) | target); + SETPORT(SCSISEQ, ENRESELI); - if(TESTLO( SSTAT0, SELDI )) - aha152x_panic("RESELI failed"); + if(TESTLO(SSTAT0, SELDI)) + aha152x_panic(shpnt, "RESELI failed"); - SETPORT( SCSISIG, P_MSGI ); + SETPORT(SCSIRATE, HOSTDATA(shpnt)->syncrate[target]&0x7f); - /* Get identify message */ - if((i=getphase())!=P_MSGI) - { - printk("target doesn't enter MSGI to identify (phase=%02x)\n", i); - aha152x_panic("unknown lun"); - } - SETPORT( SCSISEQ, 0 ); + SETPORT(SCSISIG, P_MSGI); - SETPORT( SXFRCTL0, CH1); + /* 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"); + } + SETPORT(SCSISEQ, 0); - identify_msg = GETPORT(SCSIBUS); + SETPORT(SXFRCTL0, CH1); - if(!(identify_msg & IDENTIFY_BASE)) - { - printk("target=%d, inbound message (%02x) != IDENTIFY\n", - target, identify_msg); - aha152x_panic("unknown lun"); - } + 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"); + } - make_acklow(); - getphase(); #if defined(DEBUG_QUEUES) - if(aha152x_debug & debug_queues) - printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f ); + if(HOSTDATA(shpnt)->debug & debug_queues) + printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f); #endif - save_flags(flags); - cli(); + save_flags(flags); + cli(); #if defined(DEBUG_QUEUES) - if(aha152x_debug & debug_queues) - printk("d-, "); + if(HOSTDATA(shpnt)->debug & debug_queues) + printk("d-, "); #endif - current_SC = remove_SC( &disconnected_SC, - target, - identify_msg & 0x3f ); + CURRENT_SC = remove_SC(&DISCONNECTED_SC, target, identify_msg & 0x3f); - if(!current_SC) - { - printk("lun=%d, ", identify_msg & 0x3f ); - aha152x_panic("no disconnected command for that lun"); - } + 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); + CURRENT_SC->SCp.phase &= ~disconnected; + restore_flags(flags); - SETPORT( SIMODE0, 0 ); - SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE ); + make_acklow(shpnt); + if(getphase(shpnt)!=P_MSGI) { + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); #if defined(DEBUG_RACE) leave_driver("(reselected) intr"); #endif - SETBITS( DMACNTRL0, INTEN); + SETBITS(DMACNTRL0, INTEN); return; } + } /* Check, if we aren't busy with a command */ - if(!current_SC) - { - /* bus is free to issue a queued command */ - if(TESTHI( SSTAT1, BUSFREE) && issue_SC) - { - save_flags(flags); - cli(); + if(!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(aha152x_debug & debug_queues) - printk("i-, "); + if(HOSTDATA(shpnt)->debug & debug_queues) + printk("i-, "); #endif - current_SC = remove_first_SC( &issue_SC ); - restore_flags(flags); + CURRENT_SC = remove_first_SC(&ISSUE_SC); + restore_flags(flags); #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if(aha152x_debug & (debug_intr|debug_selection|debug_phases)) - printk("issuing command, "); + if(HOSTDATA(shpnt)->debug & (debug_intr|debug_selection|debug_phases)) + printk("issuing command, "); #endif - current_SC->SCp.phase = in_selection; + CURRENT_SC->SCp.phase = in_selection; - #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if(aha152x_debug & (debug_intr|debug_selection|debug_phases)) - printk("selecting %d, ", current_SC->target); - #endif - SETPORT( SCSIID, (this_host << OID_) | current_SC->target ); +#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) + if(HOSTDATA(shpnt)->debug & (debug_intr|debug_selection|debug_phases)) + printk("selecting %d, ", CURRENT_SC->target); +#endif + SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); - /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */ - SETPORT( SXFRCTL1, can_doparity ? (ENSPCHK|ENSTIMER) : ENSTIMER); + /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */ + SETPORT(SXFRCTL1, HOSTDATA(shpnt)->parity ? (ENSPCHK|ENSTIMER) : ENSTIMER); - /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ - SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) ); - SETPORT( SIMODE1, ENSELTIMO ); + /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ + SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); + SETPORT(SIMODE1, ENSELTIMO); - /* Enable SELECTION OUT sequence */ - SETBITS(SCSISEQ, ENSELO | ENAUTOATNO ); + /* Enable SELECTION OUT sequence */ + SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); - #if defined(DEBUG_RACE) - leave_driver("(selecting) intr"); - #endif - SETBITS( DMACNTRL0, INTEN ); - return; - } - + } else { /* No command we are busy with and no new to issue */ printk("aha152x: ignoring spurious interrupt, nothing to do\n"); - return; + if(TESTHI(DMACNTRL0, SWINT)) { + printk("aha152x: SWINT is set! Why?\n"); + CLRBITS(DMACNTRL0, SWINT); + } + show_queues(shpnt); } +#if defined(DEBUG_RACE) + leave_driver("(selecting) intr"); +#endif + SETBITS(DMACNTRL0, INTEN); + return; + } + /* the bus is busy with something */ #if defined(DEBUG_INTR) - if(aha152x_debug & debug_intr) - disp_ports(); + if(HOSTDATA(shpnt)->debug & debug_intr) + disp_ports(shpnt); #endif /* 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); + 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 sequence */ + CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO); - /* Disable SELECTION OUT DONE interrupt */ - CLRBITS(SIMODE0, ENSELDO); - CLRBITS(SIMODE1, ENSELTIMO); + /* Disable SELECTION OUT DONE interrupt */ + CLRBITS(SIMODE0, ENSELDO); + CLRBITS(SIMODE1, ENSELTIMO); - if( TESTLO(SSTAT0, SELDO) ) - { - printk("aha152x: passing bus free condition\n"); + if(TESTLO(SSTAT0, SELDO)) { + printk("aha152x: passing bus free condition\n"); #if defined(DEBUG_RACE) - leave_driver("(passing bus free) intr"); + leave_driver("(passing bus free) intr"); #endif - SETBITS( DMACNTRL0, INTEN); + SETBITS(DMACNTRL0, INTEN); - if(current_SC->SCp.phase & aborted) - { - abort_result=SCSI_ABORT_ERROR; - abortion_complete++; - } + if(CURRENT_SC->SCp.phase & aborted) { + HOSTDATA(shpnt)->abort_result=SCSI_ABORT_ERROR; + HOSTDATA(shpnt)->abortion_complete++; + } - aha152x_done( DID_NO_CONNECT << 16 ); - return; - } + aha152x_done(shpnt, DID_NO_CONNECT << 16); + + return; + } #if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if(aha152x_debug & (debug_selection|debug_phases)) - printk("SELDO (SELID=%x), ", GETPORT(SELID)); + if(HOSTDATA(shpnt)->debug & (debug_selection|debug_phases)) + printk("SELDO (SELID=%x), ", GETPORT(SELID)); #endif - /* selection was done */ - SETPORT( SSTAT0, CLRSELDO ); + /* selection was done */ + SETPORT(SSTAT0, CLRSELDO); #if defined(DEBUG_ABORT) - if((aha152x_debug & debug_abort) && (current_SC->SCp.phase & aborted)) - printk("(ABORT) target selected, "); + if((HOSTDATA(shpnt)->debug & debug_abort) && (CURRENT_SC->SCp.phase & aborted)) + printk("(ABORT) target selected, "); #endif - current_SC->SCp.phase &= ~in_selection; - current_SC->SCp.phase |= in_other; + CURRENT_SC->SCp.phase &= ~in_selection; + CURRENT_SC->SCp.phase |= in_other; + + ADDMSG(IDENTIFY(HOSTDATA(shpnt)->reconnect,CURRENT_SC->lun)); + + if(!(SYNCRATE&0x80) && HOSTDATA(shpnt)->synchronous) { + ADDMSG(EXTENDED_MESSAGE); + ADDMSG(3); + ADDMSG(EXTENDED_SDTR); + ADDMSG(50); + ADDMSG(8); + + printk("outbound SDTR: "); + print_msg(&MSG(MSGLEN-5)); + + SYNCRATE=0x80; + CURRENT_SC->SCp.phase |= in_sync; + } #if defined(DEBUG_RACE) - leave_driver("(SELDO) intr"); + leave_driver("(SELDO) intr"); #endif + SETPORT(SCSIRATE, SYNCRATE&0x7f); - SETPORT( SCSISIG, P_MSGO ); + SETPORT(SCSISIG, P_MSGO); - SETPORT( SIMODE0, 0 ); - SETPORT( SIMODE1, ENREQINIT|ENBUSFREE ); - SETBITS( DMACNTRL0, INTEN); - return; - } - else - aha152x_panic("neither timeout nor selection\007"); - else - { + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENREQINIT|ENBUSFREE); + SETBITS(DMACNTRL0, INTEN); + + return; + } else + aha152x_panic(shpnt, "neither timeout nor selection\007"); + else { #if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if(aha152x_debug & (debug_selection|debug_phases)) - printk("SELTO, "); + if(HOSTDATA(shpnt)->debug & (debug_selection|debug_phases)) + printk("SELTO, "); #endif - /* end selection attempt */ - CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO ); + /* end selection attempt */ + CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO); - /* timeout */ - SETPORT( SSTAT1, CLRSELTIMO ); + /* timeout */ + SETPORT(SSTAT1, CLRSELTIMO); - SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 ); - SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0); - SETBITS( DMACNTRL0, INTEN ); + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + SETBITS(DMACNTRL0, INTEN); #if defined(DEBUG_RACE) - leave_driver("(SELTO) intr"); + leave_driver("(SELTO) intr"); #endif - if(current_SC->SCp.phase & aborted) - { + if(CURRENT_SC->SCp.phase & aborted) { #if defined(DEBUG_ABORT) - if(aha152x_debug & debug_abort) - printk("(ABORT) selection timeout, "); + if(HOSTDATA(shpnt)->debug & debug_abort) + printk("(ABORT) selection timeout, "); #endif - abort_result=SCSI_ABORT_ERROR; - abortion_complete++; - } + HOSTDATA(shpnt)->abort_result=SCSI_ABORT_ERROR; + HOSTDATA(shpnt)->abortion_complete++; + } - if( TESTLO( SSTAT0, SELINGO ) ) - /* ARBITRATION not won */ - aha152x_done( DID_BUS_BUSY << 16 ); - else - /* ARBITRATION won, but SELECTION failed */ - aha152x_done( DID_NO_CONNECT << 16 ); - return; - } + 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); + + return; } + } /* enable interrupt, when target leaves current phase */ - phase = getphase(); + 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 ); + CURRENT_SC->SCp.phase = + (CURRENT_SC->SCp.phase & ~((P_MASK|1)<<16)) | (phase << 16); /* information transfer phase */ - switch( phase ) + switch(phase) { + case P_MSGO: /* MESSAGE OUT */ { - case P_MSGO: /* MESSAGE OUT */ - { - unsigned char message; + int i, identify=0, abort=0; #if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES) - if(aha152x_debug & (debug_intr|debug_msgo|debug_phases)) - printk("MESSAGE OUT, "); + if(HOSTDATA(shpnt)->debug & (debug_intr|debug_msgo|debug_phases)) + printk("MESSAGE OUT, "); #endif - - if( current_SC->SCp.phase & aborted ) - { -#if defined(DEBUG_MSGO) || defined(DEBUG_ABORT) - if(aha152x_debug & (debug_msgo|debug_abort)) - printk("ABORT, "); + if(MSGLEN==0) { + ADDMSG(MESSAGE_REJECT); +#if defined(DEBUG_MSGO) + if(HOSTDATA(shpnt)->debug & debug_msgo) + printk("unexpected MESSAGE OUT phase; rejecting, "); #endif - message=ABORT; - } - else - /* If we didn't identify yet, do it. Otherwise there's nothing to do, - but reject (probably we got an message before, that we have to - reject (SDTR, WDTR, etc.) */ - if( !(current_SC->SCp.phase & sent_ident)) - { - message=IDENTIFY(can_disconnect,current_SC->lun); + } + + CLRBITS(SXFRCTL0, ENDMA); + + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE); + + /* wait for data latch to become ready or a phase change */ + while(TESTLO(DMASTAT, INTSTAT)) + barrier(); + #if defined(DEBUG_MSGO) - if(aha152x_debug & debug_msgo) - printk("IDENTIFY (reconnect=%s;lun=%d), ", - can_disconnect ? "enabled" : "disabled", current_SC->lun); + if(HOSTDATA(shpnt)->debug & debug_msgo) { + int i; + + printk("messages ("); + for(i=0; i<MSGLEN; i+=print_msg(&MSG(i)), printk(" ")) + ; + printk("), "); + } #endif - } - else - { - message=MESSAGE_REJECT; + + for(i=0; i<MSGLEN && TESTLO(SSTAT1, PHASEMIS); i++) { #if defined(DEBUG_MSGO) - if(aha152x_debug & debug_msgo) - printk("REJECT, "); + if(HOSTDATA(shpnt)->debug & debug_msgo) + printk("%x ", MSG(i)); #endif - } + if(i==MSGLEN-1) { + /* Leave MESSAGE OUT after transfer */ + SETPORT(SSTAT1, CLRATNO); + } - CLRBITS( SXFRCTL0, ENDMA); - - SETPORT( SIMODE0, 0 ); - SETPORT( SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE ); + SETPORT(SCSIDAT, MSG(i)); - /* wait for data latch to become ready or a phase change */ - while( TESTLO( DMASTAT, INTSTAT ) ) - ; + make_acklow(shpnt); + getphase(shpnt); - if( TESTHI( SSTAT1, PHASEMIS ) ) - aha152x_panic("unable to send message"); + if(MSG(i)==IDENTIFY(HOSTDATA(shpnt)->reconnect,CURRENT_SC->lun)) + identify++; - /* Leave MESSAGE OUT after transfer */ - SETPORT( SSTAT1, CLRATNO); + if(MSG(i)==ABORT) + abort++; - SETPORT( SCSIDAT, message ); + } - make_acklow(); - getphase(); + MSGLEN=0; - if(message==IDENTIFY(can_disconnect,current_SC->lun)) - current_SC->SCp.phase |= sent_ident; + if(identify) + CURRENT_SC->SCp.phase |= sent_ident; - if(message==ABORT) - { - /* revive abort(); abort() enables interrupts */ - abort_result=SCSI_ABORT_SUCCESS; - abortion_complete++; + if(abort) { + /* revive abort(); abort() enables interrupts */ + HOSTDATA(shpnt)->abort_result=SCSI_ABORT_SUCCESS; + HOSTDATA(shpnt)->abortion_complete++; - current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16)); + CURRENT_SC->SCp.phase &= ~(P_MASK<<16); - /* exit */ - SETBITS( DMACNTRL0, INTEN ); + /* exit */ + SETBITS(DMACNTRL0, INTEN); #if defined(DEBUG_RACE) - leave_driver("(ABORT) intr"); + leave_driver("(ABORT) intr"); #endif - aha152x_done(DID_ABORT<<16); - return; - } + aha152x_done(shpnt, DID_ABORT<<16); + + return; } - break; + } + break; - case P_CMD: /* COMMAND phase */ + case P_CMD: /* COMMAND phase */ #if defined(DEBUG_INTR) || defined(DEBUG_CMD) || defined(DEBUG_PHASES) - if(aha152x_debug & (debug_intr|debug_cmd|debug_phases)) - printk("COMMAND, "); -#endif - if( !(current_SC->SCp.sent_command) ) - { - if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT)) - printk("aha152x: P_CMD: %d(%d) bytes left in FIFO, resetting\n", - GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT)); - - /* reset fifo and enable writes */ - SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO); - SETPORT(DMACNTRL0, ENDMA|WRITE_READ); - - /* clear transfer count and scsi fifo */ - SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 ); - SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1); - - /* missing phase raises INTSTAT */ - SETPORT( SIMODE0, 0 ); - SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE ); - -#if defined(DEBUG_CMD) - if(aha152x_debug & debug_cmd) - printk("waiting, "); -#endif - /* wait for FIFO to get empty */ - while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) ) - ; - - if( TESTHI( SSTAT1, PHASEMIS ) ) - aha152x_panic("target left COMMAND phase"); - -#if defined(DEBUG_CMD) - if(aha152x_debug & debug_cmd) - { - printk("DFIFOEMP, outsw (%d bytes, %d words), ", - current_SC->cmd_len, current_SC->cmd_len >> 1 ); - disp_ports(); - } + if(HOSTDATA(shpnt)->debug & (debug_intr|debug_cmd|debug_phases)) + printk("COMMAND, "); #endif - - outsw( DATAPORT, ¤t_SC->cmnd, current_SC->cmd_len >> 1 ); + if(!(CURRENT_SC->SCp.sent_command)) { + int i; -#if defined(DEBUG_CMD) - if(aha152x_debug & debug_cmd) - { - printk("FCNT=%d, STCNT=%d, ", GETPORT(FIFOSTAT), GETSTCNT() ); - disp_ports(); - } -#endif - -#if defined(DEBUG_CMD) - if(aha152x_debug & debug_cmd) - printk("waiting for SEMPTY, "); -#endif - - /* wait for SCSI FIFO to get empty. - very important to send complete commands. */ - while( TESTLO ( SSTAT2, SEMPTY ) ) - ; - -#if defined(DEBUG_CMD) - if(aha152x_debug & debug_cmd) - printk("SEMPTY, "); -#endif + CLRBITS(SXFRCTL0, ENDMA); - CLRBITS(SXFRCTL0, SCSIEN|DMAEN); - /* transfer can be considered ended, when SCSIEN reads back zero */ - while( TESTHI( SXFRCTL0, SCSIEN ) ) - ; - -#if defined(DEBUG_CMD) - if(aha152x_debug & debug_cmd) - printk("!SEMPTY, "); -#endif + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE); + + /* wait for data latch to become ready or a phase change */ + while(TESTLO(DMASTAT, INTSTAT)) + barrier(); + + for(i=0; i<CURRENT_SC->cmd_len && TESTLO(SSTAT1, PHASEMIS); i++) { + SETPORT(SCSIDAT, CURRENT_SC->cmnd[i]); - CLRBITS(DMACNTRL0, ENDMA); + make_acklow(shpnt); + getphase(shpnt); + } -#if defined(DEBUG_CMD) || defined(DEBUG_INTR) - if(debug_cmd & debug_intr) - printk("sent %d/%d command bytes, ", GETSTCNT(), - current_SC->cmd_len); -#endif + if(i<CURRENT_SC->cmd_len && TESTHI(SSTAT1, PHASEMIS)) + aha152x_panic(shpnt, "target left COMMAND"); - } - else - aha152x_panic("Nothing to sent while in COMMAND OUT"); + CURRENT_SC->SCp.sent_command++; + } else + aha152x_panic(shpnt, "Nothing to send while in COMMAND"); break; - case P_MSGI: /* MESSAGE IN phase */ + case P_MSGI: /* MESSAGE IN phase */ + { + int start_sync=0; + #if defined(DEBUG_INTR) || defined(DEBUG_MSGI) || defined(DEBUG_PHASES) - if(aha152x_debug & (debug_intr|debug_msgi|debug_phases)) + if(HOSTDATA(shpnt)->debug & (debug_intr|debug_msgi|debug_phases)) printk("MESSAGE IN, "); #endif - SETPORT( SXFRCTL0, CH1); + SETPORT(SXFRCTL0, CH1); - SETPORT( SIMODE0, 0); - SETPORT( SIMODE1, ENBUSFREE); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENBUSFREE); - while( phase == P_MSGI ) - { - current_SC->SCp.Message = GETPORT( SCSIBUS ); - switch(current_SC->SCp.Message) - { - case DISCONNECT: + 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(aha152x_debug & (debug_msgi|debug_phases)) - printk("target disconnected, "); + if(HOSTDATA(shpnt)->debug & (debug_msgi|debug_phases)) + printk("target disconnected, "); #endif - current_SC->SCp.Message = 0; - current_SC->SCp.phase |= disconnected; - if(!can_disconnect) - aha152x_panic("target was not allowed to disconnect"); - break; + 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: + case COMMAND_COMPLETE: #if defined(DEBUG_MSGI) || defined(DEBUG_PHASES) - if(aha152x_debug & (debug_msgi|debug_phases)) - printk("inbound message ( COMMAND COMPLETE ), "); + if(HOSTDATA(shpnt)->debug & (debug_msgi|debug_phases)) + printk("inbound message (COMMAND COMPLETE), "); #endif - done++; - break; + done++; + break; - case MESSAGE_REJECT: + 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(aha152x_debug & debug_msgi) - printk("inbound message ( MESSAGE REJECT ), "); + if(HOSTDATA(shpnt)->debug & debug_msgi) + printk("inbound message (MESSAGE REJECT), "); #endif - break; + break; - case SAVE_POINTERS: + case SAVE_POINTERS: #if defined(DEBUG_MSGI) - if(aha152x_debug & debug_msgi) - printk("inbound message ( SAVE DATA POINTERS ), "); + if(HOSTDATA(shpnt)->debug & debug_msgi) + printk("inbound message (SAVE DATA POINTERS), "); #endif - break; + 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: - { - int i, code; + case EXTENDED_MESSAGE: + { + char buffer[16]; + int i; #if defined(DEBUG_MSGI) - if(aha152x_debug & debug_msgi) - printk("inbound message ( EXTENDED MESSAGE ), "); + if(HOSTDATA(shpnt)->debug & debug_msgi) + printk("inbound message (EXTENDED MESSAGE), "); #endif - make_acklow(); - if(getphase()!=P_MSGI) - break; + make_acklow(shpnt); + if(getphase(shpnt)!=P_MSGI) + break; - i=GETPORT(SCSIBUS); + buffer[0]=EXTENDED_MESSAGE; + buffer[1]=GETPORT(SCSIDAT); + + for(i=0; i<buffer[1] && + (make_acklow(shpnt), getphase(shpnt)==P_MSGI); i++) + buffer[2+i]=GETPORT(SCSIDAT); #if defined(DEBUG_MSGI) - if(aha152x_debug & debug_msgi) - printk("length (%d), code ( ", i); + if(HOSTDATA(shpnt)->debug & debug_msgi) + print_msg(buffer); #endif - make_acklow(); - if(getphase()!=P_MSGI) + switch(buffer [2]) { + case EXTENDED_SDTR: + { + long ticks; + + if(buffer[1]!=3) + aha152x_panic(shpnt, "SDTR message length != 3"); + + if(!HOSTDATA(shpnt)->synchronous) break; - code = GETPORT(SCSIBUS); + printk("inbound SDTR: "); print_msg(buffer); - switch( code ) - { - case 0x00: -#if defined(DEBUG_MSGI) - if(aha152x_debug & debug_msgi) - printk("MODIFY DATA POINTER "); -#endif - SETPORT(SCSISIG, P_MSGI|ATNO); - break; - case 0x01: -#if defined(DEBUG_MSGI) - if(aha152x_debug & debug_msgi) - printk("SYNCHRONOUS DATA TRANSFER REQUEST "); -#endif - SETPORT(SCSISIG, P_MSGI|ATNO); - break; - case 0x02: -#if defined(DEBUG_MSGI) - if(aha152x_debug & debug_msgi) - printk("EXTENDED IDENTIFY "); -#endif - break; - case 0x03: -#if defined(DEBUG_MSGI) - if(aha152x_debug & debug_msgi) - printk("WIDE DATA TRANSFER REQUEST "); -#endif - SETPORT(SCSISIG, P_MSGI|ATNO); - break; - default: -#if defined(DEBUG_MSGI) - if(aha152x_debug & debug_msgi) - if( code & 0x80 ) - printk("reserved (%d) ", code ); - else - printk("vendor specific (%d) ", code); -#endif - SETPORT(SCSISIG, P_MSGI|ATNO); - break; - } -#if defined(DEBUG_MSGI) - if(aha152x_debug & debug_msgi) - printk(" ), data ( "); -#endif - while( --i && (make_acklow(), getphase()==P_MSGI)) - { -#if defined(DEBUG_MSGI) - if(aha152x_debug & debug_msgi) - printk("%x ", GETPORT(SCSIBUS) ); -#else - GETPORT(SCSIBUS); -#endif - } -#if defined(DEBUG_MSGI) - if(aha152x_debug & debug_msgi) - printk(" ), "); -#endif - /* We reject all extended messages. To do this - we just enter MSGO by asserting ATN. Since - we have already identified a REJECT message - will be sent. */ - SETPORT(SCSISIG, P_MSGI|ATNO); + ticks=(buffer[3]*4+49)/50; + + 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; + + ADDMSG(EXTENDED_MESSAGE); + ADDMSG(3); + ADDMSG(EXTENDED_SDTR); + if(ticks<4) { + ticks=4; + ADDMSG(50); + } else + ADDMSG(buffer[3]); + + ADDMSG(buffer[4]); + + printk("outbound SDTR: "); + print_msg(&MSG(MSGLEN-5)); + + CURRENT_SC->SCp.phase |= in_sync; + + SYNCRATE |= ((ticks-2)<<4) + buffer[4]; + + start_sync++; + } else { + /* requested SDTR is too slow, do it asynchronously */ + ADDMSG(MESSAGE_REJECT); + SYNCRATE = 0; + } + + SETPORT(SCSIRATE, SYNCRATE&0x7f); } break; - + + case EXTENDED_MODIFY_DATA_POINTER: + case EXTENDED_EXTENDED_IDENTIFY: + case EXTENDED_WDTR: default: - printk("unsupported inbound message %x, ", current_SC->SCp.Message); + ADDMSG(MESSAGE_REJECT); break; - } + } + break; + + default: + printk("unsupported inbound message %x, ", CURRENT_SC->SCp.Message); + break; + + } - make_acklow(); - phase=getphase(); - } + make_acklow(shpnt); + phase=getphase(shpnt); + } + if(start_sync) + CURRENT_SC->SCp.phase |= in_sync; + else + CURRENT_SC->SCp.phase &= ~in_sync; + + if(MSGLEN>0) + SETPORT(SCSISIG, P_MSGI|ATNO); + /* clear SCSI fifo on BUSFREE */ if(phase==P_BUSFREE) SETPORT(SXFRCTL0, CH1|CLRCH1); - if(current_SC->SCp.phase & disconnected) - { - save_flags(flags); - cli(); + if(CURRENT_SC->SCp.phase & disconnected) { + save_flags(flags); + cli(); #if defined(DEBUG_QUEUES) - if(aha152x_debug & debug_queues) - printk("d+, "); + if(HOSTDATA(shpnt)->debug & debug_queues) + printk("d+, "); #endif - append_SC( &disconnected_SC, current_SC); - current_SC = NULL; - restore_flags(flags); + append_SC(&DISCONNECTED_SC, CURRENT_SC); + CURRENT_SC->SCp.phase |= 1<<16; + CURRENT_SC = NULL; + restore_flags(flags); - SETBITS( SCSISEQ, ENRESELI ); + SETBITS(SCSISEQ, ENRESELI); - SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 ); - SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0); + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - SETBITS( DMACNTRL0, INTEN ); - return; - } - break; + SETBITS(DMACNTRL0, INTEN); + + return; + } + } + break; - case P_STATUS: /* STATUS IN phase */ + case P_STATUS: /* STATUS IN phase */ #if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - if(aha152x_debug & (debug_status|debug_intr|debug_phases)) - printk("STATUS, "); + if(HOSTDATA(shpnt)->debug & (debug_status|debug_intr|debug_phases)) + printk("STATUS, "); #endif - SETPORT( SXFRCTL0, CH1); + SETPORT(SXFRCTL0, CH1); - SETPORT( SIMODE0, 0 ); - SETPORT( SIMODE1, ENREQINIT|ENBUSFREE ); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENREQINIT|ENBUSFREE); - if( TESTHI( SSTAT1, PHASEMIS ) ) - printk("aha152x: passing STATUS phase"); - - current_SC->SCp.Status = GETPORT( SCSIBUS ); - make_acklow(); - getphase(); + if(TESTHI(SSTAT1, PHASEMIS)) + printk("aha152x: passing STATUS phase"); + + CURRENT_SC->SCp.Status = GETPORT(SCSIBUS); + make_acklow(shpnt); + getphase(shpnt); #if defined(DEBUG_STATUS) - if(aha152x_debug & debug_status) - { - printk("inbound status "); - print_status( current_SC->SCp.Status ); - printk(", "); - } + if(HOSTDATA(shpnt)->debug & debug_status) { + printk("inbound status "); + print_status(CURRENT_SC->SCp.Status); + printk(", "); + } #endif - break; + break; - case P_DATAI: /* DATA IN phase */ - { - int fifodata, data_count, done; + case P_DATAI: /* DATA IN phase */ + { + int fifodata, data_count, done; #if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - if(aha152x_debug & (debug_datai|debug_intr|debug_phases)) - printk("DATA IN, "); + if(HOSTDATA(shpnt)->debug & (debug_datai|debug_intr|debug_phases)) + printk("DATA IN, "); #endif - 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)); +#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 - /* reset host fifo */ - SETPORT(DMACNTRL0, RSTFIFO); - SETPORT(DMACNTRL0, RSTFIFO|ENDMA); + /* reset host fifo */ + SETPORT(DMACNTRL0, RSTFIFO); + SETPORT(DMACNTRL0, RSTFIFO|ENDMA); - SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN ); + SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); - SETPORT( SIMODE0, 0 ); - SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE ); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); - /* done is set when the FIFO is empty after the target left DATA IN */ - done=0; + /* done is set when the FIFO is empty after the target left DATA IN */ + done=0; - /* while the target stays in DATA to transfer data */ - while ( !done ) - { + /* while the target stays in DATA to transfer data */ + while (!done) { #if defined(DEBUG_DATAI) - if(aha152x_debug & debug_datai) - printk("expecting data, "); + if(HOSTDATA(shpnt)->debug & debug_datai) + printk("expecting data, "); #endif - /* wait for PHASEMIS or full FIFO */ - while( TESTLO ( DMASTAT, DFIFOFULL|INTSTAT ) ) - ; - - if( TESTHI( DMASTAT, DFIFOFULL ) ) - fifodata=GETPORT(FIFOSTAT); - else - { - /* wait for SCSI fifo to get empty */ - while( TESTLO( SSTAT2, SEMPTY ) ) - ; + /* wait for PHASEMIS or full FIFO */ + while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) + barrier(); - /* rest of data in FIFO */ - fifodata=GETPORT(FIFOSTAT); #if defined(DEBUG_DATAI) - if(aha152x_debug & debug_datai) - printk("last transfer, "); + if(HOSTDATA(shpnt)->debug & debug_datai) + printk("ok, "); +#endif + + if(TESTHI(DMASTAT, DFIFOFULL)) + fifodata=GETPORT(FIFOSTAT); + else { + /* wait for SCSI fifo to get empty */ + while(TESTLO(SSTAT2, SEMPTY)) + barrier(); + + /* rest of data in FIFO */ + fifodata=GETPORT(FIFOSTAT); +#if defined(DEBUG_DATAI) + if(HOSTDATA(shpnt)->debug & debug_datai) + printk("last transfer, "); #endif - done=1; - } + done=1; + } #if defined(DEBUG_DATAI) - if(aha152x_debug & debug_datai) - printk("fifodata=%d, ", fifodata); + if(HOSTDATA(shpnt)->debug & debug_datai) + printk("fifodata=%d, ", fifodata); #endif - while( fifodata && current_SC->SCp.this_residual ) - { - data_count=fifodata; + while(fifodata && CURRENT_SC->SCp.this_residual) { + data_count=fifodata; - /* limit data transfer to size of first sg buffer */ - if (data_count > current_SC->SCp.this_residual) - data_count = current_SC->SCp.this_residual; + /* limit data transfer to size of first sg buffer */ + if(data_count > CURRENT_SC->SCp.this_residual) + data_count = CURRENT_SC->SCp.this_residual; - fifodata -= data_count; + fifodata -= data_count; #if defined(DEBUG_DATAI) - if(aha152x_debug & debug_datai) - printk("data_count=%d, ", data_count); + if(HOSTDATA(shpnt)->debug & debug_datai) + printk("data_count=%d, ", data_count); #endif - 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(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(aha152x_debug & debug_datai) -/* show what comes with the last transfer */ - if(done) - { - int i; - unsigned char *data; + if(HOSTDATA(shpnt)->debug & debug_datai) + /* show what comes with the last transfer */ + if(done) { +#if 0 + int i; + unsigned char *data; +#endif - 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 - 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; - } + 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; + } + } - /* - * 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"); - } + /* + * 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(aha152x_debug & debug_datai) - if(!fifodata) - printk("fifo empty, "); - else - printk("something left in fifo, "); + if(HOSTDATA(shpnt)->debug & debug_datai) + if(!fifodata) + printk("fifo empty, "); + else + printk("something left in fifo, "); #endif - } + } #if defined(DEBUG_DATAI) - if((aha152x_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 ) ) - ; - CLRBITS(DMACNTRL0, ENDMA ); + 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 defined(DEBUG_DATAI) || defined(DEBUG_INTR) - if(aha152x_debug & (debug_datai|debug_intr)) - printk("got %d bytes, ", GETSTCNT()); + if(HOSTDATA(shpnt)->debug & (debug_datai|debug_intr)) + printk("got %d bytes, ", GETSTCNT()); #endif - current_SC->SCp.have_data_in++; - } - break; + CURRENT_SC->SCp.have_data_in++; + } + break; - case P_DATAO: /* DATA OUT phase */ - { - int data_count; + case P_DATAO: /* DATA OUT phase */ + { + int data_count; #if defined(DEBUG_DATAO) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - if(aha152x_debug & (debug_datao|debug_intr|debug_phases)) - printk("DATA OUT, "); + if(HOSTDATA(shpnt)->debug & (debug_datao|debug_intr|debug_phases)) + printk("DATA OUT, "); #endif #if defined(DEBUG_DATAO) - if(aha152x_debug & debug_datao) - printk("got data to send (bytes=%d, buffers=%d), ", - current_SC->SCp.this_residual, - current_SC->SCp.buffers_residual ); + 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("FIFO should be empty"); - } + 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(DMACNTRL0, WRITE_READ|RSTFIFO); - SETPORT(DMACNTRL0, ENDMA|WRITE_READ); + SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1); + SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1); + + SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO); + SETPORT(DMACNTRL0, ENDMA|WRITE_READ); - SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 ); - SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1); - - SETPORT( SIMODE0, 0 ); - SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE ); - - /* while current buffer is not empty or - there are more buffers to transfer */ - while( TESTLO( SSTAT1, PHASEMIS ) && - (current_SC->SCp.this_residual || - current_SC->SCp.buffers_residual) ) - { + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); + + /* while current buffer is not empty or + there are more buffers to transfer */ + while(TESTLO(SSTAT1, PHASEMIS) && + (CURRENT_SC->SCp.this_residual || + CURRENT_SC->SCp.buffers_residual)) { #if defined(DEBUG_DATAO) - if(aha152x_debug & debug_datao) - printk("sending data (left: bytes=%d, buffers=%d), waiting, ", - current_SC->SCp.this_residual, - current_SC->SCp.buffers_residual); + 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 ; + /* 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(aha152x_debug & debug_datao) - printk("data_count=%d, ", data_count); + 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; - } + 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 ) ) - ; + /* wait for FIFO to get empty */ + while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) + barrier(); #if defined(DEBUG_DATAO) - if(aha152x_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; - } - } + 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; + } + } - if ( current_SC->SCp.this_residual || - current_SC->SCp.buffers_residual ) - { - /* target leaves DATA OUT for an other phase - (perhaps disconnect) */ + if(CURRENT_SC->SCp.this_residual || CURRENT_SC->SCp.buffers_residual) { + /* target leaves DATA OUT for an other phase (perhaps disconnect) */ - /* data in fifos has to be resend */ - data_count = GETPORT(SSTAT2) & (SFULL|SFCNT); + /* data in fifos has to be resend */ + data_count = GETPORT(SSTAT2) & (SFULL|SFCNT); - data_count += GETPORT(FIFOSTAT) ; - current_SC->SCp.ptr -= data_count; - current_SC->SCp.this_residual += data_count; + data_count += GETPORT(FIFOSTAT) ; + CURRENT_SC->SCp.ptr -= data_count; + CURRENT_SC->SCp.this_residual += data_count; #if defined(DEBUG_DATAO) - if(aha152x_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(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(aha152x_debug & debug_datao) - printk("waiting for SCSI fifo to get empty, "); + 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 ) ) - ; + /* wait for SCSI fifo to get empty */ + while(TESTLO(SSTAT2, SEMPTY)) + barrier(); #if defined(DEBUG_DATAO) - if(aha152x_debug & debug_datao) - printk("ok, left data (bytes=%d, buffers=%d) ", - current_SC->SCp.this_residual, - current_SC->SCp.buffers_residual); + 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); + CLRBITS(SXFRCTL0, SCSIEN|DMAEN); - /* transfer can be considered ended, when SCSIEN reads back zero */ - while( TESTHI( SXFRCTL0, SCSIEN ) ) - ; + /* transfer can be considered ended, when SCSIEN reads back zero */ + while(TESTHI(SXFRCTL0, SCSIEN)) + barrier(); - CLRBITS(DMACNTRL0, ENDMA); - } + CLRBITS(DMACNTRL0, ENDMA); + } #if defined(DEBUG_DATAO) || defined(DEBUG_INTR) - if(aha152x_debug & (debug_datao|debug_intr)) - printk("sent %d data bytes, ", GETSTCNT() ); + if(HOSTDATA(shpnt)->debug & (debug_datao|debug_intr)) + printk("sent %d data bytes, ", GETSTCNT()); #endif - } - break; + } + break; - case P_BUSFREE: /* BUSFREE */ + case P_BUSFREE: /* BUSFREE */ #if defined(DEBUG_RACE) - leave_driver("(BUSFREE) intr"); + leave_driver("(BUSFREE) intr"); #endif #if defined(DEBUG_PHASES) - if(aha152x_debug & debug_phases) - printk("unexpected BUS FREE, "); + if(HOSTDATA(shpnt)->debug & debug_phases) + printk("unexpected BUS FREE, "); #endif - current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16)); + CURRENT_SC->SCp.phase &= ~(P_MASK<<16); - aha152x_done( DID_ERROR << 16 ); /* Don't know any better */ - return; - break; + aha152x_done(shpnt, DID_ERROR << 16); /* Don't know any better */ + return; + break; - case P_PARITY: /* parity error in DATA phase */ + case P_PARITY: /* parity error in DATA phase */ #if defined(DEBUG_RACE) - leave_driver("(DID_PARITY) intr"); + leave_driver("(DID_PARITY) intr"); #endif - printk("PARITY error in DATA phase, "); + printk("PARITY error in DATA phase, "); - current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16)); + CURRENT_SC->SCp.phase &= ~(P_MASK<<16); - SETBITS( DMACNTRL0, INTEN ); - aha152x_done( DID_PARITY << 16 ); - return; - break; + SETBITS(DMACNTRL0, INTEN); + aha152x_done(shpnt, DID_PARITY << 16); + return; + break; - default: - printk("aha152x: unexpected phase\n"); - break; - } + default: + printk("aha152x: unexpected phase\n"); + break; + } - if(done) - { + if(done) { #if defined(DEBUG_INTR) - if(aha152x_debug & debug_intr) - printk("command done.\n"); + if(HOSTDATA(shpnt)->debug & debug_intr) + printk("command done.\n"); #endif #if defined(DEBUG_RACE) - leave_driver("(done) intr"); + leave_driver("(done) intr"); #endif - SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 ); - SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0); - SETPORT(SCSISEQ, disconnected_SC ? ENRESELI : 0 ); - - SETBITS( DMACNTRL0, INTEN ); - - aha152x_done( (current_SC->SCp.Status & 0xff) - | ( (current_SC->SCp.Message & 0xff) << 8) - | ( DID_OK << 16) ); + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0); + + SETBITS(DMACNTRL0, INTEN); + + 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); + printk("done returned (DID_OK: Status=%x; Message=%x).\n", + CURRENT_SC->SCp.Status, CURRENT_SC->SCp.Message); #endif - return; - } + return; + } - if(current_SC) - current_SC->SCp.phase |= 1<<16 ; + if(CURRENT_SC) + CURRENT_SC->SCp.phase |= 1<<16; - SETPORT( SIMODE0, 0 ); - SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE ); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); #if defined(DEBUG_INTR) - if(aha152x_debug & debug_intr) - disp_enintr(); + if(HOSTDATA(shpnt)->debug & debug_intr) + disp_enintr(shpnt); #endif #if defined(DEBUG_RACE) leave_driver("(PHASEEND) intr"); #endif - SETBITS( DMACNTRL0, INTEN); + SETBITS(DMACNTRL0, INTEN); return; } /* * Dump the current driver status and panic... */ -static void aha152x_panic(char *msg) +static void aha152x_panic(struct Scsi_Host *shpnt, char *msg) { - printk("\naha152x_panic: %s\n", msg); - show_queues(); + printk("\naha152x: %s\n", msg); + show_queues(shpnt); panic("aha152x panic"); } /* * Display registers of AIC-6260 */ -static void disp_ports(void) +static void disp_ports(struct Scsi_Host *shpnt) { #ifdef DEBUG_AHA152X int s; #ifdef SKIP_PORTS - if(aha152x_debug & debug_skipports) - return; + if(HOSTDATA(shpnt)->debug & debug_skipports) + return; #endif - printk("\n%s: ", current_SC ? "on bus" : "waiting"); + printk("\n%s: ", CURRENT_SC ? "on bus" : "waiting"); s=GETPORT(SCSISEQ); - printk("SCSISEQ ( "); - if( s & TEMODEO ) printk("TARGET MODE "); - if( s & ENSELO ) printk("SELO "); - if( s & ENSELI ) printk("SELI "); - if( s & ENRESELI ) printk("RESELI "); - if( s & ENAUTOATNO ) printk("AUTOATNO "); - if( s & ENAUTOATNI ) printk("AUTOATNI "); - if( s & ENAUTOATNP ) printk("AUTOATNP "); - if( s & SCSIRSTO ) printk("SCSIRSTO "); + printk("SCSISEQ ("); + if(s & TEMODEO) printk("TARGET MODE "); + if(s & ENSELO) printk("SELO "); + if(s & ENSELI) printk("SELI "); + if(s & ENRESELI) printk("RESELI "); + if(s & ENAUTOATNO) printk("AUTOATNO "); + if(s & ENAUTOATNI) printk("AUTOATNI "); + if(s & ENAUTOATNP) printk("AUTOATNP "); + if(s & SCSIRSTO) printk("SCSIRSTO "); printk(");"); - printk(" SCSISIG ( "); + printk(" SCSISIG ("); s=GETPORT(SCSISIG); - switch(s & 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; - } + switch(s & 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(" ); "); + printk("); "); - printk("INTSTAT ( %s ); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); + printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); - printk("SSTAT ( "); + printk("SSTAT ("); s=GETPORT(SSTAT0); - if( s & TARGET ) printk("TARGET "); - if( s & SELDO ) printk("SELDO "); - if( s & SELDI ) printk("SELDI "); - if( s & SELINGO ) printk("SELINGO "); - if( s & SWRAP ) printk("SWRAP "); - if( s & SDONE ) printk("SDONE "); - if( s & SPIORDY ) printk("SPIORDY "); - if( s & DMADONE ) printk("DMADONE "); + if(s & TARGET) printk("TARGET "); + if(s & SELDO) printk("SELDO "); + if(s & SELDI) printk("SELDI "); + if(s & SELINGO) printk("SELINGO "); + if(s & SWRAP) printk("SWRAP "); + if(s & SDONE) printk("SDONE "); + if(s & SPIORDY) printk("SPIORDY "); + if(s & DMADONE) printk("DMADONE "); s=GETPORT(SSTAT1); - if( s & SELTO ) printk("SELTO "); - if( s & ATNTARG ) printk("ATNTARG "); - if( s & SCSIRSTI ) printk("SCSIRSTI "); - if( s & PHASEMIS ) printk("PHASEMIS "); - if( s & BUSFREE ) printk("BUSFREE "); - if( s & SCSIPERR ) printk("SCSIPERR "); - if( s & PHASECHG ) printk("PHASECHG "); - if( s & REQINIT ) printk("REQINIT "); + if(s & SELTO) printk("SELTO "); + if(s & ATNTARG) printk("ATNTARG "); + if(s & SCSIRSTI) printk("SCSIRSTI "); + if(s & PHASEMIS) printk("PHASEMIS "); + if(s & BUSFREE) printk("BUSFREE "); + if(s & SCSIPERR) printk("SCSIPERR "); + if(s & PHASECHG) printk("PHASECHG "); + if(s & REQINIT) printk("REQINIT "); printk("); "); - printk("SSTAT ( "); + printk("SSTAT ("); s=GETPORT(SSTAT0) & GETPORT(SIMODE0); - if( s & TARGET ) printk("TARGET "); - if( s & SELDO ) printk("SELDO "); - if( s & SELDI ) printk("SELDI "); - if( s & SELINGO ) printk("SELINGO "); - if( s & SWRAP ) printk("SWRAP "); - if( s & SDONE ) printk("SDONE "); - if( s & SPIORDY ) printk("SPIORDY "); - if( s & DMADONE ) printk("DMADONE "); + if(s & TARGET) printk("TARGET "); + if(s & SELDO) printk("SELDO "); + if(s & SELDI) printk("SELDI "); + if(s & SELINGO) printk("SELINGO "); + if(s & SWRAP) printk("SWRAP "); + if(s & SDONE) printk("SDONE "); + if(s & SPIORDY) printk("SPIORDY "); + if(s & DMADONE) printk("DMADONE "); s=GETPORT(SSTAT1) & GETPORT(SIMODE1); - if( s & SELTO ) printk("SELTO "); - if( s & ATNTARG ) printk("ATNTARG "); - if( s & SCSIRSTI ) printk("SCSIRSTI "); - if( s & PHASEMIS ) printk("PHASEMIS "); - if( s & BUSFREE ) printk("BUSFREE "); - if( s & SCSIPERR ) printk("SCSIPERR "); - if( s & PHASECHG ) printk("PHASECHG "); - if( s & REQINIT ) printk("REQINIT "); + if(s & SELTO) printk("SELTO "); + if(s & ATNTARG) printk("ATNTARG "); + if(s & SCSIRSTI) printk("SCSIRSTI "); + if(s & PHASEMIS) printk("PHASEMIS "); + if(s & BUSFREE) printk("BUSFREE "); + if(s & SCSIPERR) printk("SCSIPERR "); + if(s & PHASECHG) printk("PHASECHG "); + if(s & REQINIT) printk("REQINIT "); printk("); "); - printk("SXFRCTL0 ( "); + printk("SXFRCTL0 ("); s=GETPORT(SXFRCTL0); - if( s & SCSIEN ) printk("SCSIEN "); - if( s & DMAEN ) printk("DMAEN "); - if( s & CH1 ) printk("CH1 "); - if( s & CLRSTCNT ) printk("CLRSTCNT "); - if( s & SPIOEN ) printk("SPIOEN "); - if( s & CLRCH1 ) printk("CLRCH1 "); + if(s & SCSIEN) printk("SCSIEN "); + if(s & DMAEN) printk("DMAEN "); + if(s & CH1) printk("CH1 "); + if(s & CLRSTCNT) printk("CLRSTCNT "); + if(s & SPIOEN) printk("SPIOEN "); + if(s & CLRCH1) printk("CLRCH1 "); printk("); "); - printk("SIGNAL ( "); + printk("SIGNAL ("); s=GETPORT(SCSISIG); - if( s & ATNI ) printk("ATNI "); - if( s & SELI ) printk("SELI "); - if( s & BSYI ) printk("BSYI "); - if( s & REQI ) printk("REQI "); - if( s & ACKI ) printk("ACKI "); + if(s & ATNI) printk("ATNI "); + if(s & SELI) printk("SELI "); + if(s & BSYI) printk("BSYI "); + if(s & REQI) printk("REQI "); + if(s & ACKI) printk("ACKI "); printk("); "); - printk("SELID ( %02x ), ", GETPORT(SELID) ); + printk("SELID (%02x), ", GETPORT(SELID)); - printk("SSTAT2 ( "); + printk("SSTAT2 ("); s=GETPORT(SSTAT2); - if( s & SOFFSET) printk("SOFFSET "); - if( s & SEMPTY) printk("SEMPTY "); - if( s & SFULL) printk("SFULL "); - printk("); SFCNT ( %d ); ", s & (SFULL|SFCNT) ); + if(s & SOFFSET) printk("SOFFSET "); + if(s & SEMPTY) printk("SEMPTY "); + if(s & SFULL) printk("SFULL "); + printk("); SFCNT (%d); ", s & (SFULL|SFCNT)); -#if 0 - printk("SSTAT4 ( "); + s=GETPORT(SSTAT3); + printk("SCSICNT (%d), OFFCNT(%d), ", (s&0xf0)>>4, s&0x0f); + + printk("SSTAT4 ("); s=GETPORT(SSTAT4); - if( s & SYNCERR) printk("SYNCERR "); - if( s & FWERR) printk("FWERR "); - if( s & FRERR) printk("FRERR "); + if(s & SYNCERR) printk("SYNCERR "); + if(s & FWERR) printk("FWERR "); + if(s & FRERR) printk("FRERR "); printk("); "); -#endif - - printk("FCNT ( %d ); ", GETPORT(FIFOSTAT) ); - printk("DMACNTRL0 ( "); + printk("DMACNTRL0 ("); s=GETPORT(DMACNTRL0); - printk( "%s ", s & _8BIT ? "8BIT" : "16BIT" ); - printk( "%s ", s & DMA ? "DMA" : "PIO" ); - printk( "%s ", s & WRITE_READ ? "WRITE" : "READ" ); - if( s & ENDMA ) printk("ENDMA "); - if( s & INTEN ) printk("INTEN "); - if( s & RSTFIFO ) printk("RSTFIFO "); - if( s & SWINT ) printk("SWINT "); - printk("); "); - - -#if 0 - printk("DMACNTRL1 ( "); - - s=GETPORT(DMACNTRL1); - if( s & PWRDWN ) printk("PWRDN "); + printk("%s ", s & _8BIT ? "8BIT" : "16BIT"); + printk("%s ", s & DMA ? "DMA" : "PIO" ); + printk("%s ", s & WRITE_READ ? "WRITE" : "READ" ); + if(s & ENDMA) printk("ENDMA "); + if(s & INTEN) printk("INTEN "); + if(s & RSTFIFO) printk("RSTFIFO "); + if(s & SWINT) printk("SWINT "); printk("); "); - - printk("STK ( %d ); ", s & 0xf); - printk("DMASTAT ("); s=GETPORT(DMASTAT); - if( s & ATDONE ) printk("ATDONE "); - if( s & WORDRDY ) printk("WORDRDY "); - if( s & DFIFOFULL ) printk("DFIFOFULL "); - if( s & DFIFOEMP ) printk("DFIFOEMP "); + if(s & ATDONE) printk("ATDONE "); + if(s & WORDRDY) printk("WORDRDY "); + if(s & DFIFOFULL) printk("DFIFOFULL "); + if(s & DFIFOEMP) printk("DFIFOEMP "); printk(")"); -#endif - printk("\n"); #endif } @@ -2467,29 +2749,29 @@ static void disp_ports(void) /* * display enabled interrupts */ -static void disp_enintr(void) +static void disp_enintr(struct Scsi_Host *shpnt) { int s; - printk("enabled interrupts ( "); + printk("enabled interrupts ("); s=GETPORT(SIMODE0); - if( s & ENSELDO ) printk("ENSELDO "); - if( s & ENSELDI ) printk("ENSELDI "); - if( s & ENSELINGO ) printk("ENSELINGO "); - if( s & ENSWRAP ) printk("ENSWRAP "); - if( s & ENSDONE ) printk("ENSDONE "); - if( s & ENSPIORDY ) printk("ENSPIORDY "); - if( s & ENDMADONE ) printk("ENDMADONE "); + if(s & ENSELDO) printk("ENSELDO "); + if(s & ENSELDI) printk("ENSELDI "); + if(s & ENSELINGO) printk("ENSELINGO "); + if(s & ENSWRAP) printk("ENSWRAP "); + if(s & ENSDONE) printk("ENSDONE "); + if(s & ENSPIORDY) printk("ENSPIORDY "); + if(s & ENDMADONE) printk("ENDMADONE "); s=GETPORT(SIMODE1); - if( s & ENSELTIMO ) printk("ENSELTIMO "); - if( s & ENATNTARG ) printk("ENATNTARG "); - if( s & ENPHASEMIS ) printk("ENPHASEMIS "); - if( s & ENBUSFREE ) printk("ENBUSFREE "); - if( s & ENSCSIPERR ) printk("ENSCSIPERR "); - if( s & ENPHASECHG ) printk("ENPHASECHG "); - if( s & ENREQINIT ) printk("ENREQINIT "); + if(s & ENSELTIMO) printk("ENSELTIMO "); + if(s & ENATNTARG) printk("ENATNTARG "); + if(s & ENPHASEMIS) printk("ENPHASEMIS "); + if(s & ENBUSFREE) printk("ENBUSFREE "); + if(s & ENSCSIPERR) printk("ENSCSIPERR "); + if(s & ENPHASECHG) printk("ENPHASECHG "); + if(s & ENREQINIT) printk("ENREQINIT "); printk(")\n"); } @@ -2508,11 +2790,10 @@ static void enter_driver(const char *func) 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"); - } + if(in_driver) { + printk("%s should leave first.\n", should_leave); + panic("aha152x: already in driver\n"); + } in_driver++; should_leave=func; @@ -2526,11 +2807,10 @@ static void leave_driver(const char *func) 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"); - } + if(!in_driver) { + printk("aha152x: %s already left.\n", should_leave); + panic("aha152x: %s already left driver.\n"); + } in_driver--; should_leave=func; @@ -2543,7 +2823,7 @@ static void leave_driver(const char *func) */ static void show_command(Scsi_Cmnd *ptr) { - printk("0x%08x: target=%d; lun=%d; cmnd=( ", + printk("0x%08x: target=%d; lun=%d; cmnd=(", (unsigned int) ptr, ptr->target, ptr->lun); print_command(ptr->cmnd); @@ -2551,49 +2831,47 @@ static void show_command(Scsi_Cmnd *ptr) printk("); residual=%d; buffers=%d; phase |", ptr->SCp.this_residual, ptr->SCp.buffers_residual); - if( ptr->SCp.phase & not_issued ) printk("not issued|"); - if( ptr->SCp.phase & in_selection ) printk("in selection|"); - if( ptr->SCp.phase & disconnected ) printk("disconnected|"); - 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"); + if(ptr->SCp.phase & not_issued ) printk("not issued|"); + if(ptr->SCp.phase & in_selection) printk("in selection|"); + if(ptr->SCp.phase & disconnected) printk("disconnected|"); + 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); } /* * Dump the queued data */ -static void show_queues(void) +static void show_queues(struct Scsi_Host *shpnt) { unsigned long flags; Scsi_Cmnd *ptr; @@ -2601,20 +2879,395 @@ static void show_queues(void) save_flags(flags); cli(); printk("QUEUE STATUS:\nissue_SC:\n"); - for(ptr=issue_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble ) + for(ptr=ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) show_command(ptr); printk("current_SC:\n"); - if(current_SC) - show_command(current_SC); + if(CURRENT_SC) + show_command(CURRENT_SC); else printk("none\n"); printk("disconnected_SC:\n"); - for(ptr=disconnected_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble ) + for(ptr=DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) show_command(ptr); - disp_ports(); - disp_enintr(); + 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 +#define SPRINTF(args...) pos += sprintf(pos, ## args) + +static int get_command(char *pos, Scsi_Cmnd *ptr) +{ + char *start = pos; + int i; + + SPRINTF("0x%08x: target=%d; lun=%d; cmnd=( ", + (unsigned int) ptr, ptr->target, ptr->lun); + + 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); + + if(ptr->SCp.phase & not_issued ) SPRINTF("not issued|"); + if(ptr->SCp.phase & in_selection) SPRINTF("in selection|"); + 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); + + return(pos-start); +} + +static int get_ports(struct Scsi_Host *shpnt, char *pos) +{ + char *start = pos; + int s; + +#ifdef SKIP_PORTS + if(HOSTDATA(shpnt)->debug & debug_skipports) + return; +#endif + + SPRINTF("\n%s: ", CURRENT_SC ? "on bus" : "waiting"); + + s=GETPORT(SCSISEQ); + SPRINTF("SCSISEQ ("); + if(s & TEMODEO) SPRINTF("TARGET MODE "); + if(s & ENSELO) SPRINTF("SELO "); + if(s & ENSELI) SPRINTF("SELI "); + if(s & ENRESELI) SPRINTF("RESELI "); + if(s & ENAUTOATNO) SPRINTF("AUTOATNO "); + if(s & ENAUTOATNI) SPRINTF("AUTOATNI "); + if(s & ENAUTOATNP) SPRINTF("AUTOATNP "); + if(s & SCSIRSTO) SPRINTF("SCSIRSTO "); + SPRINTF(");"); + + SPRINTF(" SCSISIG ("); + s=GETPORT(SCSISIG); + switch(s & 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("); "); + + SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); + + SPRINTF("SSTAT ("); + s=GETPORT(SSTAT0); + if(s & TARGET) SPRINTF("TARGET "); + if(s & SELDO) SPRINTF("SELDO "); + if(s & SELDI) SPRINTF("SELDI "); + if(s & SELINGO) SPRINTF("SELINGO "); + if(s & SWRAP) SPRINTF("SWRAP "); + if(s & SDONE) SPRINTF("SDONE "); + if(s & SPIORDY) SPRINTF("SPIORDY "); + if(s & DMADONE) SPRINTF("DMADONE "); + + s=GETPORT(SSTAT1); + if(s & SELTO) SPRINTF("SELTO "); + if(s & ATNTARG) SPRINTF("ATNTARG "); + if(s & SCSIRSTI) SPRINTF("SCSIRSTI "); + if(s & PHASEMIS) SPRINTF("PHASEMIS "); + if(s & BUSFREE) SPRINTF("BUSFREE "); + if(s & SCSIPERR) SPRINTF("SCSIPERR "); + if(s & PHASECHG) SPRINTF("PHASECHG "); + if(s & REQINIT) SPRINTF("REQINIT "); + SPRINTF("); "); + + + SPRINTF("SSTAT ("); + + s=GETPORT(SSTAT0) & GETPORT(SIMODE0); + + if(s & TARGET) SPRINTF("TARGET "); + if(s & SELDO) SPRINTF("SELDO "); + if(s & SELDI) SPRINTF("SELDI "); + if(s & SELINGO) SPRINTF("SELINGO "); + if(s & SWRAP) SPRINTF("SWRAP "); + if(s & SDONE) SPRINTF("SDONE "); + if(s & SPIORDY) SPRINTF("SPIORDY "); + if(s & DMADONE) SPRINTF("DMADONE "); + + s=GETPORT(SSTAT1) & GETPORT(SIMODE1); + + if(s & SELTO) SPRINTF("SELTO "); + if(s & ATNTARG) SPRINTF("ATNTARG "); + if(s & SCSIRSTI) SPRINTF("SCSIRSTI "); + if(s & PHASEMIS) SPRINTF("PHASEMIS "); + if(s & BUSFREE) SPRINTF("BUSFREE "); + if(s & SCSIPERR) SPRINTF("SCSIPERR "); + if(s & PHASECHG) SPRINTF("PHASECHG "); + if(s & REQINIT) SPRINTF("REQINIT "); + SPRINTF("); "); + + SPRINTF("SXFRCTL0 ("); + + s=GETPORT(SXFRCTL0); + if(s & SCSIEN) SPRINTF("SCSIEN "); + if(s & DMAEN) SPRINTF("DMAEN "); + if(s & CH1) SPRINTF("CH1 "); + if(s & CLRSTCNT) SPRINTF("CLRSTCNT "); + if(s & SPIOEN) SPRINTF("SPIOEN "); + if(s & CLRCH1) SPRINTF("CLRCH1 "); + SPRINTF("); "); + + SPRINTF("SIGNAL ("); + + s=GETPORT(SCSISIG); + if(s & ATNI) SPRINTF("ATNI "); + if(s & SELI) SPRINTF("SELI "); + if(s & BSYI) SPRINTF("BSYI "); + if(s & REQI) SPRINTF("REQI "); + if(s & ACKI) SPRINTF("ACKI "); + SPRINTF("); "); + + SPRINTF("SELID (%02x), ", GETPORT(SELID)); + + SPRINTF("SSTAT2 ("); + + s=GETPORT(SSTAT2); + if(s & SOFFSET) SPRINTF("SOFFSET "); + if(s & SEMPTY) SPRINTF("SEMPTY "); + if(s & SFULL) SPRINTF("SFULL "); + SPRINTF("); SFCNT (%d); ", s & (SFULL|SFCNT)); + + s=GETPORT(SSTAT3); + SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s&0xf0)>>4, s&0x0f); + + SPRINTF("SSTAT4 ("); + s=GETPORT(SSTAT4); + if(s & SYNCERR) SPRINTF("SYNCERR "); + if(s & FWERR) SPRINTF("FWERR "); + if(s & FRERR) SPRINTF("FRERR "); + SPRINTF("); "); + + SPRINTF("DMACNTRL0 ("); + s=GETPORT(DMACNTRL0); + SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT"); + SPRINTF("%s ", s & DMA ? "DMA" : "PIO" ); + SPRINTF("%s ", s & WRITE_READ ? "WRITE" : "READ" ); + if(s & ENDMA) SPRINTF("ENDMA "); + if(s & INTEN) SPRINTF("INTEN "); + if(s & RSTFIFO) SPRINTF("RSTFIFO "); + if(s & SWINT) SPRINTF("SWINT "); + SPRINTF("); "); + + SPRINTF("DMASTAT ("); + s=GETPORT(DMASTAT); + if(s & ATDONE) SPRINTF("ATDONE "); + if(s & WORDRDY) SPRINTF("WORDRDY "); + if(s & DFIFOFULL) SPRINTF("DFIFOFULL "); + if(s & DFIFOEMP) SPRINTF("DFIFOEMP "); + SPRINTF(")\n\n"); + + SPRINTF("enabled interrupts ("); + + s=GETPORT(SIMODE0); + if(s & ENSELDO) SPRINTF("ENSELDO "); + if(s & ENSELDI) SPRINTF("ENSELDI "); + if(s & ENSELINGO) SPRINTF("ENSELINGO "); + if(s & ENSWRAP) SPRINTF("ENSWRAP "); + if(s & ENSDONE) SPRINTF("ENSDONE "); + if(s & ENSPIORDY) SPRINTF("ENSPIORDY "); + if(s & ENDMADONE) SPRINTF("ENDMADONE "); + + s=GETPORT(SIMODE1); + if(s & ENSELTIMO) SPRINTF("ENSELTIMO "); + if(s & ENATNTARG) SPRINTF("ENATNTARG "); + if(s & ENPHASEMIS) SPRINTF("ENPHASEMIS "); + if(s & ENBUSFREE) SPRINTF("ENBUSFREE "); + if(s & ENSCSIPERR) SPRINTF("ENSCSIPERR "); + if(s & ENPHASECHG) SPRINTF("ENPHASECHG "); + if(s & ENREQINIT) SPRINTF("ENREQINIT "); + SPRINTF(")\n"); + + return (pos-start); +} + +#undef SPRINTF +#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) +{ + int i; + char *pos = buffer; + struct Scsi_Host *shpnt; + unsigned long flags; + Scsi_Cmnd *ptr; + + 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); + + if(inout) /* Has data been written to the file ? */ + return(aha152x_set_info(buffer, length, shpnt)); + + SPRINTF(AHA152X_REVID "\n"); + + save_flags(flags); + cli(); + + SPRINTF("ioports 0x%04x to 0x%04x\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"); + SPRINTF("parity checking %s\n", + HOSTDATA(shpnt)->parity ? "enabled" : "disabled"); + SPRINTF("synchronous transfers %s\n", + HOSTDATA(shpnt)->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 + SPRINTF("synchronously operating targets (tick=50 ns):\n"); + for(i=0; i<8; i++) + if(HOSTDATA(shpnt)->syncrate[i]&0x7f) + SPRINTF("target %d: period %dT/%dns; req/ack offset %d\n", + i, + (((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); + + SPRINTF("enabled debugging options: "); + + PDEBUG(debug_skipports, "skip ports"); + PDEBUG(debug_queue, "queue"); + PDEBUG(debug_intr, "interrupt"); + PDEBUG(debug_selection, "selection"); + PDEBUG(debug_msgo, "message out"); + PDEBUG(debug_msgi, "message in"); + PDEBUG(debug_status, "status"); + 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_phases, "phases"); + PDEBUG(debug_queues, "queues"); + PDEBUG(debug_reset, "reset"); + + SPRINTF("\n"); +#endif + + SPRINTF("\nqueue status:\n"); + if(ISSUE_SC) { + SPRINTF("not yet issued commands:\n"); + for(ptr=ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + pos += get_command(pos, ptr); + } else + SPRINTF("no not yet issued commands\n"); + + if(CURRENT_SC) { + SPRINTF("current command:\n"); + pos += get_command(pos, CURRENT_SC); + } else + SPRINTF("no current command\n"); + + if(DISCONNECTED_SC) { + SPRINTF("disconnected commands:\n"); + for(ptr=DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + 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) + return 0; + else if (pos - buffer - offset < length) + return pos - buffer - offset; + else + return length; } + +#ifdef MODULE +/* Eventually this will go into an include file, but this will be later */ +Scsi_Host_Template driver_template = AHA152X; + +#include "scsi_module.c" +#endif |