2005-04-17 02:20:36 +04:00
/* aha152x.c -- Adaptec AHA-152x driver
* Author : J <EFBFBD> rgen E . Fischer , fischer @ norbit . de
* Copyright 1993 - 2004 J <EFBFBD> rgen E . Fischer
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* 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 2.7 2004 / 01 / 24 11 : 42 : 59 fischer Exp $
*
* $ Log : aha152x . c , v $
* Revision 2.7 2004 / 01 / 24 11 : 42 : 59 fischer
* - gather code that is not used by PCMCIA at the end
* - move request_region for ! PCMCIA case to detection
* - migration to new scsi host api ( remove legacy code )
* - free host scribble before scsi_done
* - fix error handling
* - one isapnp device added to id_table
*
* Revision 2.6 2003 / 10 / 30 20 : 52 : 47 fischer
* - interfaces changes for kernel 2.6
* - aha152x_probe_one introduced for pcmcia stub
* - fixed pnpdev handling
* - instead of allocation a new one , reuse command for request sense after check condition and reset
* - fixes race in is_complete
*
* Revision 2.5 2002 / 04 / 14 11 : 24 : 53 fischer
* - isapnp support
* - abort fixed
* - 2.5 support
*
* Revision 2.4 2000 / 12 / 16 12 : 53 : 56 fischer
* - allow REQUEST SENSE to be queued
* - handle shared PCI interrupts
*
* Revision 2.3 2000 / 11 / 04 16 : 40 : 26 fischer
* - handle data overruns
* - extend timeout for data phases
*
* Revision 2.2 2000 / 08 / 08 19 : 54 : 53 fischer
* - minor changes
*
* Revision 2.1 2000 / 05 / 17 16 : 23 : 17 fischer
* - signature update
* - fix for data out w / o scatter gather
*
* Revision 2.0 1999 / 12 / 25 15 : 07 : 32 fischer
* - interrupt routine completly reworked
* - basic support for new eh code
*
* Revision 1.21 1999 / 11 / 10 23 : 46 : 36 fischer
* - default to synchronous operation
* - synchronous negotiation fixed
* - added timeout to loops
* - debugging output can be controlled through procfs
*
* Revision 1.20 1999 / 11 / 07 18 : 37 : 31 fischer
* - synchronous operation works
* - resid support for sg driver
*
* Revision 1.19 1999 / 11 / 02 22 : 39 : 59 fischer
* - moved leading comments to README . aha152x
* - new additional module parameters
* - updates for 2.3
* - support for the Tripace TC1550 controller
* - interrupt handling changed
*
* Revision 1.18 1996 / 09 / 07 20 : 10 : 40 fischer
* - fixed can_queue handling ( multiple outstanding commands working again )
*
* 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 > 1 GB 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
*
* Revision 1.8 1995 / 01 / 21 22 : 07 : 19 root
* - snarf_region = > request_region
* - aha152x_intr interface change
*
* Revision 1.7 1995 / 01 / 02 23 : 19 : 36 root
* - updated COMMAND_SIZE to cmd_len
* - changed sti ( ) to restore_flags ( )
* - fixed some # ifdef which generated warnings
*
* Revision 1.6 1994 / 11 / 24 20 : 35 : 27 root
* - problem with odd number of bytes in fifo fixed
*
* Revision 1.5 1994 / 10 / 30 14 : 39 : 56 root
* - abort code fixed
* - debugging improved
*
* Revision 1.4 1994 / 09 / 12 11 : 33 : 01 root
* - irqaction to request_irq
* - abortion updated
*
* Revision 1.3 1994 / 08 / 04 13 : 53 : 05 root
* - updates for mid - level - driver changes
* - accept unexpected BUSFREE phase as error condition
* - parity check now configurable
*
* Revision 1.2 1994 / 07 / 03 12 : 56 : 36 root
* - cleaned up debugging code
* - more tweaking on reset delays
* - updated abort / reset code ( pretty untested . . . )
*
* Revision 1.1 1994 / 05 / 28 21 : 18 : 49 root
* - update for mid - level interface change ( abort - reset )
* - delays after resets adjusted for some slow devices
*
* Revision 1.0 1994 / 03 / 25 12 : 52 : 00 root
* - Fixed " more data than expected " problem
* - added new BIOS signatures
*
* Revision 0.102 1994 / 01 / 31 20 : 44 : 12 root
* - minor changes in insw / outsw handling
*
* Revision 0.101 1993 / 12 / 13 01 : 16 : 27 root
* - fixed STATUS phase ( non - GOOD stati were dropped sometimes ;
* fixes problems with CD - ROM sector size detection & media change )
*
* Revision 0.100 1993 / 12 / 10 16 : 58 : 47 root
* - fix for unsuccessful selections in case of non - continuous id assignments
* on the scsi bus .
*
* Revision 0.99 1993 / 10 / 24 16 : 19 : 59 root
* - fixed DATA IN ( rare read errors gone )
*
* Revision 0.98 1993 / 10 / 17 12 : 54 : 44 root
* - fixed some recent fixes ( shame on me )
* - moved initialization of scratch area to aha152x_queue
*
* Revision 0.97 1993 / 10 / 09 18 : 53 : 53 root
* - DATA IN fixed . Rarely left data in the fifo .
*
* Revision 0.96 1993 / 10 / 03 00 : 53 : 59 root
* - minor changes on DATA IN
*
* Revision 0.95 1993 / 09 / 24 10 : 36 : 01 root
* - change handling of MSGI after reselection
* - fixed sti / cli
* - minor changes
*
* Revision 0.94 1993 / 09 / 18 14 : 08 : 22 root
* - fixed bug in multiple outstanding command code
* - changed detection
* - support for kernel command line configuration
* - reset corrected
* - changed message handling
*
* Revision 0.93 1993 / 09 / 15 20 : 41 : 19 root
* - fixed bugs with multiple outstanding commands
*
* Revision 0.92 1993 / 09 / 13 02 : 46 : 33 root
* - multiple outstanding commands work ( no problems with IBM drive )
*
* Revision 0.91 1993 / 09 / 12 20 : 51 : 46 root
* added multiple outstanding commands
* ( some problem with this $ % & ? IBM device remain )
*
* Revision 0.9 1993 / 09 / 12 11 : 11 : 22 root
* - corrected auto - configuration
* - changed the auto - configuration ( added some ' # define ' s )
* - added support for dis - / reconnection
*
* Revision 0.8 1993 / 09 / 06 23 : 09 : 39 root
* - added support for the drive activity light
* - minor changes
*
* Revision 0.7 1993 / 09 / 05 14 : 30 : 15 root
* - improved phase detection
* - now using the new snarf_region code of 0.99 pl13
*
* Revision 0.6 1993 / 09 / 02 11 : 01 : 38 root
* first public release ; added some signatures and biosparam ( )
*
* Revision 0.5 1993 / 08 / 30 10 : 23 : 30 root
* fixed timing problems with my IBM drive
*
* Revision 0.4 1993 / 08 / 29 14 : 06 : 52 root
* fixed some problems with timeouts due incomplete commands
*
* Revision 0.3 1993 / 08 / 28 15 : 55 : 03 root
* writing data works too . mounted and worked on a dos partition
*
* Revision 0.2 1993 / 08 / 27 22 : 42 : 07 root
* reading data works . Mounted a msdos partition .
*
* Revision 0.1 1993 / 08 / 25 13 : 38 : 30 root
* first " damn thing doesn't work " version
*
* Revision 0.0 1993 / 08 / 14 19 : 54 : 25 root
* empty function bodies ; detect ( ) works .
*
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
see Documentation / scsi / aha152x . txt for configuration details
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/module.h>
# include <linux/sched.h>
# include <asm/irq.h>
# include <asm/io.h>
# include <linux/blkdev.h>
# include <asm/system.h>
# include <linux/errno.h>
# include <linux/string.h>
# include <linux/wait.h>
# include <linux/ioport.h>
# include <linux/delay.h>
# include <linux/proc_fs.h>
# include <linux/interrupt.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/isapnp.h>
# include <linux/spinlock.h>
# include <linux/workqueue.h>
# include <asm/semaphore.h>
# include <scsi/scsicam.h>
# include "scsi.h"
2005-04-03 23:53:59 +04:00
# include <scsi/scsi_dbg.h>
2005-04-17 02:20:36 +04:00
# include <scsi/scsi_host.h>
2005-12-16 00:22:01 +03:00
# include <scsi/scsi_transport_spi.h>
2005-04-17 02:20:36 +04:00
# include "aha152x.h"
/* DEFINES */
/* For PCMCIA cards, always use AUTOCONF */
# if defined(PCMCIA) || defined(MODULE)
# if !defined(AUTOCONF)
# define AUTOCONF
# endif
# endif
# if !defined(AUTOCONF) && !defined(SETUP0)
# error define AUTOCONF or SETUP0
# endif
# if defined(AHA152X_DEBUG)
# define DEBUG_DEFAULT debug_eh
# define DPRINTK(when,msgs...) \
do { if ( HOSTDATA ( shpnt ) - > debug & ( when ) ) printk ( msgs ) ; } while ( 0 )
# define DO_LOCK(flags) \
do { \
if ( spin_is_locked ( & QLOCK ) ) { \
DPRINTK ( debug_intr , DEBUG_LEAD " (%s:%d) already locked at %s:%d \n " , CMDINFO ( CURRENT_SC ) , __FUNCTION__ , __LINE__ , QLOCKER , QLOCKERL ) ; \
} \
DPRINTK ( debug_locks , DEBUG_LEAD " (%s:%d) locking \n " , CMDINFO ( CURRENT_SC ) , __FUNCTION__ , __LINE__ ) ; \
spin_lock_irqsave ( & QLOCK , flags ) ; \
DPRINTK ( debug_locks , DEBUG_LEAD " (%s:%d) locked \n " , CMDINFO ( CURRENT_SC ) , __FUNCTION__ , __LINE__ ) ; \
QLOCKER = __FUNCTION__ ; \
QLOCKERL = __LINE__ ; \
} while ( 0 )
# define DO_UNLOCK(flags) \
do { \
DPRINTK ( debug_locks , DEBUG_LEAD " (%s:%d) unlocking (locked at %s:%d) \n " , CMDINFO ( CURRENT_SC ) , __FUNCTION__ , __LINE__ , QLOCKER , QLOCKERL ) ; \
spin_unlock_irqrestore ( & QLOCK , flags ) ; \
DPRINTK ( debug_locks , DEBUG_LEAD " (%s:%d) unlocked \n " , CMDINFO ( CURRENT_SC ) , __FUNCTION__ , __LINE__ ) ; \
QLOCKER = " (not locked) " ; \
QLOCKERL = 0 ; \
} while ( 0 )
# else
# define DPRINTK(when,msgs...)
# define DO_LOCK(flags) spin_lock_irqsave(&QLOCK,flags)
# define DO_UNLOCK(flags) spin_unlock_irqrestore(&QLOCK,flags)
# endif
# define LEAD "(scsi%d:%d:%d) "
# define WARN_LEAD KERN_WARNING LEAD
# define INFO_LEAD KERN_INFO LEAD
# define NOTE_LEAD KERN_NOTICE LEAD
# define ERR_LEAD KERN_ERR LEAD
# define DEBUG_LEAD KERN_DEBUG LEAD
# define CMDINFO(cmd) \
( cmd ) ? ( ( cmd ) - > device - > host - > host_no ) : - 1 , \
( cmd ) ? ( ( cmd ) - > device - > id & 0x0f ) : - 1 , \
( cmd ) ? ( ( cmd ) - > device - > lun & 0x07 ) : - 1
# define DELAY_DEFAULT 1000
# if defined(PCMCIA)
# define IRQ_MIN 0
# define IRQ_MAX 16
# else
# define IRQ_MIN 9
# if defined(__PPC)
# define IRQ_MAX (NR_IRQS-1)
# else
# define IRQ_MAX 12
# endif
# endif
enum {
not_issued = 0x0001 , /* command not yet issued */
selecting = 0x0002 , /* target is beeing selected */
identified = 0x0004 , /* IDENTIFY was sent */
disconnected = 0x0008 , /* target disconnected */
completed = 0x0010 , /* target sent COMMAND COMPLETE */
aborted = 0x0020 , /* ABORT was sent */
resetted = 0x0040 , /* BUS DEVICE RESET was sent */
spiordy = 0x0080 , /* waiting for SPIORDY to raise */
syncneg = 0x0100 , /* synchronous negotiation in progress */
aborting = 0x0200 , /* ABORT is pending */
resetting = 0x0400 , /* BUS DEVICE RESET is pending */
check_condition = 0x0800 , /* requesting sense after CHECK CONDITION */
} ;
MODULE_AUTHOR ( " J<EFBFBD> rgen Fischer " ) ;
MODULE_DESCRIPTION ( AHA152X_REVID ) ;
MODULE_LICENSE ( " GPL " ) ;
# if !defined(PCMCIA)
# if defined(MODULE)
static int io [ ] = { 0 , 0 } ;
module_param_array ( io , int , NULL , 0 ) ;
MODULE_PARM_DESC ( io , " base io address of controller " ) ;
static int irq [ ] = { 0 , 0 } ;
module_param_array ( irq , int , NULL , 0 ) ;
MODULE_PARM_DESC ( irq , " interrupt for controller " ) ;
static int scsiid [ ] = { 7 , 7 } ;
module_param_array ( scsiid , int , NULL , 0 ) ;
MODULE_PARM_DESC ( scsiid , " scsi id of controller " ) ;
static int reconnect [ ] = { 1 , 1 } ;
module_param_array ( reconnect , int , NULL , 0 ) ;
MODULE_PARM_DESC ( reconnect , " allow targets to disconnect " ) ;
static int parity [ ] = { 1 , 1 } ;
module_param_array ( parity , int , NULL , 0 ) ;
MODULE_PARM_DESC ( parity , " use scsi parity " ) ;
static int sync [ ] = { 1 , 1 } ;
module_param_array ( sync , int , NULL , 0 ) ;
MODULE_PARM_DESC ( sync , " use synchronous transfers " ) ;
static int delay [ ] = { DELAY_DEFAULT , DELAY_DEFAULT } ;
module_param_array ( delay , int , NULL , 0 ) ;
MODULE_PARM_DESC ( delay , " scsi reset delay " ) ;
static int exttrans [ ] = { 0 , 0 } ;
module_param_array ( exttrans , int , NULL , 0 ) ;
MODULE_PARM_DESC ( exttrans , " use extended translation " ) ;
# if !defined(AHA152X_DEBUG)
static int aha152x [ ] = { 0 , 11 , 7 , 1 , 1 , 0 , DELAY_DEFAULT , 0 } ;
module_param_array ( aha152x , int , NULL , 0 ) ;
MODULE_PARM_DESC ( aha152x , " parameters for first controller " ) ;
static int aha152x1 [ ] = { 0 , 11 , 7 , 1 , 1 , 0 , DELAY_DEFAULT , 0 } ;
module_param_array ( aha152x1 , int , NULL , 0 ) ;
MODULE_PARM_DESC ( aha152x1 , " parameters for second controller " ) ;
# else
static int debug [ ] = { DEBUG_DEFAULT , DEBUG_DEFAULT } ;
module_param_array ( debug , int , NULL , 0 ) ;
MODULE_PARM_DESC ( debug , " flags for driver debugging " ) ;
static int aha152x [ ] = { 0 , 11 , 7 , 1 , 1 , 1 , DELAY_DEFAULT , 0 , DEBUG_DEFAULT } ;
module_param_array ( aha152x , int , NULL , 0 ) ;
MODULE_PARM_DESC ( aha152x , " parameters for first controller " ) ;
static int aha152x1 [ ] = { 0 , 11 , 7 , 1 , 1 , 1 , DELAY_DEFAULT , 0 , DEBUG_DEFAULT } ;
module_param_array ( aha152x1 , int , NULL , 0 ) ;
MODULE_PARM_DESC ( aha152x1 , " parameters for second controller " ) ;
# endif /* !defined(AHA152X_DEBUG) */
# endif /* MODULE */
# ifdef __ISAPNP__
static struct isapnp_device_id id_table [ ] __devinitdata = {
{ ISAPNP_ANY_ID , ISAPNP_ANY_ID ,
ISAPNP_VENDOR ( ' A ' , ' D ' , ' P ' ) , ISAPNP_FUNCTION ( 0x1505 ) , 0 } ,
{ ISAPNP_ANY_ID , ISAPNP_ANY_ID ,
ISAPNP_VENDOR ( ' A ' , ' D ' , ' P ' ) , ISAPNP_FUNCTION ( 0x1530 ) , 0 } ,
{ ISAPNP_DEVICE_SINGLE_END , }
} ;
MODULE_DEVICE_TABLE ( isapnp , id_table ) ;
# endif /* ISAPNP */
# endif /* !PCMCIA */
static int registered_count = 0 ;
static struct Scsi_Host * aha152x_host [ 2 ] ;
2005-10-31 20:31:40 +03:00
static struct scsi_host_template aha152x_driver_template ;
2005-04-17 02:20:36 +04:00
/*
* internal states of the host
*
*/
enum aha152x_state {
idle = 0 ,
unknown ,
seldo ,
seldi ,
selto ,
busfree ,
msgo ,
cmd ,
msgi ,
status ,
datai ,
datao ,
parerr ,
rsti ,
maxstate
} ;
/*
* current state information of the host
*
*/
struct aha152x_hostdata {
Scsi_Cmnd * issue_SC ;
/* pending commands to issue */
Scsi_Cmnd * current_SC ;
/* current command on the bus */
Scsi_Cmnd * disconnected_SC ;
/* commands that disconnected */
Scsi_Cmnd * done_SC ;
/* command that was completed */
spinlock_t lock ;
/* host lock */
# if defined(AHA152X_DEBUG)
const char * locker ;
/* which function has the lock */
int lockerl ; /* where did it get it */
int debug ; /* current debugging setting */
# endif
# if defined(AHA152X_STAT)
int total_commands ;
int disconnections ;
int busfree_without_any_action ;
int busfree_without_old_command ;
int busfree_without_new_command ;
int busfree_without_done_command ;
int busfree_with_check_condition ;
int count [ maxstate ] ;
int count_trans [ maxstate ] ;
unsigned long time [ maxstate ] ;
# endif
int commands ; /* current number of commands */
int reconnect ; /* disconnection allowed */
int parity ; /* parity checking enabled */
int synchronous ; /* synchronous transferes enabled */
int delay ; /* reset out delay */
int ext_trans ; /* extended translation enabled */
int swint ; /* software-interrupt was fired during detect() */
int service ; /* bh needs to be run */
int in_intr ; /* bh is running */
/* current state,
previous state ,
last state different from current state */
enum aha152x_state state , prevstate , laststate ;
int target ;
/* reconnecting target */
unsigned char syncrate [ 8 ] ;
/* current synchronous transfer agreements */
unsigned char syncneg [ 8 ] ;
/* 0: no negotiation;
* 1 : negotiation in progress ;
* 2 : negotiation completed
*/
int cmd_i ;
/* number of sent bytes of current command */
int msgi_len ;
/* number of received message bytes */
unsigned char msgi [ 256 ] ;
/* received message bytes */
int msgo_i , msgo_len ;
/* number of sent bytes and length of current messages */
unsigned char msgo [ 256 ] ;
/* pending messages */
int data_len ;
/* number of sent/received bytes in dataphase */
unsigned long io_port0 ;
unsigned long io_port1 ;
# ifdef __ISAPNP__
struct pnp_dev * pnpdev ;
# endif
} ;
/*
* host specific command extension
*
*/
struct aha152x_scdata {
Scsi_Cmnd * next ; /* next sc in queue */
struct semaphore * sem ; /* semaphore to block on */
} ;
/* access macros for hostdata */
# define HOSTDATA(shpnt) ((struct aha152x_hostdata *) &shpnt->hostdata)
# define HOSTNO ((shpnt)->host_no)
# define CURRENT_SC (HOSTDATA(shpnt)->current_SC)
# define DONE_SC (HOSTDATA(shpnt)->done_SC)
# define ISSUE_SC (HOSTDATA(shpnt)->issue_SC)
# define DISCONNECTED_SC (HOSTDATA(shpnt)->disconnected_SC)
# define QLOCK (HOSTDATA(shpnt)->lock)
# define QLOCKER (HOSTDATA(shpnt)->locker)
# define QLOCKERL (HOSTDATA(shpnt)->lockerl)
# define STATE (HOSTDATA(shpnt)->state)
# define PREVSTATE (HOSTDATA(shpnt)->prevstate)
# define LASTSTATE (HOSTDATA(shpnt)->laststate)
# define RECONN_TARGET (HOSTDATA(shpnt)->target)
# define CMD_I (HOSTDATA(shpnt)->cmd_i)
# define MSGO(i) (HOSTDATA(shpnt)->msgo[i])
# define MSGO_I (HOSTDATA(shpnt)->msgo_i)
# define MSGOLEN (HOSTDATA(shpnt)->msgo_len)
# define ADDMSGO(x) (MSGOLEN<256 ? (void)(MSGO(MSGOLEN++)=x) : aha152x_error(shpnt,"MSGO overflow"))
# define MSGI(i) (HOSTDATA(shpnt)->msgi[i])
# define MSGILEN (HOSTDATA(shpnt)->msgi_len)
# define ADDMSGI(x) (MSGILEN<256 ? (void)(MSGI(MSGILEN++)=x) : aha152x_error(shpnt,"MSGI overflow"))
# define DATA_LEN (HOSTDATA(shpnt)->data_len)
# define SYNCRATE (HOSTDATA(shpnt)->syncrate[CURRENT_SC->device->id])
# define SYNCNEG (HOSTDATA(shpnt)->syncneg[CURRENT_SC->device->id])
# define DELAY (HOSTDATA(shpnt)->delay)
# define EXT_TRANS (HOSTDATA(shpnt)->ext_trans)
# define TC1550 (HOSTDATA(shpnt)->tc1550)
# define RECONNECT (HOSTDATA(shpnt)->reconnect)
# define PARITY (HOSTDATA(shpnt)->parity)
# define SYNCHRONOUS (HOSTDATA(shpnt)->synchronous)
# define HOSTIOPORT0 (HOSTDATA(shpnt)->io_port0)
# define HOSTIOPORT1 (HOSTDATA(shpnt)->io_port1)
# define SCDATA(SCpnt) ((struct aha152x_scdata *) (SCpnt)->host_scribble)
# define SCNEXT(SCpnt) SCDATA(SCpnt)->next
# define SCSEM(SCpnt) SCDATA(SCpnt)->sem
# define SG_ADDRESS(buffer) ((char *) (page_address((buffer)->page)+(buffer)->offset))
/* state handling */
static void seldi_run ( struct Scsi_Host * shpnt ) ;
static void seldo_run ( struct Scsi_Host * shpnt ) ;
static void selto_run ( struct Scsi_Host * shpnt ) ;
static void busfree_run ( struct Scsi_Host * shpnt ) ;
static void msgo_init ( struct Scsi_Host * shpnt ) ;
static void msgo_run ( struct Scsi_Host * shpnt ) ;
static void msgo_end ( struct Scsi_Host * shpnt ) ;
static void cmd_init ( struct Scsi_Host * shpnt ) ;
static void cmd_run ( struct Scsi_Host * shpnt ) ;
static void cmd_end ( struct Scsi_Host * shpnt ) ;
static void datai_init ( struct Scsi_Host * shpnt ) ;
static void datai_run ( struct Scsi_Host * shpnt ) ;
static void datai_end ( struct Scsi_Host * shpnt ) ;
static void datao_init ( struct Scsi_Host * shpnt ) ;
static void datao_run ( struct Scsi_Host * shpnt ) ;
static void datao_end ( struct Scsi_Host * shpnt ) ;
static void status_run ( struct Scsi_Host * shpnt ) ;
static void msgi_run ( struct Scsi_Host * shpnt ) ;
static void msgi_end ( struct Scsi_Host * shpnt ) ;
static void parerr_run ( struct Scsi_Host * shpnt ) ;
static void rsti_run ( struct Scsi_Host * shpnt ) ;
static void is_complete ( struct Scsi_Host * shpnt ) ;
/*
* driver states
*
*/
static struct {
char * name ;
void ( * init ) ( struct Scsi_Host * ) ;
void ( * run ) ( struct Scsi_Host * ) ;
void ( * end ) ( struct Scsi_Host * ) ;
int spio ;
} states [ ] = {
{ " idle " , NULL , NULL , NULL , 0 } ,
{ " unknown " , NULL , NULL , NULL , 0 } ,
{ " seldo " , NULL , seldo_run , NULL , 0 } ,
{ " seldi " , NULL , seldi_run , NULL , 0 } ,
{ " selto " , NULL , selto_run , NULL , 0 } ,
{ " busfree " , NULL , busfree_run , NULL , 0 } ,
{ " msgo " , msgo_init , msgo_run , msgo_end , 1 } ,
{ " cmd " , cmd_init , cmd_run , cmd_end , 1 } ,
{ " msgi " , NULL , msgi_run , msgi_end , 1 } ,
{ " status " , NULL , status_run , NULL , 1 } ,
{ " datai " , datai_init , datai_run , datai_end , 0 } ,
{ " datao " , datao_init , datao_run , datao_end , 0 } ,
{ " parerr " , NULL , parerr_run , NULL , 0 } ,
{ " rsti " , NULL , rsti_run , NULL , 0 } ,
} ;
/* setup & interrupt */
static irqreturn_t intr ( int irq , void * dev_id , struct pt_regs * ) ;
static void reset_ports ( struct Scsi_Host * shpnt ) ;
static void aha152x_error ( struct Scsi_Host * shpnt , char * msg ) ;
static void done ( struct Scsi_Host * shpnt , int error ) ;
/* diagnostics */
static void disp_ports ( struct Scsi_Host * shpnt ) ;
static void show_command ( Scsi_Cmnd * ptr ) ;
static void show_queues ( struct Scsi_Host * shpnt ) ;
static void disp_enintr ( struct Scsi_Host * shpnt ) ;
/*
* queue services :
*
*/
static inline void append_SC ( Scsi_Cmnd * * SC , Scsi_Cmnd * new_SC )
{
Scsi_Cmnd * end ;
SCNEXT ( new_SC ) = NULL ;
if ( ! * SC )
* SC = new_SC ;
else {
for ( end = * SC ; SCNEXT ( end ) ; end = SCNEXT ( end ) )
;
SCNEXT ( end ) = new_SC ;
}
}
static inline Scsi_Cmnd * remove_first_SC ( Scsi_Cmnd * * SC )
{
Scsi_Cmnd * ptr ;
ptr = * SC ;
if ( ptr ) {
* SC = SCNEXT ( * SC ) ;
SCNEXT ( ptr ) = NULL ;
}
return ptr ;
}
static inline Scsi_Cmnd * remove_lun_SC ( Scsi_Cmnd * * SC , int target , int lun )
{
Scsi_Cmnd * ptr , * prev ;
for ( ptr = * SC , prev = NULL ;
ptr & & ( ( ptr - > device - > id ! = target ) | | ( ptr - > device - > lun ! = lun ) ) ;
prev = ptr , ptr = SCNEXT ( ptr ) )
;
if ( ptr ) {
if ( prev )
SCNEXT ( prev ) = SCNEXT ( ptr ) ;
else
* SC = SCNEXT ( ptr ) ;
SCNEXT ( ptr ) = NULL ;
}
return ptr ;
}
static inline Scsi_Cmnd * remove_SC ( Scsi_Cmnd * * SC , Scsi_Cmnd * SCp )
{
Scsi_Cmnd * ptr , * prev ;
for ( ptr = * SC , prev = NULL ;
ptr & & SCp ! = ptr ;
prev = ptr , ptr = SCNEXT ( ptr ) )
;
if ( ptr ) {
if ( prev )
SCNEXT ( prev ) = SCNEXT ( ptr ) ;
else
* SC = SCNEXT ( ptr ) ;
SCNEXT ( ptr ) = NULL ;
}
return ptr ;
}
static inline struct Scsi_Host * lookup_irq ( int irqno )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( aha152x_host ) ; i + + )
if ( aha152x_host [ i ] & & aha152x_host [ i ] - > irq = = irqno )
return aha152x_host [ i ] ;
return NULL ;
}
static irqreturn_t swintr ( int irqno , void * dev_id , struct pt_regs * regs )
{
struct Scsi_Host * shpnt = lookup_irq ( irqno ) ;
if ( ! shpnt ) {
printk ( KERN_ERR " aha152x: catched software interrupt %d for unknown controller. \n " , irqno ) ;
return IRQ_NONE ;
}
HOSTDATA ( shpnt ) - > swint + + ;
SETPORT ( DMACNTRL0 , INTEN ) ;
return IRQ_HANDLED ;
}
struct Scsi_Host * aha152x_probe_one ( struct aha152x_setup * setup )
{
struct Scsi_Host * shpnt ;
shpnt = scsi_host_alloc ( & aha152x_driver_template , sizeof ( struct aha152x_hostdata ) ) ;
if ( ! shpnt ) {
printk ( KERN_ERR " aha152x: scsi_host_alloc failed \n " ) ;
return NULL ;
}
/* need to have host registered before triggering any interrupt */
aha152x_host [ registered_count ] = shpnt ;
memset ( HOSTDATA ( shpnt ) , 0 , sizeof * HOSTDATA ( shpnt ) ) ;
shpnt - > io_port = setup - > io_port ;
shpnt - > n_io_port = IO_RANGE ;
shpnt - > irq = setup - > irq ;
if ( ! setup - > tc1550 ) {
HOSTIOPORT0 = setup - > io_port ;
HOSTIOPORT1 = setup - > io_port ;
} else {
HOSTIOPORT0 = setup - > io_port + 0x10 ;
HOSTIOPORT1 = setup - > io_port - 0x10 ;
}
spin_lock_init ( & QLOCK ) ;
RECONNECT = setup - > reconnect ;
SYNCHRONOUS = setup - > synchronous ;
PARITY = setup - > parity ;
DELAY = setup - > delay ;
EXT_TRANS = setup - > ext_trans ;
# if defined(AHA152X_DEBUG)
HOSTDATA ( shpnt ) - > debug = setup - > debug ;
# endif
SETPORT ( SCSIID , setup - > scsiid < < 4 ) ;
shpnt - > this_id = setup - > scsiid ;
if ( setup - > reconnect )
shpnt - > can_queue = AHA152X_MAXQUEUE ;
/* RESET OUT */
printk ( " aha152x: resetting bus... \n " ) ;
SETPORT ( SCSISEQ , SCSIRSTO ) ;
mdelay ( 256 ) ;
SETPORT ( SCSISEQ , 0 ) ;
mdelay ( DELAY ) ;
reset_ports ( shpnt ) ;
printk ( KERN_INFO
" aha152x%d%s: "
" vital data: rev=%x, "
" io=0x%03lx (0x%03lx/0x%03lx), "
" irq=%d, "
" scsiid=%d, "
" reconnect=%s, "
" parity=%s, "
" synchronous=%s, "
" delay=%d, "
" extended translation=%s \n " ,
shpnt - > host_no , setup - > tc1550 ? " (tc1550 mode) " : " " ,
GETPORT ( REV ) & 0x7 ,
shpnt - > io_port , HOSTIOPORT0 , HOSTIOPORT1 ,
shpnt - > irq ,
shpnt - > this_id ,
RECONNECT ? " enabled " : " disabled " ,
PARITY ? " enabled " : " disabled " ,
SYNCHRONOUS ? " enabled " : " disabled " ,
DELAY ,
EXT_TRANS ? " enabled " : " disabled " ) ;
/* not expecting any interrupts */
SETPORT ( SIMODE0 , 0 ) ;
SETPORT ( SIMODE1 , 0 ) ;
2006-07-02 06:29:42 +04:00
if ( request_irq ( shpnt - > irq , swintr , IRQF_DISABLED | IRQF_SHARED , " aha152x " , shpnt ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " aha152x%d: irq %d busy. \n " , shpnt - > host_no , shpnt - > irq ) ;
goto out_host_put ;
}
HOSTDATA ( shpnt ) - > swint = 0 ;
printk ( KERN_INFO " aha152x%d: trying software interrupt, " , shpnt - > host_no ) ;
mb ( ) ;
SETPORT ( DMACNTRL0 , SWINT | INTEN ) ;
mdelay ( 1000 ) ;
free_irq ( shpnt - > irq , shpnt ) ;
if ( ! HOSTDATA ( shpnt ) - > swint ) {
if ( TESTHI ( DMASTAT , INTSTAT ) ) {
printk ( " lost. \n " ) ;
} else {
printk ( " failed. \n " ) ;
}
SETPORT ( DMACNTRL0 , INTEN ) ;
printk ( KERN_ERR " aha152x%d: irq %d possibly wrong. "
" Please verify. \n " , shpnt - > host_no , shpnt - > irq ) ;
goto out_host_put ;
}
printk ( " ok. \n " ) ;
/* clear interrupts */
SETPORT ( SSTAT0 , 0x7f ) ;
SETPORT ( SSTAT1 , 0xef ) ;
2006-07-02 06:29:42 +04:00
if ( request_irq ( shpnt - > irq , intr , IRQF_DISABLED | IRQF_SHARED , " aha152x " , shpnt ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " aha152x%d: failed to reassign irq %d. \n " , shpnt - > host_no , shpnt - > irq ) ;
goto out_host_put ;
}
if ( scsi_add_host ( shpnt , NULL ) ) {
free_irq ( shpnt - > irq , shpnt ) ;
printk ( KERN_ERR " aha152x%d: failed to add host. \n " , shpnt - > host_no ) ;
goto out_host_put ;
}
scsi_scan_host ( shpnt ) ;
registered_count + + ;
return shpnt ;
out_host_put :
aha152x_host [ registered_count ] = NULL ;
scsi_host_put ( shpnt ) ;
return NULL ;
}
void aha152x_release ( struct Scsi_Host * shpnt )
{
if ( ! shpnt )
return ;
if ( shpnt - > irq )
free_irq ( shpnt - > irq , shpnt ) ;
# if !defined(PCMCIA)
if ( shpnt - > io_port )
release_region ( shpnt - > io_port , IO_RANGE ) ;
# endif
# ifdef __ISAPNP__
if ( HOSTDATA ( shpnt ) - > pnpdev )
pnp_device_detach ( HOSTDATA ( shpnt ) - > pnpdev ) ;
# endif
scsi_remove_host ( shpnt ) ;
scsi_host_put ( shpnt ) ;
}
/*
* setup controller to generate interrupts depending
* on current state ( lock has to be acquired )
*
*/
static int setup_expected_interrupts ( struct Scsi_Host * shpnt )
{
if ( CURRENT_SC ) {
CURRENT_SC - > SCp . phase | = 1 < < 16 ;
if ( CURRENT_SC - > SCp . phase & selecting ) {
DPRINTK ( debug_intr , DEBUG_LEAD " expecting: (seldo) (seltimo) (seldi) \n " , CMDINFO ( CURRENT_SC ) ) ;
SETPORT ( SSTAT1 , SELTO ) ;
SETPORT ( SIMODE0 , ENSELDO | ( DISCONNECTED_SC ? ENSELDI : 0 ) ) ;
SETPORT ( SIMODE1 , ENSELTIMO ) ;
} else {
DPRINTK ( debug_intr , DEBUG_LEAD " expecting: (phase change) (busfree) %s \n " , CMDINFO ( CURRENT_SC ) , CURRENT_SC - > SCp . phase & spiordy ? " (spiordy) " : " " ) ;
SETPORT ( SIMODE0 , ( CURRENT_SC - > SCp . phase & spiordy ) ? ENSPIORDY : 0 ) ;
SETPORT ( SIMODE1 , ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE ) ;
}
} else if ( STATE = = seldi ) {
DPRINTK ( debug_intr , DEBUG_LEAD " expecting: (phase change) (identify) \n " , CMDINFO ( CURRENT_SC ) ) ;
SETPORT ( SIMODE0 , 0 ) ;
SETPORT ( SIMODE1 , ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE ) ;
} else {
DPRINTK ( debug_intr , DEBUG_LEAD " expecting: %s %s \n " ,
CMDINFO ( CURRENT_SC ) ,
DISCONNECTED_SC ? " (reselection) " : " " ,
ISSUE_SC ? " (busfree) " : " " ) ;
SETPORT ( SIMODE0 , DISCONNECTED_SC ? ENSELDI : 0 ) ;
SETPORT ( SIMODE1 , ENSCSIRST | ( ( ISSUE_SC | | DONE_SC ) ? ENBUSFREE : 0 ) ) ;
}
if ( ! HOSTDATA ( shpnt ) - > in_intr )
SETBITS ( DMACNTRL0 , INTEN ) ;
return TESTHI ( DMASTAT , INTSTAT ) ;
}
/*
* Queue a command and setup interrupts for a free bus .
*/
static int aha152x_internal_queue ( Scsi_Cmnd * SCpnt , struct semaphore * sem , int phase , void ( * done ) ( Scsi_Cmnd * ) )
{
struct Scsi_Host * shpnt = SCpnt - > device - > host ;
unsigned long flags ;
# if defined(AHA152X_DEBUG)
if ( HOSTDATA ( shpnt ) - > debug & debug_queue ) {
printk ( INFO_LEAD " queue: %p; cmd_len=%d pieces=%d size=%u cmnd= " ,
CMDINFO ( SCpnt ) , SCpnt , SCpnt - > cmd_len , SCpnt - > use_sg , SCpnt - > request_bufflen ) ;
2005-04-03 23:53:59 +04:00
__scsi_print_command ( SCpnt - > cmnd ) ;
2005-04-17 02:20:36 +04:00
}
# endif
SCpnt - > scsi_done = done ;
SCpnt - > resid = SCpnt - > request_bufflen ;
SCpnt - > SCp . phase = not_issued | phase ;
SCpnt - > SCp . Status = CHECK_CONDITION ;
SCpnt - > SCp . Message = 0 ;
SCpnt - > SCp . have_data_in = 0 ;
SCpnt - > SCp . sent_command = 0 ;
if ( SCpnt - > SCp . phase & ( resetting | check_condition ) ) {
if ( SCpnt - > host_scribble = = 0 | | SCSEM ( SCpnt ) | | SCNEXT ( SCpnt ) ) {
printk ( ERR_LEAD " cannot reuse command \n " , CMDINFO ( SCpnt ) ) ;
return FAILED ;
}
} else {
SCpnt - > host_scribble = kmalloc ( sizeof ( struct aha152x_scdata ) , GFP_ATOMIC ) ;
if ( SCpnt - > host_scribble = = 0 ) {
printk ( ERR_LEAD " allocation failed \n " , CMDINFO ( SCpnt ) ) ;
return FAILED ;
}
}
SCNEXT ( SCpnt ) = NULL ;
SCSEM ( SCpnt ) = sem ;
/* setup scratch area
SCp . ptr : buffer pointer
SCp . this_residual : buffer length
SCp . buffer : next buffer
SCp . buffers_residual : left buffers in list
SCp . phase : current state of the command */
if ( SCpnt - > use_sg ) {
SCpnt - > SCp . buffer = ( struct scatterlist * ) SCpnt - > request_buffer ;
SCpnt - > SCp . ptr = SG_ADDRESS ( SCpnt - > SCp . buffer ) ;
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 ;
}
DO_LOCK ( flags ) ;
# if defined(AHA152X_STAT)
HOSTDATA ( shpnt ) - > total_commands + + ;
# endif
/* Turn led on, when this is the first command. */
HOSTDATA ( shpnt ) - > commands + + ;
if ( HOSTDATA ( shpnt ) - > commands = = 1 )
SETPORT ( PORTA , 1 ) ;
append_SC ( & ISSUE_SC , SCpnt ) ;
if ( ! HOSTDATA ( shpnt ) - > in_intr )
setup_expected_interrupts ( shpnt ) ;
DO_UNLOCK ( flags ) ;
return 0 ;
}
/*
* queue a command
*
*/
static int aha152x_queue ( Scsi_Cmnd * SCpnt , void ( * done ) ( Scsi_Cmnd * ) )
{
#if 0
if ( * SCpnt - > cmnd = = REQUEST_SENSE ) {
SCpnt - > result = 0 ;
done ( SCpnt ) ;
return 0 ;
}
# endif
return aha152x_internal_queue ( SCpnt , NULL , 0 , done ) ;
}
/*
*
*
*/
static void reset_done ( Scsi_Cmnd * SCpnt )
{
#if 0
struct Scsi_Host * shpnt = SCpnt - > host ;
DPRINTK ( debug_eh , INFO_LEAD " reset_done called \n " , CMDINFO ( SCpnt ) ) ;
# endif
if ( SCSEM ( SCpnt ) ) {
up ( SCSEM ( SCpnt ) ) ;
} else {
printk ( KERN_ERR " aha152x: reset_done w/o semaphore \n " ) ;
}
}
/*
* Abort a command
*
*/
static int aha152x_abort ( Scsi_Cmnd * SCpnt )
{
struct Scsi_Host * shpnt = SCpnt - > device - > host ;
Scsi_Cmnd * ptr ;
unsigned long flags ;
# if defined(AHA152X_DEBUG)
if ( HOSTDATA ( shpnt ) - > debug & debug_eh ) {
printk ( DEBUG_LEAD " abort(%p) " , CMDINFO ( SCpnt ) , SCpnt ) ;
show_queues ( shpnt ) ;
}
# endif
DO_LOCK ( flags ) ;
ptr = remove_SC ( & ISSUE_SC , SCpnt ) ;
if ( ptr ) {
DPRINTK ( debug_eh , DEBUG_LEAD " not yet issued - SUCCESS \n " , CMDINFO ( SCpnt ) ) ;
HOSTDATA ( shpnt ) - > commands - - ;
if ( ! HOSTDATA ( shpnt ) - > commands )
SETPORT ( PORTA , 0 ) ;
DO_UNLOCK ( flags ) ;
kfree ( SCpnt - > host_scribble ) ;
SCpnt - > host_scribble = NULL ;
return SUCCESS ;
}
DO_UNLOCK ( flags ) ;
/*
* FIXME :
* for current command : queue ABORT for message out and raise ATN
* for disconnected command : pseudo SC with ABORT message or ABORT on reselection ?
*
*/
printk ( ERR_LEAD " cannot abort running or disconnected command \n " , CMDINFO ( SCpnt ) ) ;
return FAILED ;
}
static void timer_expired ( unsigned long p )
{
Scsi_Cmnd * SCp = ( Scsi_Cmnd * ) p ;
struct semaphore * sem = SCSEM ( SCp ) ;
struct Scsi_Host * shpnt = SCp - > device - > host ;
unsigned long flags ;
/* remove command from issue queue */
DO_LOCK ( flags ) ;
remove_SC ( & ISSUE_SC , SCp ) ;
DO_UNLOCK ( flags ) ;
up ( sem ) ;
}
/*
* Reset a device
*
*/
static int aha152x_device_reset ( Scsi_Cmnd * SCpnt )
{
struct Scsi_Host * shpnt = SCpnt - > device - > host ;
DECLARE_MUTEX_LOCKED ( sem ) ;
struct timer_list timer ;
int ret , issued , disconnected ;
unsigned long flags ;
# if defined(AHA152X_DEBUG)
if ( HOSTDATA ( shpnt ) - > debug & debug_eh ) {
printk ( INFO_LEAD " aha152x_device_reset(%p) " , CMDINFO ( SCpnt ) , SCpnt ) ;
show_queues ( shpnt ) ;
}
# endif
if ( CURRENT_SC = = SCpnt ) {
printk ( ERR_LEAD " cannot reset current device \n " , CMDINFO ( SCpnt ) ) ;
return FAILED ;
}
DO_LOCK ( flags ) ;
issued = remove_SC ( & ISSUE_SC , SCpnt ) = = 0 ;
disconnected = issued & & remove_SC ( & DISCONNECTED_SC , SCpnt ) ;
DO_UNLOCK ( flags ) ;
SCpnt - > cmd_len = 0 ;
SCpnt - > use_sg = 0 ;
SCpnt - > request_buffer = NULL ;
SCpnt - > request_bufflen = 0 ;
init_timer ( & timer ) ;
timer . data = ( unsigned long ) SCpnt ;
timer . expires = jiffies + 100 * HZ ; /* 10s */
timer . function = ( void ( * ) ( unsigned long ) ) timer_expired ;
aha152x_internal_queue ( SCpnt , & sem , resetting , reset_done ) ;
add_timer ( & timer ) ;
down ( & sem ) ;
del_timer ( & timer ) ;
SCpnt - > cmd_len = SCpnt - > old_cmd_len ;
SCpnt - > use_sg = SCpnt - > old_use_sg ;
SCpnt - > request_buffer = SCpnt - > buffer ;
SCpnt - > request_bufflen = SCpnt - > bufflen ;
DO_LOCK ( flags ) ;
if ( SCpnt - > SCp . phase & resetted ) {
HOSTDATA ( shpnt ) - > commands - - ;
if ( ! HOSTDATA ( shpnt ) - > commands )
SETPORT ( PORTA , 0 ) ;
kfree ( SCpnt - > host_scribble ) ;
SCpnt - > host_scribble = NULL ;
ret = SUCCESS ;
} else {
/* requeue */
if ( ! issued ) {
append_SC ( & ISSUE_SC , SCpnt ) ;
} else if ( disconnected ) {
append_SC ( & DISCONNECTED_SC , SCpnt ) ;
}
ret = FAILED ;
}
DO_UNLOCK ( flags ) ;
return ret ;
}
static void free_hard_reset_SCs ( struct Scsi_Host * shpnt , Scsi_Cmnd * * SCs )
{
Scsi_Cmnd * ptr ;
ptr = * SCs ;
while ( ptr ) {
Scsi_Cmnd * next ;
if ( SCDATA ( ptr ) ) {
next = SCNEXT ( ptr ) ;
} else {
printk ( DEBUG_LEAD " queue corrupted at %p \n " , CMDINFO ( ptr ) , ptr ) ;
next = NULL ;
}
if ( ! ptr - > device - > soft_reset ) {
DPRINTK ( debug_eh , DEBUG_LEAD " disconnected command %p removed \n " , CMDINFO ( ptr ) , ptr ) ;
remove_SC ( SCs , ptr ) ;
HOSTDATA ( shpnt ) - > commands - - ;
kfree ( ptr - > host_scribble ) ;
ptr - > host_scribble = NULL ;
}
ptr = next ;
}
}
/*
* Reset the bus
*
*/
2006-02-19 02:31:51 +03:00
static int aha152x_bus_reset_host ( struct Scsi_Host * shpnt )
2005-04-17 02:20:36 +04:00
{
unsigned long flags ;
DO_LOCK ( flags ) ;
# if defined(AHA152X_DEBUG)
if ( HOSTDATA ( shpnt ) - > debug & debug_eh ) {
2006-02-19 02:31:51 +03:00
printk ( KERN_DEBUG " scsi%d: bus reset " , shpnt - > host_no ) ;
2005-04-17 02:20:36 +04:00
show_queues ( shpnt ) ;
}
# endif
free_hard_reset_SCs ( shpnt , & ISSUE_SC ) ;
free_hard_reset_SCs ( shpnt , & DISCONNECTED_SC ) ;
2006-02-19 02:31:51 +03:00
DPRINTK ( debug_eh , KERN_DEBUG " scsi%d: resetting bus \n " , shpnt - > host_no ) ;
2005-04-17 02:20:36 +04:00
SETPORT ( SCSISEQ , SCSIRSTO ) ;
mdelay ( 256 ) ;
SETPORT ( SCSISEQ , 0 ) ;
mdelay ( DELAY ) ;
2006-02-19 02:31:51 +03:00
DPRINTK ( debug_eh , KERN_DEBUG " scsi%d: bus resetted \n " , shpnt - > host_no ) ;
2005-04-17 02:20:36 +04:00
setup_expected_interrupts ( shpnt ) ;
if ( HOSTDATA ( shpnt ) - > commands = = 0 )
SETPORT ( PORTA , 0 ) ;
DO_UNLOCK ( flags ) ;
return SUCCESS ;
}
2006-02-19 02:31:51 +03:00
/*
* Reset the bus
*
*/
static int aha152x_bus_reset ( Scsi_Cmnd * SCpnt )
{
return aha152x_bus_reset_host ( SCpnt - > device - > host ) ;
}
2005-04-17 02:20:36 +04:00
/*
* Restore default values to the AIC - 6260 registers and reset the fifos
*
*/
static void reset_ports ( struct Scsi_Host * shpnt )
{
unsigned long flags ;
/* disable interrupts */
SETPORT ( DMACNTRL0 , RSTFIFO ) ;
SETPORT ( SCSISEQ , 0 ) ;
SETPORT ( SXFRCTL1 , 0 ) ;
SETPORT ( SCSISIG , 0 ) ;
SETRATE ( 0 ) ;
/* clear all interrupt conditions */
SETPORT ( SSTAT0 , 0x7f ) ;
SETPORT ( SSTAT1 , 0xef ) ;
SETPORT ( SSTAT4 , SYNCERR | FWERR | FRERR ) ;
SETPORT ( DMACNTRL0 , 0 ) ;
SETPORT ( DMACNTRL1 , 0 ) ;
SETPORT ( BRSTCNTRL , 0xf1 ) ;
/* clear SCSI fifos and transfer count */
SETPORT ( SXFRCTL0 , CH1 | CLRCH1 | CLRSTCNT ) ;
SETPORT ( SXFRCTL0 , CH1 ) ;
DO_LOCK ( flags ) ;
setup_expected_interrupts ( shpnt ) ;
DO_UNLOCK ( flags ) ;
}
/*
* Reset the host ( bus and controller )
*
*/
2006-02-19 02:31:51 +03:00
int aha152x_host_reset_host ( struct Scsi_Host * shpnt )
2005-04-17 02:20:36 +04:00
{
2006-02-19 02:31:51 +03:00
DPRINTK ( debug_eh , KERN_DEBUG " scsi%d: host reset \n " , shpnt - > host_no ) ;
2005-04-17 02:20:36 +04:00
2006-02-19 02:31:51 +03:00
aha152x_bus_reset_host ( shpnt ) ;
2005-04-17 02:20:36 +04:00
2006-02-19 02:31:51 +03:00
DPRINTK ( debug_eh , KERN_DEBUG " scsi%d: resetting ports \n " , shpnt - > host_no ) ;
reset_ports ( shpnt ) ;
2005-04-17 02:20:36 +04:00
return SUCCESS ;
}
2006-02-19 02:31:51 +03:00
/*
* Reset the host ( bus and controller )
*
*/
static int aha152x_host_reset ( Scsi_Cmnd * SCpnt )
{
return aha152x_host_reset_host ( SCpnt - > device - > host ) ;
}
2005-04-17 02:20:36 +04:00
/*
* Return the " logical geometry "
*
*/
static int aha152x_biosparam ( struct scsi_device * sdev , struct block_device * bdev ,
sector_t capacity , int * info_array )
{
struct Scsi_Host * shpnt = sdev - > host ;
/* try default translation */
info_array [ 0 ] = 64 ;
info_array [ 1 ] = 32 ;
info_array [ 2 ] = ( unsigned long ) 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 ( bdev , capacity , info ) < 0 | |
! ( ( info [ 0 ] = = 64 & & info [ 1 ] = = 32 ) | | ( info [ 0 ] = = 255 & & info [ 1 ] = = 63 ) ) ) {
if ( EXT_TRANS ) {
printk ( KERN_NOTICE
" aha152x: unable to verify geometry for disk with >1GB. \n "
" using extended translation. \n " ) ;
info_array [ 0 ] = 255 ;
info_array [ 1 ] = 63 ;
info_array [ 2 ] = ( unsigned long ) capacity / ( 255 * 63 ) ;
} else {
printk ( KERN_NOTICE
" aha152x: unable to verify geometry for disk with >1GB. \n "
" Using default translation. Please verify yourself. \n "
" Perhaps you need to enable extended translation in the driver. \n "
" See Documentation/scsi/aha152x.txt 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 ( KERN_NOTICE
" aha152x: current partition table is using extended translation. \n "
" using it also, although it's not explicitly enabled. \n " ) ;
}
}
}
return 0 ;
}
/*
* Internal done function
*
*/
static void done ( struct Scsi_Host * shpnt , int error )
{
if ( CURRENT_SC ) {
if ( DONE_SC )
printk ( ERR_LEAD " there's already a completed command %p - will cause abort \n " , CMDINFO ( CURRENT_SC ) , DONE_SC ) ;
DONE_SC = CURRENT_SC ;
CURRENT_SC = NULL ;
DONE_SC - > result = error ;
} else
printk ( KERN_ERR " aha152x: done() called outside of command \n " ) ;
}
static struct work_struct aha152x_tq ;
/*
* Run service completions on the card with interrupts enabled .
*
*/
static void run ( void )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( aha152x_host ) ; i + + ) {
2006-02-19 02:31:51 +03:00
is_complete ( aha152x_host [ i ] ) ;
2005-04-17 02:20:36 +04:00
}
}
/*
2006-02-19 02:31:51 +03:00
* Interrupt handler
2005-04-17 02:20:36 +04:00
*
*/
static irqreturn_t intr ( int irqno , void * dev_id , struct pt_regs * regs )
{
struct Scsi_Host * shpnt = lookup_irq ( irqno ) ;
2006-02-19 02:31:51 +03:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
unsigned char rev , dmacntrl0 ;
if ( ! shpnt ) {
printk ( KERN_ERR " aha152x: catched interrupt %d for unknown controller. \n " , irqno ) ;
return IRQ_NONE ;
}
/*
* Read a couple of registers that are known to not be all 1 ' s . If
* we read all 1 ' s ( - 1 ) , that means that either :
*
* a . The host adapter chip has gone bad , and we cannot control it ,
* OR
* b . The host adapter is a PCMCIA card that has been ejected
*
* In either case , we cannot do anything with the host adapter at
* this point in time . So just ignore the interrupt and return .
* In the latter case , the interrupt might actually be meant for
* someone else sharing this IRQ , and that driver will handle it .
*/
rev = GETPORT ( REV ) ;
dmacntrl0 = GETPORT ( DMACNTRL0 ) ;
if ( ( rev = = 0xFF ) & & ( dmacntrl0 = = 0xFF ) )
return IRQ_NONE ;
2006-02-19 02:31:51 +03:00
if ( TESTLO ( DMASTAT , INTSTAT ) )
return IRQ_NONE ;
2005-04-17 02:20:36 +04:00
/* no more interrupts from the controller, while we're busy.
INTEN is restored by the BH handler */
CLRBITS ( DMACNTRL0 , INTEN ) ;
2006-02-19 02:31:51 +03:00
DO_LOCK ( flags ) ;
if ( HOSTDATA ( shpnt ) - > service = = 0 ) {
HOSTDATA ( shpnt ) - > service = 1 ;
/* Poke the BH handler */
INIT_WORK ( & aha152x_tq , ( void * ) run , NULL ) ;
schedule_work ( & aha152x_tq ) ;
2005-04-17 02:20:36 +04:00
}
2006-02-19 02:31:51 +03:00
DO_UNLOCK ( flags ) ;
2005-04-17 02:20:36 +04:00
return IRQ_HANDLED ;
}
/*
* busfree phase
* - handle completition / disconnection / error of current command
* - start selection for next command ( if any )
*/
static void busfree_run ( struct Scsi_Host * shpnt )
{
unsigned long flags ;
# if defined(AHA152X_STAT)
int action = 0 ;
# endif
SETPORT ( SXFRCTL0 , CH1 | CLRCH1 | CLRSTCNT ) ;
SETPORT ( SXFRCTL0 , CH1 ) ;
SETPORT ( SSTAT1 , CLRBUSFREE ) ;
if ( CURRENT_SC ) {
# if defined(AHA152X_STAT)
action + + ;
# endif
CURRENT_SC - > SCp . phase & = ~ syncneg ;
if ( CURRENT_SC - > SCp . phase & completed ) {
/* target sent COMMAND COMPLETE */
done ( shpnt , ( CURRENT_SC - > SCp . Status & 0xff ) | ( ( CURRENT_SC - > SCp . Message & 0xff ) < < 8 ) | ( DID_OK < < 16 ) ) ;
} else if ( CURRENT_SC - > SCp . phase & aborted ) {
DPRINTK ( debug_eh , DEBUG_LEAD " ABORT sent \n " , CMDINFO ( CURRENT_SC ) ) ;
done ( shpnt , ( CURRENT_SC - > SCp . Status & 0xff ) | ( ( CURRENT_SC - > SCp . Message & 0xff ) < < 8 ) | ( DID_ABORT < < 16 ) ) ;
} else if ( CURRENT_SC - > SCp . phase & resetted ) {
DPRINTK ( debug_eh , DEBUG_LEAD " BUS DEVICE RESET sent \n " , CMDINFO ( CURRENT_SC ) ) ;
done ( shpnt , ( CURRENT_SC - > SCp . Status & 0xff ) | ( ( CURRENT_SC - > SCp . Message & 0xff ) < < 8 ) | ( DID_RESET < < 16 ) ) ;
} else if ( CURRENT_SC - > SCp . phase & disconnected ) {
/* target sent DISCONNECT */
DPRINTK ( debug_selection , DEBUG_LEAD " target disconnected at %d/%d \n " ,
CMDINFO ( CURRENT_SC ) ,
CURRENT_SC - > resid ,
CURRENT_SC - > request_bufflen ) ;
# if defined(AHA152X_STAT)
HOSTDATA ( shpnt ) - > disconnections + + ;
# endif
append_SC ( & DISCONNECTED_SC , CURRENT_SC ) ;
CURRENT_SC - > SCp . phase | = 1 < < 16 ;
CURRENT_SC = NULL ;
} else {
done ( shpnt , DID_ERROR < < 16 ) ;
}
# if defined(AHA152X_STAT)
} else {
HOSTDATA ( shpnt ) - > busfree_without_old_command + + ;
# endif
}
DO_LOCK ( flags ) ;
if ( DONE_SC ) {
# if defined(AHA152X_STAT)
action + + ;
# endif
if ( DONE_SC - > SCp . phase & check_condition ) {
#if 0
if ( HOSTDATA ( shpnt ) - > debug & debug_eh ) {
printk ( ERR_LEAD " received sense: " , CMDINFO ( DONE_SC ) ) ;
2005-04-03 23:53:59 +04:00
scsi_print_sense ( " bh " , DONE_SC ) ;
2005-04-17 02:20:36 +04:00
}
# endif
/* restore old command */
memcpy ( ( void * ) DONE_SC - > cmnd , ( void * ) DONE_SC - > data_cmnd , sizeof ( DONE_SC - > data_cmnd ) ) ;
DONE_SC - > request_buffer = DONE_SC - > buffer ;
DONE_SC - > request_bufflen = DONE_SC - > bufflen ;
DONE_SC - > use_sg = DONE_SC - > old_use_sg ;
DONE_SC - > cmd_len = DONE_SC - > old_cmd_len ;
DONE_SC - > SCp . Status = 0x02 ;
HOSTDATA ( shpnt ) - > commands - - ;
if ( ! HOSTDATA ( shpnt ) - > commands )
SETPORT ( PORTA , 0 ) ; /* turn led off */
} else if ( DONE_SC - > SCp . Status = = 0x02 ) {
# if defined(AHA152X_STAT)
HOSTDATA ( shpnt ) - > busfree_with_check_condition + + ;
# endif
#if 0
DPRINTK ( debug_eh , ERR_LEAD " CHECK CONDITION found \n " , CMDINFO ( DONE_SC ) ) ;
# endif
if ( ! ( DONE_SC - > SCp . Status & not_issued ) ) {
Scsi_Cmnd * ptr = DONE_SC ;
DONE_SC = NULL ;
#if 0
DPRINTK ( debug_eh , ERR_LEAD " requesting sense \n " , CMDINFO ( ptr ) ) ;
# endif
ptr - > cmnd [ 0 ] = REQUEST_SENSE ;
ptr - > cmnd [ 1 ] = 0 ;
ptr - > cmnd [ 2 ] = 0 ;
ptr - > cmnd [ 3 ] = 0 ;
ptr - > cmnd [ 4 ] = sizeof ( ptr - > sense_buffer ) ;
ptr - > cmnd [ 5 ] = 0 ;
ptr - > cmd_len = 6 ;
ptr - > use_sg = 0 ;
ptr - > request_buffer = ptr - > sense_buffer ;
ptr - > request_bufflen = sizeof ( ptr - > sense_buffer ) ;
DO_UNLOCK ( flags ) ;
aha152x_internal_queue ( ptr , NULL , check_condition , ptr - > scsi_done ) ;
DO_LOCK ( flags ) ;
#if 0
} else {
DPRINTK ( debug_eh , ERR_LEAD " command not issued - CHECK CONDITION ignored \n " , CMDINFO ( DONE_SC ) ) ;
# endif
}
}
if ( DONE_SC & & DONE_SC - > scsi_done ) {
# if defined(AHA152X_DEBUG)
int hostno = DONE_SC - > device - > host - > host_no ;
int id = DONE_SC - > device - > id & 0xf ;
int lun = DONE_SC - > device - > lun & 0x7 ;
# endif
Scsi_Cmnd * ptr = DONE_SC ;
DONE_SC = NULL ;
/* turn led off, when no commands are in the driver */
HOSTDATA ( shpnt ) - > commands - - ;
if ( ! HOSTDATA ( shpnt ) - > commands )
SETPORT ( PORTA , 0 ) ; /* turn led off */
if ( ptr - > scsi_done ! = reset_done ) {
kfree ( ptr - > host_scribble ) ;
ptr - > host_scribble = NULL ;
}
DO_UNLOCK ( flags ) ;
DPRINTK ( debug_done , DEBUG_LEAD " calling scsi_done(%p) \n " , hostno , id , lun , ptr ) ;
ptr - > scsi_done ( ptr ) ;
DPRINTK ( debug_done , DEBUG_LEAD " scsi_done(%p) returned \n " , hostno , id , lun , ptr ) ;
DO_LOCK ( flags ) ;
}
DONE_SC = NULL ;
# if defined(AHA152X_STAT)
} else {
HOSTDATA ( shpnt ) - > busfree_without_done_command + + ;
# endif
}
if ( ISSUE_SC )
CURRENT_SC = remove_first_SC ( & ISSUE_SC ) ;
DO_UNLOCK ( flags ) ;
if ( CURRENT_SC ) {
# if defined(AHA152X_STAT)
action + + ;
# endif
CURRENT_SC - > SCp . phase | = selecting ;
DPRINTK ( debug_selection , DEBUG_LEAD " selecting target \n " , CMDINFO ( CURRENT_SC ) ) ;
/* clear selection timeout */
SETPORT ( SSTAT1 , SELTO ) ;
SETPORT ( SCSIID , ( shpnt - > this_id < < OID_ ) | CURRENT_SC - > device - > id ) ;
SETPORT ( SXFRCTL1 , ( PARITY ? ENSPCHK : 0 ) | ENSTIMER ) ;
SETPORT ( SCSISEQ , ENSELO | ENAUTOATNO | ( DISCONNECTED_SC ? ENRESELI : 0 ) ) ;
} else {
# if defined(AHA152X_STAT)
HOSTDATA ( shpnt ) - > busfree_without_new_command + + ;
# endif
SETPORT ( SCSISEQ , DISCONNECTED_SC ? ENRESELI : 0 ) ;
}
# if defined(AHA152X_STAT)
if ( ! action )
HOSTDATA ( shpnt ) - > busfree_without_any_action + + ;
# endif
}
/*
* Selection done ( OUT )
* - queue IDENTIFY message and SDTR to selected target for message out
* ( ATN asserted automagically via ENAUTOATNO in busfree ( ) )
*/
static void seldo_run ( struct Scsi_Host * shpnt )
{
SETPORT ( SCSISIG , 0 ) ;
SETPORT ( SSTAT1 , CLRBUSFREE ) ;
SETPORT ( SSTAT1 , CLRPHASECHG ) ;
CURRENT_SC - > SCp . phase & = ~ ( selecting | not_issued ) ;
SETPORT ( SCSISEQ , 0 ) ;
if ( TESTLO ( SSTAT0 , SELDO ) ) {
printk ( ERR_LEAD " aha152x: passing bus free condition \n " , CMDINFO ( CURRENT_SC ) ) ;
done ( shpnt , DID_NO_CONNECT < < 16 ) ;
return ;
}
SETPORT ( SSTAT0 , CLRSELDO ) ;
ADDMSGO ( IDENTIFY ( RECONNECT , CURRENT_SC - > device - > lun ) ) ;
if ( CURRENT_SC - > SCp . phase & aborting ) {
ADDMSGO ( ABORT ) ;
} else if ( CURRENT_SC - > SCp . phase & resetting ) {
ADDMSGO ( BUS_DEVICE_RESET ) ;
} else if ( SYNCNEG = = 0 & & SYNCHRONOUS ) {
CURRENT_SC - > SCp . phase | = syncneg ;
2006-02-07 17:54:46 +03:00
MSGOLEN + = spi_populate_sync_msg ( & MSGO ( MSGOLEN ) , 50 , 8 ) ;
2005-04-17 02:20:36 +04:00
SYNCNEG = 1 ; /* negotiation in progress */
}
SETRATE ( SYNCRATE ) ;
}
/*
* Selection timeout
* - return command to mid - level with failure cause
*
*/
static void selto_run ( struct Scsi_Host * shpnt )
{
SETPORT ( SCSISEQ , 0 ) ;
SETPORT ( SSTAT1 , CLRSELTIMO ) ;
DPRINTK ( debug_selection , DEBUG_LEAD " selection timeout \n " , CMDINFO ( CURRENT_SC ) ) ;
if ( ! CURRENT_SC ) {
DPRINTK ( debug_selection , DEBUG_LEAD " !CURRENT_SC \n " , CMDINFO ( CURRENT_SC ) ) ;
return ;
}
CURRENT_SC - > SCp . phase & = ~ selecting ;
if ( CURRENT_SC - > SCp . phase & aborted ) {
DPRINTK ( debug_selection , DEBUG_LEAD " aborted \n " , CMDINFO ( CURRENT_SC ) ) ;
done ( shpnt , DID_ABORT < < 16 ) ;
} else if ( TESTLO ( SSTAT0 , SELINGO ) ) {
DPRINTK ( debug_selection , DEBUG_LEAD " arbitration not won \n " , CMDINFO ( CURRENT_SC ) ) ;
done ( shpnt , DID_BUS_BUSY < < 16 ) ;
} else {
/* ARBITRATION won, but SELECTION failed */
DPRINTK ( debug_selection , DEBUG_LEAD " selection failed \n " , CMDINFO ( CURRENT_SC ) ) ;
done ( shpnt , DID_NO_CONNECT < < 16 ) ;
}
}
/*
* Selection in done
* - put current command back to issue queue
* ( reconnection of a disconnected nexus instead
* of successful selection out )
*
*/
static void seldi_run ( struct Scsi_Host * shpnt )
{
int selid ;
int target ;
unsigned long flags ;
SETPORT ( SCSISIG , 0 ) ;
SETPORT ( SSTAT0 , CLRSELDI ) ;
SETPORT ( SSTAT1 , CLRBUSFREE ) ;
SETPORT ( SSTAT1 , CLRPHASECHG ) ;
if ( CURRENT_SC ) {
if ( ! ( CURRENT_SC - > SCp . phase & not_issued ) )
printk ( ERR_LEAD " command should not have been issued yet \n " , CMDINFO ( CURRENT_SC ) ) ;
DPRINTK ( debug_selection , ERR_LEAD " command requeued - reselection \n " , CMDINFO ( CURRENT_SC ) ) ;
DO_LOCK ( flags ) ;
append_SC ( & ISSUE_SC , CURRENT_SC ) ;
DO_UNLOCK ( flags ) ;
CURRENT_SC = NULL ;
}
if ( ! DISCONNECTED_SC ) {
DPRINTK ( debug_selection , DEBUG_LEAD " unexpected SELDI " , CMDINFO ( CURRENT_SC ) ) ;
return ;
}
RECONN_TARGET = - 1 ;
selid = GETPORT ( SELID ) & ~ ( 1 < < shpnt - > this_id ) ;
if ( selid = = 0 ) {
printk ( " aha152x%d: target id unknown (%02x) \n " , HOSTNO , selid ) ;
return ;
}
for ( target = 7 ; ! ( selid & ( 1 < < target ) ) ; target - - )
;
if ( selid & ~ ( 1 < < target ) ) {
printk ( " aha152x%d: multiple targets reconnected (%02x) \n " ,
HOSTNO , selid ) ;
}
SETPORT ( SCSIID , ( shpnt - > this_id < < OID_ ) | target ) ;
SETPORT ( SCSISEQ , 0 ) ;
SETRATE ( HOSTDATA ( shpnt ) - > syncrate [ target ] ) ;
RECONN_TARGET = target ;
DPRINTK ( debug_selection , DEBUG_LEAD " target %d reselected (%02x). \n " , CMDINFO ( CURRENT_SC ) , target , selid ) ;
}
/*
* message in phase
* - handle initial message after reconnection to identify
* reconnecting nexus
* - queue command on DISCONNECTED_SC on DISCONNECT message
* - set completed flag on COMMAND COMPLETE
* ( other completition code moved to busfree_run )
* - handle response to SDTR
* - clear synchronous transfer agreements on BUS RESET
*
* FIXME : what about SAVE POINTERS , RESTORE POINTERS ?
*
*/
static void msgi_run ( struct Scsi_Host * shpnt )
{
for ( ; ; ) {
int sstat1 = GETPORT ( SSTAT1 ) ;
if ( sstat1 & ( PHASECHG | PHASEMIS | BUSFREE ) | | ! ( sstat1 & REQINIT ) )
return ;
if ( TESTLO ( SSTAT0 , SPIORDY ) ) {
DPRINTK ( debug_msgi , DEBUG_LEAD " !SPIORDY \n " , CMDINFO ( CURRENT_SC ) ) ;
return ;
}
ADDMSGI ( GETPORT ( SCSIDAT ) ) ;
# if defined(AHA152X_DEBUG)
if ( HOSTDATA ( shpnt ) - > debug & debug_msgi ) {
printk ( INFO_LEAD " inbound message %02x " , CMDINFO ( CURRENT_SC ) , MSGI ( 0 ) ) ;
2005-12-16 00:22:01 +03:00
spi_print_msg ( & MSGI ( 0 ) ) ;
2005-04-17 02:20:36 +04:00
printk ( " \n " ) ;
}
# endif
if ( ! CURRENT_SC ) {
if ( LASTSTATE ! = seldi ) {
printk ( KERN_ERR " aha152x%d: message in w/o current command not after reselection \n " , HOSTNO ) ;
}
/*
* Handle reselection
*/
if ( ! ( MSGI ( 0 ) & IDENTIFY_BASE ) ) {
printk ( KERN_ERR " aha152x%d: target didn't identify after reselection \n " , HOSTNO ) ;
continue ;
}
CURRENT_SC = remove_lun_SC ( & DISCONNECTED_SC , RECONN_TARGET , MSGI ( 0 ) & 0x3f ) ;
if ( ! CURRENT_SC ) {
show_queues ( shpnt ) ;
printk ( KERN_ERR " aha152x%d: no disconnected command for target %d/%d \n " , HOSTNO , RECONN_TARGET , MSGI ( 0 ) & 0x3f ) ;
continue ;
}
DPRINTK ( debug_msgi , DEBUG_LEAD " target reconnected \n " , CMDINFO ( CURRENT_SC ) ) ;
CURRENT_SC - > SCp . Message = MSGI ( 0 ) ;
CURRENT_SC - > SCp . phase & = ~ disconnected ;
MSGILEN = 0 ;
/* next message if any */
continue ;
}
CURRENT_SC - > SCp . Message = MSGI ( 0 ) ;
switch ( MSGI ( 0 ) ) {
case DISCONNECT :
if ( ! RECONNECT )
printk ( WARN_LEAD " target was not allowed to disconnect \n " , CMDINFO ( CURRENT_SC ) ) ;
CURRENT_SC - > SCp . phase | = disconnected ;
break ;
case COMMAND_COMPLETE :
if ( CURRENT_SC - > SCp . phase & completed )
DPRINTK ( debug_msgi , DEBUG_LEAD " again COMMAND COMPLETE \n " , CMDINFO ( CURRENT_SC ) ) ;
CURRENT_SC - > SCp . phase | = completed ;
break ;
case MESSAGE_REJECT :
if ( SYNCNEG = = 1 ) {
printk ( INFO_LEAD " Synchronous Data Transfer Request was rejected \n " , CMDINFO ( CURRENT_SC ) ) ;
SYNCNEG = 2 ; /* negotiation completed */
} else
printk ( INFO_LEAD " inbound message (MESSAGE REJECT) \n " , CMDINFO ( CURRENT_SC ) ) ;
break ;
case SAVE_POINTERS :
break ;
case RESTORE_POINTERS :
break ;
case EXTENDED_MESSAGE :
if ( MSGILEN < 2 | | MSGILEN < MSGI ( 1 ) + 2 ) {
/* not yet completed */
continue ;
}
switch ( MSGI ( 2 ) ) {
case EXTENDED_SDTR :
{
long ticks ;
if ( MSGI ( 1 ) ! = 3 ) {
printk ( ERR_LEAD " SDTR message length!=3 \n " , CMDINFO ( CURRENT_SC ) ) ;
break ;
}
if ( ! HOSTDATA ( shpnt ) - > synchronous )
break ;
printk ( INFO_LEAD , CMDINFO ( CURRENT_SC ) ) ;
2005-12-16 00:22:01 +03:00
spi_print_msg ( & MSGI ( 0 ) ) ;
2005-04-17 02:20:36 +04:00
printk ( " \n " ) ;
ticks = ( MSGI ( 3 ) * 4 + 49 ) / 50 ;
if ( syncneg ) {
/* negotiation in progress */
if ( ticks > 9 | | MSGI ( 4 ) < 1 | | MSGI ( 4 ) > 8 ) {
ADDMSGO ( MESSAGE_REJECT ) ;
printk ( INFO_LEAD " received Synchronous Data Transfer Request invalid - rejected \n " , CMDINFO ( CURRENT_SC ) ) ;
break ;
}
SYNCRATE | = ( ( ticks - 2 ) < < 4 ) + MSGI ( 4 ) ;
} else if ( ticks < = 9 & & MSGI ( 4 ) > = 1 ) {
ADDMSGO ( EXTENDED_MESSAGE ) ;
ADDMSGO ( 3 ) ;
ADDMSGO ( EXTENDED_SDTR ) ;
if ( ticks < 4 ) {
ticks = 4 ;
ADDMSGO ( 50 ) ;
} else
ADDMSGO ( MSGI ( 3 ) ) ;
if ( MSGI ( 4 ) > 8 )
MSGI ( 4 ) = 8 ;
ADDMSGO ( MSGI ( 4 ) ) ;
SYNCRATE | = ( ( ticks - 2 ) < < 4 ) + MSGI ( 4 ) ;
} else {
/* requested SDTR is too slow, do it asynchronously */
printk ( INFO_LEAD " Synchronous Data Transfer Request too slow - Rejecting \n " , CMDINFO ( CURRENT_SC ) ) ;
ADDMSGO ( MESSAGE_REJECT ) ;
}
SYNCNEG = 2 ; /* negotiation completed */
SETRATE ( SYNCRATE ) ;
}
break ;
case BUS_DEVICE_RESET :
{
int i ;
for ( i = 0 ; i < 8 ; i + + ) {
HOSTDATA ( shpnt ) - > syncrate [ i ] = 0 ;
HOSTDATA ( shpnt ) - > syncneg [ i ] = 0 ;
}
}
break ;
case EXTENDED_MODIFY_DATA_POINTER :
case EXTENDED_EXTENDED_IDENTIFY :
case EXTENDED_WDTR :
default :
ADDMSGO ( MESSAGE_REJECT ) ;
break ;
}
break ;
}
MSGILEN = 0 ;
}
}
static void msgi_end ( struct Scsi_Host * shpnt )
{
if ( MSGILEN > 0 )
printk ( WARN_LEAD " target left before message completed (%d) \n " , CMDINFO ( CURRENT_SC ) , MSGILEN ) ;
if ( MSGOLEN > 0 & & ! ( GETPORT ( SSTAT1 ) & BUSFREE ) ) {
DPRINTK ( debug_msgi , DEBUG_LEAD " msgo pending \n " , CMDINFO ( CURRENT_SC ) ) ;
SETPORT ( SCSISIG , P_MSGI | SIG_ATNO ) ;
}
}
/*
* message out phase
*
*/
static void msgo_init ( struct Scsi_Host * shpnt )
{
if ( MSGOLEN = = 0 ) {
if ( ( CURRENT_SC - > SCp . phase & syncneg ) & & SYNCNEG = = 2 & & SYNCRATE = = 0 ) {
ADDMSGO ( IDENTIFY ( RECONNECT , CURRENT_SC - > device - > lun ) ) ;
} else {
printk ( INFO_LEAD " unexpected MESSAGE OUT phase; rejecting \n " , CMDINFO ( CURRENT_SC ) ) ;
ADDMSGO ( MESSAGE_REJECT ) ;
}
}
# if defined(AHA152X_DEBUG)
if ( HOSTDATA ( shpnt ) - > debug & debug_msgo ) {
int i ;
printk ( DEBUG_LEAD " messages( " , CMDINFO ( CURRENT_SC ) ) ;
2005-12-16 00:22:01 +03:00
for ( i = 0 ; i < MSGOLEN ; i + = spi_print_msg ( & MSGO ( i ) ) , printk ( " " ) )
2005-04-17 02:20:36 +04:00
;
printk ( " ) \n " ) ;
}
# endif
}
/*
* message out phase
*
*/
static void msgo_run ( struct Scsi_Host * shpnt )
{
if ( MSGO_I = = MSGOLEN )
DPRINTK ( debug_msgo , DEBUG_LEAD " messages all sent (%d/%d) \n " , CMDINFO ( CURRENT_SC ) , MSGO_I , MSGOLEN ) ;
while ( MSGO_I < MSGOLEN ) {
DPRINTK ( debug_msgo , DEBUG_LEAD " message byte %02x (%d/%d) \n " , CMDINFO ( CURRENT_SC ) , MSGO ( MSGO_I ) , MSGO_I , MSGOLEN ) ;
if ( TESTLO ( SSTAT0 , SPIORDY ) ) {
DPRINTK ( debug_msgo , DEBUG_LEAD " !SPIORDY \n " , CMDINFO ( CURRENT_SC ) ) ;
return ;
}
if ( MSGO_I = = MSGOLEN - 1 ) {
/* Leave MESSAGE OUT after transfer */
SETPORT ( SSTAT1 , CLRATNO ) ;
}
if ( MSGO ( MSGO_I ) & IDENTIFY_BASE )
CURRENT_SC - > SCp . phase | = identified ;
if ( MSGO ( MSGO_I ) = = ABORT )
CURRENT_SC - > SCp . phase | = aborted ;
if ( MSGO ( MSGO_I ) = = BUS_DEVICE_RESET )
CURRENT_SC - > SCp . phase | = resetted ;
SETPORT ( SCSIDAT , MSGO ( MSGO_I + + ) ) ;
}
}
static void msgo_end ( struct Scsi_Host * shpnt )
{
if ( MSGO_I < MSGOLEN ) {
printk ( ERR_LEAD " message sent incompletely (%d/%d) \n " , CMDINFO ( CURRENT_SC ) , MSGO_I , MSGOLEN ) ;
if ( SYNCNEG = = 1 ) {
printk ( INFO_LEAD " Synchronous Data Transfer Request was rejected \n " , CMDINFO ( CURRENT_SC ) ) ;
SYNCNEG = 2 ;
}
}
MSGO_I = 0 ;
MSGOLEN = 0 ;
}
/*
* command phase
*
*/
static void cmd_init ( struct Scsi_Host * shpnt )
{
if ( CURRENT_SC - > SCp . sent_command ) {
printk ( ERR_LEAD " command already sent \n " , CMDINFO ( CURRENT_SC ) ) ;
done ( shpnt , DID_ERROR < < 16 ) ;
return ;
}
# if defined(AHA152X_DEBUG)
if ( HOSTDATA ( shpnt ) - > debug & debug_cmd ) {
printk ( DEBUG_LEAD " cmd_init: " , CMDINFO ( CURRENT_SC ) ) ;
2005-04-03 23:53:59 +04:00
__scsi_print_command ( CURRENT_SC - > cmnd ) ;
2005-04-17 02:20:36 +04:00
}
# endif
CMD_I = 0 ;
}
/*
* command phase
*
*/
static void cmd_run ( struct Scsi_Host * shpnt )
{
if ( CMD_I = = CURRENT_SC - > cmd_len ) {
DPRINTK ( debug_cmd , DEBUG_LEAD " command already completely sent (%d/%d) " , CMDINFO ( CURRENT_SC ) , CMD_I , CURRENT_SC - > cmd_len ) ;
disp_ports ( shpnt ) ;
}
while ( CMD_I < CURRENT_SC - > cmd_len ) {
DPRINTK ( debug_cmd , DEBUG_LEAD " command byte %02x (%d/%d) \n " , CMDINFO ( CURRENT_SC ) , CURRENT_SC - > cmnd [ CMD_I ] , CMD_I , CURRENT_SC - > cmd_len ) ;
if ( TESTLO ( SSTAT0 , SPIORDY ) ) {
DPRINTK ( debug_cmd , DEBUG_LEAD " !SPIORDY \n " , CMDINFO ( CURRENT_SC ) ) ;
return ;
}
SETPORT ( SCSIDAT , CURRENT_SC - > cmnd [ CMD_I + + ] ) ;
}
}
static void cmd_end ( struct Scsi_Host * shpnt )
{
if ( CMD_I < CURRENT_SC - > cmd_len )
printk ( ERR_LEAD " command sent incompletely (%d/%d) \n " , CMDINFO ( CURRENT_SC ) , CMD_I , CURRENT_SC - > cmd_len ) ;
else
CURRENT_SC - > SCp . sent_command + + ;
}
/*
* status phase
*
*/
static void status_run ( struct Scsi_Host * shpnt )
{
if ( TESTLO ( SSTAT0 , SPIORDY ) ) {
DPRINTK ( debug_status , DEBUG_LEAD " !SPIORDY \n " , CMDINFO ( CURRENT_SC ) ) ;
return ;
}
CURRENT_SC - > SCp . Status = GETPORT ( SCSIDAT ) ;
# if defined(AHA152X_DEBUG)
if ( HOSTDATA ( shpnt ) - > debug & debug_status ) {
printk ( DEBUG_LEAD " inbound status %02x " , CMDINFO ( CURRENT_SC ) , CURRENT_SC - > SCp . Status ) ;
2005-04-03 23:53:59 +04:00
scsi_print_status ( CURRENT_SC - > SCp . Status ) ;
2005-04-17 02:20:36 +04:00
printk ( " \n " ) ;
}
# endif
}
/*
* data in phase
*
*/
static void datai_init ( struct Scsi_Host * shpnt )
{
SETPORT ( DMACNTRL0 , RSTFIFO ) ;
SETPORT ( DMACNTRL0 , RSTFIFO | ENDMA ) ;
SETPORT ( SXFRCTL0 , CH1 | CLRSTCNT ) ;
SETPORT ( SXFRCTL0 , CH1 | SCSIEN | DMAEN ) ;
SETPORT ( SIMODE0 , 0 ) ;
SETPORT ( SIMODE1 , ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE ) ;
DATA_LEN = 0 ;
DPRINTK ( debug_datai ,
DEBUG_LEAD " datai_init: request_bufflen=%d resid=%d \n " ,
CMDINFO ( CURRENT_SC ) , CURRENT_SC - > request_bufflen , CURRENT_SC - > resid ) ;
}
static void datai_run ( struct Scsi_Host * shpnt )
{
unsigned long the_time ;
int fifodata , data_count ;
/*
* loop while the phase persists or the fifos are not empty
*
*/
while ( TESTLO ( DMASTAT , INTSTAT ) | | TESTLO ( DMASTAT , DFIFOEMP ) | | TESTLO ( SSTAT2 , SEMPTY ) ) {
/* FIXME: maybe this should be done by setting up
* STCNT to trigger ENSWRAP interrupt , instead of
* polling for DFIFOFULL
*/
the_time = jiffies + 100 * HZ ;
while ( TESTLO ( DMASTAT , DFIFOFULL | INTSTAT ) & & time_before ( jiffies , the_time ) )
barrier ( ) ;
if ( TESTLO ( DMASTAT , DFIFOFULL | INTSTAT ) ) {
printk ( ERR_LEAD " datai timeout " , CMDINFO ( CURRENT_SC ) ) ;
disp_ports ( shpnt ) ;
break ;
}
if ( TESTHI ( DMASTAT , DFIFOFULL ) ) {
fifodata = 128 ;
} else {
the_time = jiffies + 100 * HZ ;
while ( TESTLO ( SSTAT2 , SEMPTY ) & & time_before ( jiffies , the_time ) )
barrier ( ) ;
if ( TESTLO ( SSTAT2 , SEMPTY ) ) {
printk ( ERR_LEAD " datai sempty timeout " , CMDINFO ( CURRENT_SC ) ) ;
disp_ports ( shpnt ) ;
break ;
}
fifodata = GETPORT ( FIFOSTAT ) ;
}
if ( CURRENT_SC - > SCp . this_residual > 0 ) {
while ( fifodata > 0 & & CURRENT_SC - > SCp . this_residual > 0 ) {
data_count = fifodata > CURRENT_SC - > SCp . this_residual ?
CURRENT_SC - > SCp . this_residual :
fifodata ;
fifodata - = data_count ;
if ( data_count & 1 ) {
DPRINTK ( debug_datai , DEBUG_LEAD " 8bit \n " , CMDINFO ( CURRENT_SC ) ) ;
SETPORT ( DMACNTRL0 , ENDMA | _8BIT ) ;
* CURRENT_SC - > SCp . ptr + + = GETPORT ( DATAPORT ) ;
CURRENT_SC - > SCp . this_residual - - ;
DATA_LEN + + ;
SETPORT ( DMACNTRL0 , ENDMA ) ;
}
if ( data_count > 1 ) {
DPRINTK ( debug_datai , DEBUG_LEAD " 16bit(%d) \n " , CMDINFO ( CURRENT_SC ) , data_count ) ;
data_count > > = 1 ;
insw ( DATAPORT , CURRENT_SC - > SCp . ptr , data_count ) ;
CURRENT_SC - > SCp . ptr + = 2 * data_count ;
CURRENT_SC - > SCp . this_residual - = 2 * data_count ;
DATA_LEN + = 2 * data_count ;
}
if ( CURRENT_SC - > SCp . this_residual = = 0 & & CURRENT_SC - > SCp . buffers_residual > 0 ) {
/* advance to next buffer */
CURRENT_SC - > SCp . buffers_residual - - ;
CURRENT_SC - > SCp . buffer + + ;
CURRENT_SC - > SCp . ptr = SG_ADDRESS ( CURRENT_SC - > SCp . buffer ) ;
CURRENT_SC - > SCp . this_residual = CURRENT_SC - > SCp . buffer - > length ;
}
}
} else if ( fifodata > 0 ) {
printk ( ERR_LEAD " no buffers left for %d(%d) bytes (data overrun!?) \n " , CMDINFO ( CURRENT_SC ) , fifodata , GETPORT ( FIFOSTAT ) ) ;
SETPORT ( DMACNTRL0 , ENDMA | _8BIT ) ;
while ( fifodata > 0 ) {
int data ;
data = GETPORT ( DATAPORT ) ;
DPRINTK ( debug_datai , DEBUG_LEAD " data=%02x \n " , CMDINFO ( CURRENT_SC ) , data ) ;
fifodata - - ;
DATA_LEN + + ;
}
SETPORT ( DMACNTRL0 , ENDMA | _8BIT ) ;
}
}
if ( TESTLO ( DMASTAT , INTSTAT ) | |
TESTLO ( DMASTAT , DFIFOEMP ) | |
TESTLO ( SSTAT2 , SEMPTY ) | |
GETPORT ( FIFOSTAT ) > 0 ) {
/*
* something went wrong , if there ' s something left in the fifos
* or the phase didn ' t change
*/
printk ( ERR_LEAD " fifos should be empty and phase should have changed \n " , CMDINFO ( CURRENT_SC ) ) ;
disp_ports ( shpnt ) ;
}
if ( DATA_LEN ! = GETSTCNT ( ) ) {
printk ( ERR_LEAD
" manual transfer count differs from automatic (count=%d;stcnt=%d;diff=%d;fifostat=%d) " ,
CMDINFO ( CURRENT_SC ) , DATA_LEN , GETSTCNT ( ) , GETSTCNT ( ) - DATA_LEN , GETPORT ( FIFOSTAT ) ) ;
disp_ports ( shpnt ) ;
mdelay ( 10000 ) ;
}
}
static void datai_end ( struct Scsi_Host * shpnt )
{
CURRENT_SC - > resid - = GETSTCNT ( ) ;
DPRINTK ( debug_datai ,
DEBUG_LEAD " datai_end: request_bufflen=%d resid=%d stcnt=%d \n " ,
CMDINFO ( CURRENT_SC ) , CURRENT_SC - > request_bufflen , CURRENT_SC - > resid , GETSTCNT ( ) ) ;
SETPORT ( SXFRCTL0 , CH1 | CLRSTCNT ) ;
SETPORT ( DMACNTRL0 , 0 ) ;
}
/*
* data out phase
*
*/
static void datao_init ( struct Scsi_Host * shpnt )
{
SETPORT ( DMACNTRL0 , WRITE_READ | RSTFIFO ) ;
SETPORT ( DMACNTRL0 , WRITE_READ | ENDMA ) ;
SETPORT ( SXFRCTL0 , CH1 | CLRSTCNT ) ;
SETPORT ( SXFRCTL0 , CH1 | SCSIEN | DMAEN ) ;
SETPORT ( SIMODE0 , 0 ) ;
SETPORT ( SIMODE1 , ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE ) ;
DATA_LEN = CURRENT_SC - > resid ;
DPRINTK ( debug_datao ,
DEBUG_LEAD " datao_init: request_bufflen=%d; resid=%d \n " ,
CMDINFO ( CURRENT_SC ) , CURRENT_SC - > request_bufflen , CURRENT_SC - > resid ) ;
}
static void datao_run ( struct Scsi_Host * shpnt )
{
unsigned long the_time ;
int data_count ;
/* until phase changes or all data sent */
while ( TESTLO ( DMASTAT , INTSTAT ) & & CURRENT_SC - > SCp . this_residual > 0 ) {
data_count = 128 ;
if ( data_count > CURRENT_SC - > SCp . this_residual )
data_count = CURRENT_SC - > SCp . this_residual ;
if ( TESTLO ( DMASTAT , DFIFOEMP ) ) {
printk ( ERR_LEAD " datao fifo not empty (%d) " , CMDINFO ( CURRENT_SC ) , GETPORT ( FIFOSTAT ) ) ;
disp_ports ( shpnt ) ;
break ;
}
if ( data_count & 1 ) {
SETPORT ( DMACNTRL0 , WRITE_READ | ENDMA | _8BIT ) ;
SETPORT ( DATAPORT , * CURRENT_SC - > SCp . ptr + + ) ;
CURRENT_SC - > SCp . this_residual - - ;
CURRENT_SC - > resid - - ;
SETPORT ( DMACNTRL0 , WRITE_READ | ENDMA ) ;
}
if ( data_count > 1 ) {
data_count > > = 1 ;
outsw ( DATAPORT , CURRENT_SC - > SCp . ptr , data_count ) ;
CURRENT_SC - > SCp . ptr + = 2 * data_count ;
CURRENT_SC - > SCp . this_residual - = 2 * data_count ;
CURRENT_SC - > resid - = 2 * data_count ;
}
if ( CURRENT_SC - > SCp . this_residual = = 0 & & CURRENT_SC - > SCp . buffers_residual > 0 ) {
/* advance to next buffer */
CURRENT_SC - > SCp . buffers_residual - - ;
CURRENT_SC - > SCp . buffer + + ;
CURRENT_SC - > SCp . ptr = SG_ADDRESS ( CURRENT_SC - > SCp . buffer ) ;
CURRENT_SC - > SCp . this_residual = CURRENT_SC - > SCp . buffer - > length ;
}
the_time = jiffies + 100 * HZ ;
while ( TESTLO ( DMASTAT , DFIFOEMP | INTSTAT ) & & time_before ( jiffies , the_time ) )
barrier ( ) ;
if ( TESTLO ( DMASTAT , DFIFOEMP | INTSTAT ) ) {
printk ( ERR_LEAD " dataout timeout " , CMDINFO ( CURRENT_SC ) ) ;
disp_ports ( shpnt ) ;
break ;
}
}
}
static void datao_end ( struct Scsi_Host * shpnt )
{
if ( TESTLO ( DMASTAT , DFIFOEMP ) ) {
int data_count = ( DATA_LEN - CURRENT_SC - > resid ) - GETSTCNT ( ) ;
DPRINTK ( debug_datao , DEBUG_LEAD " datao: %d bytes to resend (%d written, %d transferred) \n " ,
CMDINFO ( CURRENT_SC ) ,
data_count ,
DATA_LEN - CURRENT_SC - > resid ,
GETSTCNT ( ) ) ;
CURRENT_SC - > resid + = data_count ;
if ( CURRENT_SC - > use_sg ) {
data_count - = CURRENT_SC - > SCp . ptr - SG_ADDRESS ( CURRENT_SC - > SCp . buffer ) ;
while ( data_count > 0 ) {
CURRENT_SC - > SCp . buffer - - ;
CURRENT_SC - > SCp . buffers_residual + + ;
data_count - = CURRENT_SC - > SCp . buffer - > length ;
}
CURRENT_SC - > SCp . ptr = SG_ADDRESS ( CURRENT_SC - > SCp . buffer ) - data_count ;
CURRENT_SC - > SCp . this_residual = CURRENT_SC - > SCp . buffer - > length + data_count ;
} else {
CURRENT_SC - > SCp . ptr - = data_count ;
CURRENT_SC - > SCp . this_residual + = data_count ;
}
}
DPRINTK ( debug_datao , DEBUG_LEAD " datao_end: request_bufflen=%d; resid=%d; stcnt=%d \n " ,
CMDINFO ( CURRENT_SC ) ,
CURRENT_SC - > request_bufflen ,
CURRENT_SC - > resid ,
GETSTCNT ( ) ) ;
SETPORT ( SXFRCTL0 , CH1 | CLRCH1 | CLRSTCNT ) ;
SETPORT ( SXFRCTL0 , CH1 ) ;
SETPORT ( DMACNTRL0 , 0 ) ;
}
/*
* figure out what state we ' re in
*
*/
static int update_state ( struct Scsi_Host * shpnt )
{
int dataphase = 0 ;
unsigned int stat0 = GETPORT ( SSTAT0 ) ;
unsigned int stat1 = GETPORT ( SSTAT1 ) ;
PREVSTATE = STATE ;
STATE = unknown ;
if ( stat1 & SCSIRSTI ) {
STATE = rsti ;
SETPORT ( SCSISEQ , 0 ) ;
SETPORT ( SSTAT1 , SCSIRSTI ) ;
} else if ( stat0 & SELDI & & PREVSTATE = = busfree ) {
STATE = seldi ;
} else if ( stat0 & SELDO & & CURRENT_SC & & ( CURRENT_SC - > SCp . phase & selecting ) ) {
STATE = seldo ;
} else if ( stat1 & SELTO ) {
STATE = selto ;
} else if ( stat1 & BUSFREE ) {
STATE = busfree ;
SETPORT ( SSTAT1 , BUSFREE ) ;
} else if ( stat1 & SCSIPERR ) {
STATE = parerr ;
SETPORT ( SSTAT1 , SCSIPERR ) ;
} else if ( stat1 & REQINIT ) {
switch ( GETPORT ( SCSISIG ) & P_MASK ) {
case P_MSGI : STATE = msgi ; break ;
case P_MSGO : STATE = msgo ; break ;
case P_DATAO : STATE = datao ; break ;
case P_DATAI : STATE = datai ; break ;
case P_STATUS : STATE = status ; break ;
case P_CMD : STATE = cmd ; break ;
}
dataphase = 1 ;
}
if ( ( stat0 & SELDI ) & & STATE ! = seldi & & ! dataphase ) {
printk ( INFO_LEAD " reselection missed? " , CMDINFO ( CURRENT_SC ) ) ;
disp_ports ( shpnt ) ;
}
if ( STATE ! = PREVSTATE ) {
LASTSTATE = PREVSTATE ;
}
return dataphase ;
}
/*
* handle parity error
*
* FIXME : in which phase ?
*
*/
static void parerr_run ( struct Scsi_Host * shpnt )
{
printk ( ERR_LEAD " parity error \n " , CMDINFO ( CURRENT_SC ) ) ;
done ( shpnt , DID_PARITY < < 16 ) ;
}
/*
* handle reset in
*
*/
static void rsti_run ( struct Scsi_Host * shpnt )
{
Scsi_Cmnd * ptr ;
printk ( KERN_NOTICE " aha152x%d: scsi reset in \n " , HOSTNO ) ;
ptr = DISCONNECTED_SC ;
while ( ptr ) {
Scsi_Cmnd * next = SCNEXT ( ptr ) ;
if ( ! ptr - > device - > soft_reset ) {
remove_SC ( & DISCONNECTED_SC , ptr ) ;
kfree ( ptr - > host_scribble ) ;
ptr - > host_scribble = NULL ;
ptr - > result = DID_RESET < < 16 ;
ptr - > scsi_done ( ptr ) ;
}
ptr = next ;
}
if ( CURRENT_SC & & ! CURRENT_SC - > device - > soft_reset )
done ( shpnt , DID_RESET < < 16 ) ;
}
/*
* bottom - half handler
*
*/
static void is_complete ( struct Scsi_Host * shpnt )
{
int dataphase ;
unsigned long flags ;
int pending ;
2006-02-19 02:31:51 +03:00
if ( ! shpnt )
return ;
2005-04-17 02:20:36 +04:00
DO_LOCK ( flags ) ;
2006-02-19 02:31:51 +03:00
if ( HOSTDATA ( shpnt ) - > service = = 0 ) {
DO_UNLOCK ( flags ) ;
return ;
}
HOSTDATA ( shpnt ) - > service = 0 ;
2005-04-17 02:20:36 +04:00
if ( HOSTDATA ( shpnt ) - > in_intr ) {
DO_UNLOCK ( flags ) ;
/* aha152x_error never returns.. */
aha152x_error ( shpnt , " bottom-half already running!? " ) ;
}
HOSTDATA ( shpnt ) - > in_intr + + ;
/*
* loop while there are interrupt conditions pending
*
*/
do {
unsigned long start = jiffies ;
DO_UNLOCK ( flags ) ;
dataphase = update_state ( shpnt ) ;
DPRINTK ( debug_phases , LEAD " start %s %s(%s) \n " , CMDINFO ( CURRENT_SC ) , states [ STATE ] . name , states [ PREVSTATE ] . name , states [ LASTSTATE ] . name ) ;
/*
* end previous state
*
*/
if ( PREVSTATE ! = STATE & & states [ PREVSTATE ] . end )
states [ PREVSTATE ] . end ( shpnt ) ;
/*
* disable SPIO mode if previous phase used it
* and this one doesn ' t
*
*/
if ( states [ PREVSTATE ] . spio & & ! states [ STATE ] . spio ) {
SETPORT ( SXFRCTL0 , CH1 ) ;
SETPORT ( DMACNTRL0 , 0 ) ;
if ( CURRENT_SC )
CURRENT_SC - > SCp . phase & = ~ spiordy ;
}
/*
* accept current dataphase phase
*
*/
if ( dataphase ) {
SETPORT ( SSTAT0 , REQINIT ) ;
SETPORT ( SCSISIG , GETPORT ( SCSISIG ) & P_MASK ) ;
SETPORT ( SSTAT1 , PHASECHG ) ;
}
/*
* enable SPIO mode if previous didn ' t use it
* and this one does
*
*/
if ( ! states [ PREVSTATE ] . spio & & states [ STATE ] . spio ) {
SETPORT ( DMACNTRL0 , 0 ) ;
SETPORT ( SXFRCTL0 , CH1 | SPIOEN ) ;
if ( CURRENT_SC )
CURRENT_SC - > SCp . phase | = spiordy ;
}
/*
* initialize for new state
*
*/
if ( PREVSTATE ! = STATE & & states [ STATE ] . init )
states [ STATE ] . init ( shpnt ) ;
/*
* handle current state
*
*/
if ( states [ STATE ] . run )
states [ STATE ] . run ( shpnt ) ;
else
printk ( ERR_LEAD " unexpected state (%x) \n " , CMDINFO ( CURRENT_SC ) , STATE ) ;
/*
* setup controller to interrupt on
* the next expected condition and
* loop if it ' s already there
*
*/
DO_LOCK ( flags ) ;
pending = setup_expected_interrupts ( shpnt ) ;
# if defined(AHA152X_STAT)
HOSTDATA ( shpnt ) - > count [ STATE ] + + ;
if ( PREVSTATE ! = STATE )
HOSTDATA ( shpnt ) - > count_trans [ STATE ] + + ;
HOSTDATA ( shpnt ) - > time [ STATE ] + = jiffies - start ;
# endif
DPRINTK ( debug_phases , LEAD " end %s %s(%s) \n " , CMDINFO ( CURRENT_SC ) , states [ STATE ] . name , states [ PREVSTATE ] . name , states [ LASTSTATE ] . name ) ;
} while ( pending ) ;
/*
* enable interrupts and leave bottom - half
*
*/
HOSTDATA ( shpnt ) - > in_intr - - ;
SETBITS ( DMACNTRL0 , INTEN ) ;
DO_UNLOCK ( flags ) ;
}
/*
* Dump the current driver status and panic
*/
static void aha152x_error ( struct Scsi_Host * shpnt , char * msg )
{
printk ( KERN_EMERG " \n aha152x%d: %s \n " , HOSTNO , msg ) ;
show_queues ( shpnt ) ;
panic ( " aha152x panic \n " ) ;
}
/*
* Display registers of AIC - 6260
*/
static void disp_ports ( struct Scsi_Host * shpnt )
{
# if defined(AHA152X_DEBUG)
int s ;
printk ( " \n %s: %s(%s) " ,
CURRENT_SC ? " busy " : " waiting " ,
states [ STATE ] . name ,
states [ PREVSTATE ] . name ) ;
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 ( " ); " ) ;
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 ( " *invalid* " ) ;
break ;
}
printk ( " ); " ) ;
printk ( " INTSTAT (%s); " , TESTHI ( DMASTAT , INTSTAT ) ? " hi " : " lo " ) ;
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 " ) ;
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 " ) ;
printk ( " ); " ) ;
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 " ) ;
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 " ) ;
printk ( " ); " ) ;
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 " ) ;
printk ( " ); " ) ;
printk ( " SIGNAL( " ) ;
s = GETPORT ( SCSISIG ) ;
if ( s & SIG_ATNI )
printk ( " ATNI " ) ;
if ( s & SIG_SELI )
printk ( " SELI " ) ;
if ( s & SIG_BSYI )
printk ( " BSYI " ) ;
if ( s & SIG_REQI )
printk ( " REQI " ) ;
if ( s & SIG_ACKI )
printk ( " ACKI " ) ;
printk ( " ); " ) ;
printk ( " SELID (%02x), " , GETPORT ( SELID ) ) ;
printk ( " STCNT (%d), " , GETSTCNT ( ) ) ;
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 ) ) ;
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 " ) ;
printk ( " ); " ) ;
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 ( " ); " ) ;
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 " ) ;
printk ( " ) \n " ) ;
# endif
}
/*
* display enabled interrupts
*/
static void disp_enintr ( struct Scsi_Host * shpnt )
{
int s ;
printk ( KERN_DEBUG " 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 " ) ;
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 " ) ;
printk ( " ) \n " ) ;
}
/*
* Show the command data of a command
*/
static void show_command ( Scsi_Cmnd * ptr )
{
2005-10-25 02:04:36 +04:00
scmd_printk ( KERN_DEBUG , ptr , " %p: cmnd=( " , ptr ) ;
2005-04-17 02:20:36 +04:00
2005-04-03 23:53:59 +04:00
__scsi_print_command ( ptr - > cmnd ) ;
2005-04-17 02:20:36 +04:00
printk ( KERN_DEBUG " ); request_bufflen=%d; resid=%d; phase | " ,
ptr - > request_bufflen , ptr - > resid ) ;
if ( ptr - > SCp . phase & not_issued )
printk ( " not issued| " ) ;
if ( ptr - > SCp . phase & selecting )
printk ( " selecting| " ) ;
if ( ptr - > SCp . phase & identified )
printk ( " identified| " ) ;
if ( ptr - > SCp . phase & disconnected )
printk ( " disconnected| " ) ;
if ( ptr - > SCp . phase & completed )
printk ( " completed| " ) ;
if ( ptr - > SCp . phase & spiordy )
printk ( " spiordy| " ) ;
if ( ptr - > SCp . phase & syncneg )
printk ( " syncneg| " ) ;
if ( ptr - > SCp . phase & aborted )
printk ( " aborted| " ) ;
if ( ptr - > SCp . phase & resetted )
printk ( " resetted| " ) ;
if ( SCDATA ( ptr ) ) {
printk ( " ; next=0x%p \n " , SCNEXT ( ptr ) ) ;
} else {
printk ( " ; next=(host scribble NULL) \n " ) ;
}
}
/*
* Dump the queued data
*/
static void show_queues ( struct Scsi_Host * shpnt )
{
Scsi_Cmnd * ptr ;
unsigned long flags ;
DO_LOCK ( flags ) ;
printk ( KERN_DEBUG " \n queue status: \n issue_SC: \n " ) ;
for ( ptr = ISSUE_SC ; ptr ; ptr = SCNEXT ( ptr ) )
show_command ( ptr ) ;
DO_UNLOCK ( flags ) ;
printk ( KERN_DEBUG " current_SC: \n " ) ;
if ( CURRENT_SC )
show_command ( CURRENT_SC ) ;
else
printk ( KERN_DEBUG " none \n " ) ;
printk ( KERN_DEBUG " disconnected_SC: \n " ) ;
for ( ptr = DISCONNECTED_SC ; ptr ; ptr = SCDATA ( ptr ) ? SCNEXT ( ptr ) : NULL )
show_command ( ptr ) ;
disp_ports ( shpnt ) ;
disp_enintr ( shpnt ) ;
}
# 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 - > device - > id , ptr - > device - > lun ) ;
for ( i = 0 ; i < COMMAND_SIZE ( ptr - > cmnd [ 0 ] ) ; i + + )
SPRINTF ( " 0x%02x " , ptr - > cmnd [ i ] ) ;
SPRINTF ( " ); resid=%d; residual=%d; buffers=%d; phase | " ,
ptr - > resid , ptr - > SCp . this_residual , ptr - > SCp . buffers_residual ) ;
if ( ptr - > SCp . phase & not_issued )
SPRINTF ( " not issued| " ) ;
if ( ptr - > SCp . phase & selecting )
SPRINTF ( " selecting| " ) ;
if ( ptr - > SCp . phase & disconnected )
SPRINTF ( " disconnected| " ) ;
if ( ptr - > SCp . phase & aborted )
SPRINTF ( " aborted| " ) ;
if ( ptr - > SCp . phase & identified )
SPRINTF ( " identified| " ) ;
if ( ptr - > SCp . phase & completed )
SPRINTF ( " completed| " ) ;
if ( ptr - > SCp . phase & spiordy )
SPRINTF ( " spiordy| " ) ;
if ( ptr - > SCp . phase & syncneg )
SPRINTF ( " syncneg| " ) ;
SPRINTF ( " ; next=0x%p \n " , SCNEXT ( ptr ) ) ;
return ( pos - start ) ;
}
static int get_ports ( struct Scsi_Host * shpnt , char * pos )
{
char * start = pos ;
int s ;
SPRINTF ( " \n %s: %s(%s) " , CURRENT_SC ? " on bus " : " waiting " , states [ STATE ] . name , states [ PREVSTATE ] . name ) ;
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 ( " *invalid* " ) ;
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 & SIG_ATNI )
SPRINTF ( " ATNI " ) ;
if ( s & SIG_SELI )
SPRINTF ( " SELI " ) ;
if ( s & SIG_BSYI )
SPRINTF ( " BSYI " ) ;
if ( s & SIG_REQI )
SPRINTF ( " REQI " ) ;
if ( s & SIG_ACKI )
SPRINTF ( " ACKI " ) ;
SPRINTF ( " ); " ) ;
SPRINTF ( " SELID(%02x), " , GETPORT ( SELID ) ) ;
SPRINTF ( " STCNT(%d), " , GETSTCNT ( ) ) ;
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 " ) ;
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 ) ;
}
static int aha152x_set_info ( char * buffer , int length , struct Scsi_Host * shpnt )
{
if ( ! shpnt | | ! buffer | | length < 8 | | strncmp ( " aha152x " , buffer , 8 ) ! = 0 )
return - EINVAL ;
# if defined(AHA152X_DEBUG)
if ( length > 14 & & strncmp ( " debug " , buffer + 8 , 6 ) = = 0 ) {
int debug = HOSTDATA ( shpnt ) - > debug ;
HOSTDATA ( shpnt ) - > debug = simple_strtoul ( buffer + 14 , NULL , 0 ) ;
printk ( KERN_INFO " aha152x%d: debugging options set to 0x%04x (were 0x%04x) \n " , HOSTNO , HOSTDATA ( shpnt ) - > debug , debug ) ;
} else
# endif
# if defined(AHA152X_STAT)
if ( length > 13 & & strncmp ( " reset " , buffer + 8 , 5 ) = = 0 ) {
int i ;
HOSTDATA ( shpnt ) - > total_commands = 0 ;
HOSTDATA ( shpnt ) - > disconnections = 0 ;
HOSTDATA ( shpnt ) - > busfree_without_any_action = 0 ;
HOSTDATA ( shpnt ) - > busfree_without_old_command = 0 ;
HOSTDATA ( shpnt ) - > busfree_without_new_command = 0 ;
HOSTDATA ( shpnt ) - > busfree_without_done_command = 0 ;
HOSTDATA ( shpnt ) - > busfree_with_check_condition = 0 ;
for ( i = idle ; i < maxstate ; i + + ) {
HOSTDATA ( shpnt ) - > count [ i ] = 0 ;
HOSTDATA ( shpnt ) - > count_trans [ i ] = 0 ;
HOSTDATA ( shpnt ) - > time [ i ] = 0 ;
}
printk ( KERN_INFO " aha152x%d: stats reseted. \n " , HOSTNO ) ;
} else
# endif
{
return - EINVAL ;
}
return length ;
}
# undef SPRINTF
# define SPRINTF(args...) \
do { if ( pos < buffer + length ) pos + = sprintf ( pos , # # args ) ; } while ( 0 )
static int aha152x_proc_info ( struct Scsi_Host * shpnt , char * buffer , char * * start ,
off_t offset , int length , int inout )
{
int i ;
char * pos = buffer ;
Scsi_Cmnd * ptr ;
unsigned long flags ;
int thislength ;
DPRINTK ( debug_procinfo ,
KERN_DEBUG " aha152x_proc_info: buffer=%p offset=%ld length=%d hostno=%d inout=%d \n " ,
buffer , offset , length , shpnt - > host_no , inout ) ;
if ( inout )
return aha152x_set_info ( buffer , length , shpnt ) ;
SPRINTF ( AHA152X_REVID " \n " ) ;
SPRINTF ( " ioports 0x%04lx to 0x%04lx \n " ,
shpnt - > io_port , shpnt - > io_port + shpnt - > n_io_port - 1 ) ;
SPRINTF ( " interrupt 0x%02x \n " , shpnt - > irq ) ;
SPRINTF ( " disconnection/reconnection %s \n " ,
RECONNECT ? " enabled " : " disabled " ) ;
SPRINTF ( " parity checking %s \n " ,
PARITY ? " enabled " : " disabled " ) ;
SPRINTF ( " synchronous transfers %s \n " ,
SYNCHRONOUS ? " enabled " : " disabled " ) ;
SPRINTF ( " %d commands currently queued \n " , HOSTDATA ( shpnt ) - > commands ) ;
if ( SYNCHRONOUS ) {
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 ) ;
}
# if defined(AHA152X_DEBUG)
# define PDEBUG(flags,txt) \
if ( HOSTDATA ( shpnt ) - > debug & flags ) SPRINTF ( " (%s) " , txt ) ;
SPRINTF ( " enabled debugging options: " ) ;
PDEBUG ( debug_procinfo , " procinfo " ) ;
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_eh , " eh " ) ;
PDEBUG ( debug_locks , " locks " ) ;
PDEBUG ( debug_phases , " phases " ) ;
SPRINTF ( " \n " ) ;
# endif
SPRINTF ( " \n queue status: \n " ) ;
DO_LOCK ( flags ) ;
if ( ISSUE_SC ) {
SPRINTF ( " not yet issued commands: \n " ) ;
for ( ptr = ISSUE_SC ; ptr ; ptr = SCNEXT ( ptr ) )
pos + = get_command ( pos , ptr ) ;
} else
SPRINTF ( " no not yet issued commands \n " ) ;
DO_UNLOCK ( flags ) ;
if ( CURRENT_SC ) {
SPRINTF ( " current command: \n " ) ;
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 = SCNEXT ( ptr ) )
pos + = get_command ( pos , ptr ) ;
} else
SPRINTF ( " no disconnected commands \n " ) ;
pos + = get_ports ( shpnt , pos ) ;
# if defined(AHA152X_STAT)
SPRINTF ( " statistics: \n "
" total commands: %d \n "
" disconnections: %d \n "
" busfree with check condition: %d \n "
" busfree without old command: %d \n "
" busfree without new command: %d \n "
" busfree without done command: %d \n "
" busfree without any action: %d \n "
" state "
" transitions "
" count "
" time \n " ,
HOSTDATA ( shpnt ) - > total_commands ,
HOSTDATA ( shpnt ) - > disconnections ,
HOSTDATA ( shpnt ) - > busfree_with_check_condition ,
HOSTDATA ( shpnt ) - > busfree_without_old_command ,
HOSTDATA ( shpnt ) - > busfree_without_new_command ,
HOSTDATA ( shpnt ) - > busfree_without_done_command ,
HOSTDATA ( shpnt ) - > busfree_without_any_action ) ;
for ( i = 0 ; i < maxstate ; i + + ) {
SPRINTF ( " %-10s %-12d %-12d %-12ld \n " ,
states [ i ] . name ,
HOSTDATA ( shpnt ) - > count_trans [ i ] ,
HOSTDATA ( shpnt ) - > count [ i ] ,
HOSTDATA ( shpnt ) - > time [ i ] ) ;
}
# endif
DPRINTK ( debug_procinfo , KERN_DEBUG " aha152x_proc_info: pos=%p \n " , pos ) ;
thislength = pos - ( buffer + offset ) ;
DPRINTK ( debug_procinfo , KERN_DEBUG " aha152x_proc_info: length=%d thislength=%d \n " , length , thislength ) ;
if ( thislength < 0 ) {
DPRINTK ( debug_procinfo , KERN_DEBUG " aha152x_proc_info: output too short \n " ) ;
* start = NULL ;
return 0 ;
}
thislength = thislength < length ? thislength : length ;
DPRINTK ( debug_procinfo , KERN_DEBUG " aha152x_proc_info: return %d \n " , thislength ) ;
* start = buffer + offset ;
return thislength < length ? thislength : length ;
}
2005-10-31 20:31:40 +03:00
static struct scsi_host_template aha152x_driver_template = {
2005-04-17 02:20:36 +04:00
. module = THIS_MODULE ,
. name = AHA152X_REVID ,
. proc_name = " aha152x " ,
. proc_info = aha152x_proc_info ,
. queuecommand = aha152x_queue ,
. eh_abort_handler = aha152x_abort ,
. eh_device_reset_handler = aha152x_device_reset ,
. eh_bus_reset_handler = aha152x_bus_reset ,
. eh_host_reset_handler = aha152x_host_reset ,
. bios_param = aha152x_biosparam ,
. can_queue = 1 ,
. this_id = 7 ,
. sg_tablesize = SG_ALL ,
. cmd_per_lun = 1 ,
. use_clustering = DISABLE_CLUSTERING ,
} ;
# if !defined(PCMCIA)
static int setup_count ;
static struct aha152x_setup setup [ 2 ] ;
/* possible i/o addresses for the AIC-6260; default first */
static unsigned short ports [ ] = { 0x340 , 0x140 } ;
# if !defined(SKIP_BIOSTEST)
/* possible locations for the Adaptec BIOS; defaults first */
static unsigned int addresses [ ] =
{
0xdc000 , /* default first */
0xc8000 ,
0xcc000 ,
0xd0000 ,
0xd4000 ,
0xd8000 ,
0xe0000 ,
0xeb800 , /* VTech Platinum SMP */
0xf0000 ,
} ;
/* 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 . May be an information whether or not the BIOS supports
extended translation could be also useful here . */
static struct signature {
unsigned char * signature ;
int sig_offset ;
int sig_length ;
} signatures [ ] =
{
{ " Adaptec AHA-1520 BIOS " , 0x102e , 21 } ,
/* Adaptec 152x */
{ " Adaptec AHA-1520B " , 0x000b , 17 } ,
/* Adaptec 152x rev B */
{ " Adaptec AHA-1520B " , 0x0026 , 17 } ,
/* Iomega Jaz Jet ISA (AIC6370Q) */
{ " Adaptec ASW-B626 BIOS " , 0x1029 , 21 } ,
/* on-board controller */
{ " Adaptec BIOS: ASW-B626 " , 0x000f , 22 } ,
/* on-board controller */
{ " Adaptec ASW-B626 S2 " , 0x2e6c , 19 } ,
/* on-board controller */
{ " Adaptec BIOS:AIC-6360 " , 0x000c , 21 } ,
/* on-board controller */
{ " ScsiPro SP-360 BIOS " , 0x2873 , 19 } ,
/* ScsiPro-Controller */
{ " GA-400 LOCAL BUS SCSI BIOS " , 0x102e , 26 } ,
/* Gigabyte Local-Bus-SCSI */
{ " Adaptec BIOS:AVA-282X " , 0x000c , 21 } ,
/* Adaptec 282x */
{ " Adaptec IBM Dock II SCSI " , 0x2edd , 24 } ,
/* IBM Thinkpad Dock II */
{ " Adaptec BIOS:AHA-1532P " , 0x001c , 22 } ,
/* IBM Thinkpad Dock II SCSI */
{ " DTC3520A Host Adapter BIOS " , 0x318a , 26 } ,
/* DTC 3520A ISA SCSI */
} ;
# endif /* !SKIP_BIOSTEST */
/*
* Test , if port_base is valid .
*
*/
static int aha152x_porttest ( int io_port )
{
int i ;
SETPORT ( io_port + O_DMACNTRL1 , 0 ) ; /* reset stack pointer */
for ( i = 0 ; i < 16 ; i + + )
SETPORT ( io_port + O_STACK , i ) ;
SETPORT ( io_port + O_DMACNTRL1 , 0 ) ; /* reset stack pointer */
for ( i = 0 ; i < 16 & & GETPORT ( io_port + O_STACK ) = = i ; i + + )
;
return ( i = = 16 ) ;
}
static int tc1550_porttest ( int io_port )
{
int i ;
SETPORT ( io_port + O_TC_DMACNTRL1 , 0 ) ; /* reset stack pointer */
for ( i = 0 ; i < 16 ; i + + )
SETPORT ( io_port + O_STACK , i ) ;
SETPORT ( io_port + O_TC_DMACNTRL1 , 0 ) ; /* reset stack pointer */
for ( i = 0 ; i < 16 & & GETPORT ( io_port + O_TC_STACK ) = = i ; i + + )
;
return ( i = = 16 ) ;
}
static int checksetup ( struct aha152x_setup * setup )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( ports ) & & ( setup - > io_port ! = ports [ i ] ) ; i + + )
;
if ( i = = ARRAY_SIZE ( ports ) )
return 0 ;
if ( request_region ( setup - > io_port , IO_RANGE , " aha152x " ) = = 0 ) {
printk ( KERN_ERR " aha152x: io port 0x%x busy. \n " , setup - > io_port ) ;
return 0 ;
}
if ( aha152x_porttest ( setup - > io_port ) ) {
setup - > tc1550 = 0 ;
} else if ( tc1550_porttest ( setup - > io_port ) ) {
setup - > tc1550 = 1 ;
} else {
release_region ( setup - > io_port , IO_RANGE ) ;
return 0 ;
}
release_region ( setup - > io_port , IO_RANGE ) ;
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 ;
}
static int __init aha152x_init ( void )
{
int i , j , ok ;
# if defined(AUTOCONF)
aha152x_config conf ;
# endif
# ifdef __ISAPNP__
struct pnp_dev * dev = NULL , * pnpdev [ 2 ] = { NULL , NULL } ;
# endif
if ( setup_count ) {
printk ( KERN_INFO " aha152x: processing commandline: " ) ;
for ( i = 0 ; i < setup_count ; i + + ) {
if ( ! checksetup ( & setup [ i ] ) ) {
printk ( KERN_ERR " \n aha152x: %s \n " , setup [ i ] . conf ) ;
printk ( KERN_ERR " aha152x: invalid line \n " ) ;
}
}
printk ( " ok \n " ) ;
}
# if defined(SETUP0)
if ( setup_count < ARRAY_SIZE ( setup ) ) {
struct aha152x_setup override = SETUP0 ;
if ( setup_count = = 0 | | ( override . io_port ! = setup [ 0 ] . io_port ) ) {
if ( ! checksetup ( & override ) ) {
printk ( KERN_ERR " \n aha152x: 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
# if defined(SETUP1)
if ( setup_count < ARRAY_SIZE ( setup ) ) {
struct aha152x_setup override = SETUP1 ;
if ( setup_count = = 0 | | ( override . io_port ! = setup [ 0 ] . io_port ) ) {
if ( ! checksetup ( & override ) ) {
printk ( KERN_ERR " \n aha152x: 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 defined(MODULE)
if ( setup_count < ARRAY_SIZE ( setup ) & & ( aha152x [ 0 ] ! = 0 | | io [ 0 ] ! = 0 | | irq [ 0 ] ! = 0 ) ) {
if ( aha152x [ 0 ] ! = 0 ) {
setup [ setup_count ] . conf = " " ;
setup [ setup_count ] . io_port = aha152x [ 0 ] ;
setup [ setup_count ] . irq = aha152x [ 1 ] ;
setup [ setup_count ] . scsiid = aha152x [ 2 ] ;
setup [ setup_count ] . reconnect = aha152x [ 3 ] ;
setup [ setup_count ] . parity = aha152x [ 4 ] ;
setup [ setup_count ] . synchronous = aha152x [ 5 ] ;
setup [ setup_count ] . delay = aha152x [ 6 ] ;
setup [ setup_count ] . ext_trans = aha152x [ 7 ] ;
# if defined(AHA152X_DEBUG)
setup [ setup_count ] . debug = aha152x [ 8 ] ;
# endif
} else if ( io [ 0 ] ! = 0 | | irq [ 0 ] ! = 0 ) {
if ( io [ 0 ] ! = 0 ) setup [ setup_count ] . io_port = io [ 0 ] ;
if ( irq [ 0 ] ! = 0 ) setup [ setup_count ] . irq = irq [ 0 ] ;
setup [ setup_count ] . scsiid = scsiid [ 0 ] ;
setup [ setup_count ] . reconnect = reconnect [ 0 ] ;
setup [ setup_count ] . parity = parity [ 0 ] ;
setup [ setup_count ] . synchronous = sync [ 0 ] ;
setup [ setup_count ] . delay = delay [ 0 ] ;
setup [ setup_count ] . ext_trans = exttrans [ 0 ] ;
# if defined(AHA152X_DEBUG)
setup [ setup_count ] . debug = debug [ 0 ] ;
# endif
}
if ( checksetup ( & setup [ setup_count ] ) )
setup_count + + ;
else
printk ( KERN_ERR " aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d \n " ,
setup [ setup_count ] . io_port ,
setup [ setup_count ] . irq ,
setup [ setup_count ] . scsiid ,
setup [ setup_count ] . reconnect ,
setup [ setup_count ] . parity ,
setup [ setup_count ] . synchronous ,
setup [ setup_count ] . delay ,
setup [ setup_count ] . ext_trans ) ;
}
if ( setup_count < ARRAY_SIZE ( setup ) & & ( aha152x1 [ 0 ] ! = 0 | | io [ 1 ] ! = 0 | | irq [ 1 ] ! = 0 ) ) {
if ( aha152x1 [ 0 ] ! = 0 ) {
setup [ setup_count ] . conf = " " ;
setup [ setup_count ] . io_port = aha152x1 [ 0 ] ;
setup [ setup_count ] . irq = aha152x1 [ 1 ] ;
setup [ setup_count ] . scsiid = aha152x1 [ 2 ] ;
setup [ setup_count ] . reconnect = aha152x1 [ 3 ] ;
setup [ setup_count ] . parity = aha152x1 [ 4 ] ;
setup [ setup_count ] . synchronous = aha152x1 [ 5 ] ;
setup [ setup_count ] . delay = aha152x1 [ 6 ] ;
setup [ setup_count ] . ext_trans = aha152x1 [ 7 ] ;
# if defined(AHA152X_DEBUG)
setup [ setup_count ] . debug = aha152x1 [ 8 ] ;
# endif
} else if ( io [ 1 ] ! = 0 | | irq [ 1 ] ! = 0 ) {
if ( io [ 1 ] ! = 0 ) setup [ setup_count ] . io_port = io [ 1 ] ;
if ( irq [ 1 ] ! = 0 ) setup [ setup_count ] . irq = irq [ 1 ] ;
setup [ setup_count ] . scsiid = scsiid [ 1 ] ;
setup [ setup_count ] . reconnect = reconnect [ 1 ] ;
setup [ setup_count ] . parity = parity [ 1 ] ;
setup [ setup_count ] . synchronous = sync [ 1 ] ;
setup [ setup_count ] . delay = delay [ 1 ] ;
setup [ setup_count ] . ext_trans = exttrans [ 1 ] ;
# if defined(AHA152X_DEBUG)
setup [ setup_count ] . debug = debug [ 1 ] ;
# endif
}
if ( checksetup ( & setup [ setup_count ] ) )
setup_count + + ;
else
printk ( KERN_ERR " aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d \n " ,
setup [ setup_count ] . io_port ,
setup [ setup_count ] . irq ,
setup [ setup_count ] . scsiid ,
setup [ setup_count ] . reconnect ,
setup [ setup_count ] . parity ,
setup [ setup_count ] . synchronous ,
setup [ setup_count ] . delay ,
setup [ setup_count ] . ext_trans ) ;
}
# endif
# ifdef __ISAPNP__
for ( i = 0 ; setup_count < ARRAY_SIZE ( setup ) & & id_table [ i ] . vendor ; i + + ) {
while ( setup_count < ARRAY_SIZE ( setup ) & &
( dev = pnp_find_dev ( NULL , id_table [ i ] . vendor , id_table [ i ] . function , dev ) ) ) {
if ( pnp_device_attach ( dev ) < 0 )
continue ;
if ( pnp_activate_dev ( dev ) < 0 ) {
pnp_device_detach ( dev ) ;
continue ;
}
if ( ! pnp_port_valid ( dev , 0 ) ) {
pnp_device_detach ( dev ) ;
continue ;
}
if ( setup_count = = 1 & & pnp_port_start ( dev , 0 ) = = setup [ 0 ] . io_port ) {
pnp_device_detach ( dev ) ;
continue ;
}
setup [ setup_count ] . io_port = pnp_port_start ( dev , 0 ) ;
setup [ setup_count ] . irq = pnp_irq ( dev , 0 ) ;
setup [ setup_count ] . scsiid = 7 ;
setup [ setup_count ] . reconnect = 1 ;
setup [ setup_count ] . parity = 1 ;
setup [ setup_count ] . synchronous = 1 ;
setup [ setup_count ] . delay = DELAY_DEFAULT ;
setup [ setup_count ] . ext_trans = 0 ;
# if defined(AHA152X_DEBUG)
setup [ setup_count ] . debug = DEBUG_DEFAULT ;
# endif
# if defined(__ISAPNP__)
pnpdev [ setup_count ] = dev ;
# endif
printk ( KERN_INFO
" aha152x: found ISAPnP adapter at io=0x%03x, irq=%d \n " ,
setup [ setup_count ] . io_port , setup [ setup_count ] . irq ) ;
setup_count + + ;
}
}
# endif
# if defined(AUTOCONF)
if ( setup_count < ARRAY_SIZE ( setup ) ) {
# if !defined(SKIP_BIOSTEST)
ok = 0 ;
for ( i = 0 ; i < ARRAY_SIZE ( addresses ) & & ! ok ; i + + ) {
void __iomem * p = ioremap ( addresses [ i ] , 0x4000 ) ;
if ( ! p )
continue ;
for ( j = 0 ; j < ARRAY_SIZE ( signatures ) & & ! ok ; j + + )
ok = check_signature ( p + signatures [ j ] . sig_offset ,
signatures [ j ] . signature , signatures [ j ] . sig_length ) ;
iounmap ( p ) ;
}
if ( ! ok & & setup_count = = 0 )
return 0 ;
printk ( KERN_INFO " aha152x: BIOS test: passed, " ) ;
# else
printk ( KERN_INFO " aha152x: " ) ;
# endif /* !SKIP_BIOSTEST */
ok = 0 ;
for ( i = 0 ; i < ARRAY_SIZE ( ports ) & & setup_count < 2 ; i + + ) {
if ( ( setup_count = = 1 ) & & ( setup [ 0 ] . io_port = = ports [ i ] ) )
continue ;
if ( request_region ( ports [ i ] , IO_RANGE , " aha152x " ) = = 0 ) {
printk ( KERN_ERR " aha152x: io port 0x%x busy. \n " , ports [ i ] ) ;
continue ;
}
if ( aha152x_porttest ( ports [ i ] ) ) {
setup [ setup_count ] . tc1550 = 0 ;
conf . cf_port =
( GETPORT ( ports [ i ] + O_PORTA ) < < 8 ) + GETPORT ( ports [ i ] + O_PORTB ) ;
} else if ( tc1550_porttest ( ports [ i ] ) ) {
setup [ setup_count ] . tc1550 = 1 ;
conf . cf_port =
( GETPORT ( ports [ i ] + O_TC_PORTA ) < < 8 ) + GETPORT ( ports [ i ] + O_TC_PORTB ) ;
} else {
release_region ( ports [ i ] , IO_RANGE ) ;
continue ;
}
release_region ( ports [ i ] , IO_RANGE ) ;
ok + + ;
setup [ setup_count ] . io_port = ports [ i ] ;
setup [ setup_count ] . irq = IRQ_MIN + conf . cf_irq ;
setup [ setup_count ] . scsiid = conf . cf_id ;
setup [ setup_count ] . reconnect = conf . cf_tardisc ;
setup [ setup_count ] . parity = ! conf . cf_parity ;
setup [ setup_count ] . synchronous = conf . cf_syncneg ;
setup [ setup_count ] . delay = DELAY_DEFAULT ;
setup [ setup_count ] . ext_trans = 0 ;
# if defined(AHA152X_DEBUG)
setup [ setup_count ] . debug = DEBUG_DEFAULT ;
# endif
setup_count + + ;
}
if ( ok )
printk ( " auto configuration: ok, " ) ;
}
# endif
printk ( " %d controller(s) configured \n " , setup_count ) ;
for ( i = 0 ; i < setup_count ; i + + ) {
if ( request_region ( setup [ i ] . io_port , IO_RANGE , " aha152x " ) ) {
struct Scsi_Host * shpnt = aha152x_probe_one ( & setup [ i ] ) ;
if ( ! shpnt ) {
release_region ( setup [ i ] . io_port , IO_RANGE ) ;
# if defined(__ISAPNP__)
} else if ( pnpdev [ i ] ) {
HOSTDATA ( shpnt ) - > pnpdev = pnpdev [ i ] ;
pnpdev [ i ] = NULL ;
# endif
}
} else {
printk ( KERN_ERR " aha152x: io port 0x%x busy. \n " , setup [ i ] . io_port ) ;
}
# if defined(__ISAPNP__)
if ( pnpdev [ i ] )
pnp_device_detach ( pnpdev [ i ] ) ;
# endif
}
return registered_count > 0 ;
}
static void __exit aha152x_exit ( void )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( setup ) ; i + + ) {
aha152x_release ( aha152x_host [ i ] ) ;
aha152x_host [ i ] = NULL ;
}
}
module_init ( aha152x_init ) ;
module_exit ( aha152x_exit ) ;
# if !defined(MODULE)
static int __init aha152x_setup ( char * str )
{
# if defined(AHA152X_DEBUG)
int ints [ 11 ] ;
# else
int ints [ 10 ] ;
# endif
get_options ( str , ARRAY_SIZE ( ints ) , ints ) ;
if ( setup_count > = ARRAY_SIZE ( setup ) ) {
printk ( KERN_ERR " aha152x: you can only configure up to two controllers \n " ) ;
return 1 ;
}
setup [ setup_count ] . conf = str ;
setup [ setup_count ] . io_port = ints [ 0 ] > = 1 ? ints [ 1 ] : 0x340 ;
setup [ setup_count ] . irq = ints [ 0 ] > = 2 ? ints [ 2 ] : 11 ;
setup [ setup_count ] . scsiid = ints [ 0 ] > = 3 ? ints [ 3 ] : 7 ;
setup [ setup_count ] . reconnect = ints [ 0 ] > = 4 ? ints [ 4 ] : 1 ;
setup [ setup_count ] . parity = ints [ 0 ] > = 5 ? ints [ 5 ] : 1 ;
setup [ setup_count ] . synchronous = ints [ 0 ] > = 6 ? ints [ 6 ] : 1 ;
setup [ setup_count ] . delay = ints [ 0 ] > = 7 ? ints [ 7 ] : DELAY_DEFAULT ;
setup [ setup_count ] . ext_trans = ints [ 0 ] > = 8 ? ints [ 8 ] : 0 ;
# if defined(AHA152X_DEBUG)
setup [ setup_count ] . debug = ints [ 0 ] > = 9 ? ints [ 9 ] : DEBUG_DEFAULT ;
if ( ints [ 0 ] > 9 ) {
printk ( KERN_NOTICE " aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID> "
" [,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>[,<DEBUG>]]]]]]]] \n " ) ;
# else
if ( ints [ 0 ] > 8 ) { /*}*/
printk ( KERN_NOTICE " aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID> "
" [,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]] \n " ) ;
# endif
} else {
setup_count + + ;
return 0 ;
}
return 1 ;
}
__setup ( " aha152x= " , aha152x_setup ) ;
# endif
# endif /* !PCMCIA */