2005-04-17 02:20:36 +04:00
/* $Id: esp.c,v 1.101 2002/01/15 06:48:55 davem Exp $
* esp . c : EnhancedScsiProcessor Sun SCSI driver code .
*
* Copyright ( C ) 1995 , 1998 David S . Miller ( davem @ caip . rutgers . edu )
*/
/* TODO:
*
* 1 ) Maybe disable parity checking in config register one for SCSI1
* targets . ( Gilmore says parity error on the SBus can lock up
* old sun4c ' s )
* 2 ) Add support for DMA2 pipelining .
* 3 ) Add tagged queueing .
*/
# include <linux/config.h>
# include <linux/kernel.h>
# include <linux/delay.h>
# include <linux/types.h>
# include <linux/string.h>
# include <linux/slab.h>
# include <linux/blkdev.h>
# include <linux/proc_fs.h>
# include <linux/stat.h>
# include <linux/init.h>
# include <linux/spinlock.h>
# include <linux/interrupt.h>
# include <linux/module.h>
# include "esp.h"
# include <asm/sbus.h>
# include <asm/dma.h>
# include <asm/system.h>
# include <asm/ptrace.h>
# include <asm/pgtable.h>
# include <asm/oplib.h>
# include <asm/io.h>
# include <asm/irq.h>
# ifndef __sparc_v9__
# include <asm/machines.h>
# include <asm/idprom.h>
# endif
# include <scsi/scsi.h>
# include <scsi/scsi_cmnd.h>
# include <scsi/scsi_device.h>
# include <scsi/scsi_eh.h>
# include <scsi/scsi_host.h>
# include <scsi/scsi_tcq.h>
2005-04-25 07:35:20 +04:00
# define DRV_VERSION "1.101"
2005-04-17 02:20:36 +04:00
# define DEBUG_ESP
/* #define DEBUG_ESP_HME */
/* #define DEBUG_ESP_DATA */
/* #define DEBUG_ESP_QUEUE */
/* #define DEBUG_ESP_DISCONNECT */
/* #define DEBUG_ESP_STATUS */
/* #define DEBUG_ESP_PHASES */
/* #define DEBUG_ESP_WORKBUS */
/* #define DEBUG_STATE_MACHINE */
/* #define DEBUG_ESP_CMDS */
/* #define DEBUG_ESP_IRQS */
/* #define DEBUG_SDTR */
/* #define DEBUG_ESP_SG */
/* Use the following to sprinkle debugging messages in a way which
* suits you if combinations of the above become too verbose when
* trying to track down a specific problem .
*/
/* #define DEBUG_ESP_MISC */
# if defined(DEBUG_ESP)
# define ESPLOG(foo) printk foo
# else
# define ESPLOG(foo)
# endif /* (DEBUG_ESP) */
# if defined(DEBUG_ESP_HME)
# define ESPHME(foo) printk foo
# else
# define ESPHME(foo)
# endif
# if defined(DEBUG_ESP_DATA)
# define ESPDATA(foo) printk foo
# else
# define ESPDATA(foo)
# endif
# if defined(DEBUG_ESP_QUEUE)
# define ESPQUEUE(foo) printk foo
# else
# define ESPQUEUE(foo)
# endif
# if defined(DEBUG_ESP_DISCONNECT)
# define ESPDISC(foo) printk foo
# else
# define ESPDISC(foo)
# endif
# if defined(DEBUG_ESP_STATUS)
# define ESPSTAT(foo) printk foo
# else
# define ESPSTAT(foo)
# endif
# if defined(DEBUG_ESP_PHASES)
# define ESPPHASE(foo) printk foo
# else
# define ESPPHASE(foo)
# endif
# if defined(DEBUG_ESP_WORKBUS)
# define ESPBUS(foo) printk foo
# else
# define ESPBUS(foo)
# endif
# if defined(DEBUG_ESP_IRQS)
# define ESPIRQ(foo) printk foo
# else
# define ESPIRQ(foo)
# endif
# if defined(DEBUG_SDTR)
# define ESPSDTR(foo) printk foo
# else
# define ESPSDTR(foo)
# endif
# if defined(DEBUG_ESP_MISC)
# define ESPMISC(foo) printk foo
# else
# define ESPMISC(foo)
# endif
/* Command phase enumeration. */
enum {
not_issued = 0x00 , /* Still in the issue_SC queue. */
/* Various forms of selecting a target. */
# define in_slct_mask 0x10
in_slct_norm = 0x10 , /* ESP is arbitrating, normal selection */
in_slct_stop = 0x11 , /* ESP will select, then stop with IRQ */
in_slct_msg = 0x12 , /* select, then send a message */
in_slct_tag = 0x13 , /* select and send tagged queue msg */
in_slct_sneg = 0x14 , /* select and acquire sync capabilities */
/* Any post selection activity. */
# define in_phases_mask 0x20
in_datain = 0x20 , /* Data is transferring from the bus */
in_dataout = 0x21 , /* Data is transferring to the bus */
in_data_done = 0x22 , /* Last DMA data operation done (maybe) */
in_msgin = 0x23 , /* Eating message from target */
in_msgincont = 0x24 , /* Eating more msg bytes from target */
in_msgindone = 0x25 , /* Decide what to do with what we got */
in_msgout = 0x26 , /* Sending message to target */
in_msgoutdone = 0x27 , /* Done sending msg out */
in_cmdbegin = 0x28 , /* Sending cmd after abnormal selection */
in_cmdend = 0x29 , /* Done sending slow cmd */
in_status = 0x2a , /* Was in status phase, finishing cmd */
in_freeing = 0x2b , /* freeing the bus for cmd cmplt or disc */
in_the_dark = 0x2c , /* Don't know what bus phase we are in */
/* Special states, ie. not normal bus transitions... */
# define in_spec_mask 0x80
in_abortone = 0x80 , /* Aborting one command currently */
in_abortall = 0x81 , /* Blowing away all commands we have */
in_resetdev = 0x82 , /* SCSI target reset in progress */
in_resetbus = 0x83 , /* SCSI bus reset in progress */
in_tgterror = 0x84 , /* Target did something stupid */
} ;
enum {
/* Zero has special meaning, see skipahead[12]. */
/*0*/ do_never ,
/*1*/ do_phase_determine ,
/*2*/ do_reset_bus ,
/*3*/ do_reset_complete ,
/*4*/ do_work_bus ,
/*5*/ do_intr_end
} ;
/* The master ring of all esp hosts we are managing in this driver. */
static struct esp * espchain ;
static DEFINE_SPINLOCK ( espchain_lock ) ;
static int esps_running = 0 ;
/* Forward declarations. */
static irqreturn_t esp_intr ( int irq , void * dev_id , struct pt_regs * pregs ) ;
/* Debugging routines */
struct esp_cmdstrings {
u8 cmdchar ;
char * text ;
} esp_cmd_strings [ ] = {
/* Miscellaneous */
{ ESP_CMD_NULL , " ESP_NOP " , } ,
{ ESP_CMD_FLUSH , " FIFO_FLUSH " , } ,
{ ESP_CMD_RC , " RSTESP " , } ,
{ ESP_CMD_RS , " RSTSCSI " , } ,
/* Disconnected State Group */
{ ESP_CMD_RSEL , " RESLCTSEQ " , } ,
{ ESP_CMD_SEL , " SLCTNATN " , } ,
{ ESP_CMD_SELA , " SLCTATN " , } ,
{ ESP_CMD_SELAS , " SLCTATNSTOP " , } ,
{ ESP_CMD_ESEL , " ENSLCTRESEL " , } ,
{ ESP_CMD_DSEL , " DISSELRESEL " , } ,
{ ESP_CMD_SA3 , " SLCTATN3 " , } ,
{ ESP_CMD_RSEL3 , " RESLCTSEQ " , } ,
/* Target State Group */
{ ESP_CMD_SMSG , " SNDMSG " , } ,
{ ESP_CMD_SSTAT , " SNDSTATUS " , } ,
{ ESP_CMD_SDATA , " SNDDATA " , } ,
{ ESP_CMD_DSEQ , " DISCSEQ " , } ,
{ ESP_CMD_TSEQ , " TERMSEQ " , } ,
{ ESP_CMD_TCCSEQ , " TRGTCMDCOMPSEQ " , } ,
{ ESP_CMD_DCNCT , " DISC " , } ,
{ ESP_CMD_RMSG , " RCVMSG " , } ,
{ ESP_CMD_RCMD , " RCVCMD " , } ,
{ ESP_CMD_RDATA , " RCVDATA " , } ,
{ ESP_CMD_RCSEQ , " RCVCMDSEQ " , } ,
/* Initiator State Group */
{ ESP_CMD_TI , " TRANSINFO " , } ,
{ ESP_CMD_ICCSEQ , " INICMDSEQCOMP " , } ,
{ ESP_CMD_MOK , " MSGACCEPTED " , } ,
{ ESP_CMD_TPAD , " TPAD " , } ,
{ ESP_CMD_SATN , " SATN " , } ,
{ ESP_CMD_RATN , " RATN " , } ,
} ;
# define NUM_ESP_COMMANDS ((sizeof(esp_cmd_strings)) / (sizeof(struct esp_cmdstrings)))
/* Print textual representation of an ESP command */
static inline void esp_print_cmd ( u8 espcmd )
{
u8 dma_bit = espcmd & ESP_CMD_DMA ;
int i ;
espcmd & = ~ dma_bit ;
for ( i = 0 ; i < NUM_ESP_COMMANDS ; i + + )
if ( esp_cmd_strings [ i ] . cmdchar = = espcmd )
break ;
if ( i = = NUM_ESP_COMMANDS )
printk ( " ESP_Unknown " ) ;
else
printk ( " %s%s " , esp_cmd_strings [ i ] . text ,
( ( dma_bit ) ? " +DMA " : " " ) ) ;
}
/* Print the status register's value */
static inline void esp_print_statreg ( u8 statreg )
{
u8 phase ;
printk ( " STATUS< " ) ;
phase = statreg & ESP_STAT_PMASK ;
printk ( " %s, " , ( phase = = ESP_DOP ? " DATA-OUT " :
( phase = = ESP_DIP ? " DATA-IN " :
( phase = = ESP_CMDP ? " COMMAND " :
( phase = = ESP_STATP ? " STATUS " :
( phase = = ESP_MOP ? " MSG-OUT " :
( phase = = ESP_MIP ? " MSG_IN " :
" unknown " ) ) ) ) ) ) ) ;
if ( statreg & ESP_STAT_TDONE )
printk ( " TRANS_DONE, " ) ;
if ( statreg & ESP_STAT_TCNT )
printk ( " TCOUNT_ZERO, " ) ;
if ( statreg & ESP_STAT_PERR )
printk ( " P_ERROR, " ) ;
if ( statreg & ESP_STAT_SPAM )
printk ( " SPAM, " ) ;
if ( statreg & ESP_STAT_INTR )
printk ( " IRQ, " ) ;
printk ( " > " ) ;
}
/* Print the interrupt register's value */
static inline void esp_print_ireg ( u8 intreg )
{
printk ( " INTREG< " ) ;
if ( intreg & ESP_INTR_S )
printk ( " SLCT_NATN " ) ;
if ( intreg & ESP_INTR_SATN )
printk ( " SLCT_ATN " ) ;
if ( intreg & ESP_INTR_RSEL )
printk ( " RSLCT " ) ;
if ( intreg & ESP_INTR_FDONE )
printk ( " FDONE " ) ;
if ( intreg & ESP_INTR_BSERV )
printk ( " BSERV " ) ;
if ( intreg & ESP_INTR_DC )
printk ( " DISCNCT " ) ;
if ( intreg & ESP_INTR_IC )
printk ( " ILL_CMD " ) ;
if ( intreg & ESP_INTR_SR )
printk ( " SCSI_BUS_RESET " ) ;
printk ( " > " ) ;
}
/* Print the sequence step registers contents */
static inline void esp_print_seqreg ( u8 stepreg )
{
stepreg & = ESP_STEP_VBITS ;
printk ( " STEP<%s> " ,
( stepreg = = ESP_STEP_ASEL ? " SLCT_ARB_CMPLT " :
( stepreg = = ESP_STEP_SID ? " 1BYTE_MSG_SENT " :
( stepreg = = ESP_STEP_NCMD ? " NOT_IN_CMD_PHASE " :
( stepreg = = ESP_STEP_PPC ? " CMD_BYTES_LOST " :
( stepreg = = ESP_STEP_FINI4 ? " CMD_SENT_OK " :
" UNKNOWN " ) ) ) ) ) ) ;
}
static char * phase_string ( int phase )
{
switch ( phase ) {
case not_issued :
return " UNISSUED " ;
case in_slct_norm :
return " SLCTNORM " ;
case in_slct_stop :
return " SLCTSTOP " ;
case in_slct_msg :
return " SLCTMSG " ;
case in_slct_tag :
return " SLCTTAG " ;
case in_slct_sneg :
return " SLCTSNEG " ;
case in_datain :
return " DATAIN " ;
case in_dataout :
return " DATAOUT " ;
case in_data_done :
return " DATADONE " ;
case in_msgin :
return " MSGIN " ;
case in_msgincont :
return " MSGINCONT " ;
case in_msgindone :
return " MSGINDONE " ;
case in_msgout :
return " MSGOUT " ;
case in_msgoutdone :
return " MSGOUTDONE " ;
case in_cmdbegin :
return " CMDBEGIN " ;
case in_cmdend :
return " CMDEND " ;
case in_status :
return " STATUS " ;
case in_freeing :
return " FREEING " ;
case in_the_dark :
return " CLUELESS " ;
case in_abortone :
return " ABORTONE " ;
case in_abortall :
return " ABORTALL " ;
case in_resetdev :
return " RESETDEV " ;
case in_resetbus :
return " RESETBUS " ;
case in_tgterror :
return " TGTERROR " ;
default :
return " UNKNOWN " ;
} ;
}
# ifdef DEBUG_STATE_MACHINE
static inline void esp_advance_phase ( struct scsi_cmnd * s , int newphase )
{
ESPLOG ( ( " <%s> " , phase_string ( newphase ) ) ) ;
s - > SCp . sent_command = s - > SCp . phase ;
s - > SCp . phase = newphase ;
}
# else
# define esp_advance_phase(__s, __newphase) \
( __s ) - > SCp . sent_command = ( __s ) - > SCp . phase ; \
( __s ) - > SCp . phase = ( __newphase ) ;
# endif
# ifdef DEBUG_ESP_CMDS
static inline void esp_cmd ( struct esp * esp , u8 cmd )
{
esp - > espcmdlog [ esp - > espcmdent ] = cmd ;
esp - > espcmdent = ( esp - > espcmdent + 1 ) & 31 ;
sbus_writeb ( cmd , esp - > eregs + ESP_CMD ) ;
}
# else
# define esp_cmd(__esp, __cmd) \
sbus_writeb ( ( __cmd ) , ( ( __esp ) - > eregs ) + ESP_CMD )
# endif
# define ESP_INTSOFF(__dregs) \
sbus_writel ( sbus_readl ( ( __dregs ) + DMA_CSR ) & ~ ( DMA_INT_ENAB ) , ( __dregs ) + DMA_CSR )
# define ESP_INTSON(__dregs) \
sbus_writel ( sbus_readl ( ( __dregs ) + DMA_CSR ) | DMA_INT_ENAB , ( __dregs ) + DMA_CSR )
# define ESP_IRQ_P(__dregs) \
( sbus_readl ( ( __dregs ) + DMA_CSR ) & ( DMA_HNDL_INTR | DMA_HNDL_ERROR ) )
/* How we use the various Linux SCSI data structures for operation.
*
* struct scsi_cmnd :
*
* We keep track of the synchronous capabilities of a target
* in the device member , using sync_min_period and
* sync_max_offset . These are the values we directly write
* into the ESP registers while running a command . If offset
* is zero the ESP will use asynchronous transfers .
* If the borken flag is set we assume we shouldn ' t even bother
* trying to negotiate for synchronous transfer as this target
* is really stupid . If we notice the target is dropping the
* bus , and we have been allowing it to disconnect , we clear
* the disconnect flag .
*/
/* Manipulation of the ESP command queues. Thanks to the aha152x driver
* and its author , Juergen E . Fischer , for the methods used here .
* Note that these are per - ESP queues , not global queues like
* the aha152x driver uses .
*/
static inline void append_SC ( struct scsi_cmnd * * SC , struct scsi_cmnd * new_SC )
{
struct scsi_cmnd * end ;
new_SC - > host_scribble = ( unsigned char * ) NULL ;
if ( ! * SC )
* SC = new_SC ;
else {
for ( end = * SC ; end - > host_scribble ; end = ( struct scsi_cmnd * ) end - > host_scribble )
;
end - > host_scribble = ( unsigned char * ) new_SC ;
}
}
static inline void prepend_SC ( struct scsi_cmnd * * SC , struct scsi_cmnd * new_SC )
{
new_SC - > host_scribble = ( unsigned char * ) * SC ;
* SC = new_SC ;
}
static inline struct scsi_cmnd * remove_first_SC ( struct scsi_cmnd * * SC )
{
struct scsi_cmnd * ptr ;
ptr = * SC ;
if ( ptr )
* SC = ( struct scsi_cmnd * ) ( * SC ) - > host_scribble ;
return ptr ;
}
static inline struct scsi_cmnd * remove_SC ( struct scsi_cmnd * * SC , int target , int lun )
{
struct scsi_cmnd * ptr , * prev ;
for ( ptr = * SC , prev = NULL ;
ptr & & ( ( ptr - > device - > id ! = target ) | | ( ptr - > device - > lun ! = lun ) ) ;
prev = ptr , ptr = ( struct scsi_cmnd * ) ptr - > host_scribble )
;
if ( ptr ) {
if ( prev )
prev - > host_scribble = ptr - > host_scribble ;
else
* SC = ( struct scsi_cmnd * ) ptr - > host_scribble ;
}
return ptr ;
}
/* Resetting various pieces of the ESP scsi driver chipset/buses. */
static void esp_reset_dma ( struct esp * esp )
{
int can_do_burst16 , can_do_burst32 , can_do_burst64 ;
int can_do_sbus64 ;
u32 tmp ;
can_do_burst16 = ( esp - > bursts & DMA_BURST16 ) ! = 0 ;
can_do_burst32 = ( esp - > bursts & DMA_BURST32 ) ! = 0 ;
can_do_burst64 = 0 ;
can_do_sbus64 = 0 ;
if ( sbus_can_dma_64bit ( esp - > sdev ) )
can_do_sbus64 = 1 ;
if ( sbus_can_burst64 ( esp - > sdev ) )
can_do_burst64 = ( esp - > bursts & DMA_BURST64 ) ! = 0 ;
/* Punt the DVMA into a known state. */
if ( esp - > dma - > revision ! = dvmahme ) {
tmp = sbus_readl ( esp - > dregs + DMA_CSR ) ;
sbus_writel ( tmp | DMA_RST_SCSI , esp - > dregs + DMA_CSR ) ;
sbus_writel ( tmp & ~ DMA_RST_SCSI , esp - > dregs + DMA_CSR ) ;
}
switch ( esp - > dma - > revision ) {
case dvmahme :
/* This is the HME DVMA gate array. */
sbus_writel ( DMA_RESET_FAS366 , esp - > dregs + DMA_CSR ) ;
sbus_writel ( DMA_RST_SCSI , esp - > dregs + DMA_CSR ) ;
esp - > prev_hme_dmacsr = ( DMA_PARITY_OFF | DMA_2CLKS | DMA_SCSI_DISAB | DMA_INT_ENAB ) ;
esp - > prev_hme_dmacsr & = ~ ( DMA_ENABLE | DMA_ST_WRITE | DMA_BRST_SZ ) ;
if ( can_do_burst64 )
esp - > prev_hme_dmacsr | = DMA_BRST64 ;
else if ( can_do_burst32 )
esp - > prev_hme_dmacsr | = DMA_BRST32 ;
if ( can_do_sbus64 ) {
esp - > prev_hme_dmacsr | = DMA_SCSI_SBUS64 ;
sbus_set_sbus64 ( esp - > sdev , esp - > bursts ) ;
}
/* This chip is horrible. */
while ( sbus_readl ( esp - > dregs + DMA_CSR ) & DMA_PEND_READ )
udelay ( 1 ) ;
sbus_writel ( 0 , esp - > dregs + DMA_CSR ) ;
sbus_writel ( esp - > prev_hme_dmacsr , esp - > dregs + DMA_CSR ) ;
/* This is necessary to avoid having the SCSI channel
* engine lock up on us .
*/
sbus_writel ( 0 , esp - > dregs + DMA_ADDR ) ;
break ;
case dvmarev2 :
/* This is the gate array found in the sun4m
* NCR SBUS I / O subsystem .
*/
if ( esp - > erev ! = esp100 ) {
tmp = sbus_readl ( esp - > dregs + DMA_CSR ) ;
sbus_writel ( tmp | DMA_3CLKS , esp - > dregs + DMA_CSR ) ;
}
break ;
case dvmarev3 :
tmp = sbus_readl ( esp - > dregs + DMA_CSR ) ;
tmp & = ~ DMA_3CLKS ;
tmp | = DMA_2CLKS ;
if ( can_do_burst32 ) {
tmp & = ~ DMA_BRST_SZ ;
tmp | = DMA_BRST32 ;
}
sbus_writel ( tmp , esp - > dregs + DMA_CSR ) ;
break ;
case dvmaesc1 :
/* This is the DMA unit found on SCSI/Ether cards. */
tmp = sbus_readl ( esp - > dregs + DMA_CSR ) ;
tmp | = DMA_ADD_ENABLE ;
tmp & = ~ DMA_BCNT_ENAB ;
if ( ! can_do_burst32 & & can_do_burst16 ) {
tmp | = DMA_ESC_BURST ;
} else {
tmp & = ~ ( DMA_ESC_BURST ) ;
}
sbus_writel ( tmp , esp - > dregs + DMA_CSR ) ;
break ;
default :
break ;
} ;
ESP_INTSON ( esp - > dregs ) ;
}
/* Reset the ESP chip, _not_ the SCSI bus. */
static void __init esp_reset_esp ( struct esp * esp )
{
u8 family_code , version ;
int i ;
/* Now reset the ESP chip */
esp_cmd ( esp , ESP_CMD_RC ) ;
esp_cmd ( esp , ESP_CMD_NULL | ESP_CMD_DMA ) ;
esp_cmd ( esp , ESP_CMD_NULL | ESP_CMD_DMA ) ;
/* Reload the configuration registers */
sbus_writeb ( esp - > cfact , esp - > eregs + ESP_CFACT ) ;
esp - > prev_stp = 0 ;
sbus_writeb ( esp - > prev_stp , esp - > eregs + ESP_STP ) ;
esp - > prev_soff = 0 ;
sbus_writeb ( esp - > prev_soff , esp - > eregs + ESP_SOFF ) ;
sbus_writeb ( esp - > neg_defp , esp - > eregs + ESP_TIMEO ) ;
/* This is the only point at which it is reliable to read
* the ID - code for a fast ESP chip variants .
*/
esp - > max_period = ( ( 35 * esp - > ccycle ) / 1000 ) ;
if ( esp - > erev = = fast ) {
version = sbus_readb ( esp - > eregs + ESP_UID ) ;
family_code = ( version & 0xf8 ) > > 3 ;
if ( family_code = = 0x02 )
esp - > erev = fas236 ;
else if ( family_code = = 0x0a )
esp - > erev = fashme ; /* Version is usually '5'. */
else
esp - > erev = fas100a ;
ESPMISC ( ( " esp%d: FAST chip is %s (family=%d, version=%d) \n " ,
esp - > esp_id ,
( esp - > erev = = fas236 ) ? " fas236 " :
( ( esp - > erev = = fas100a ) ? " fas100a " :
" fasHME " ) , family_code , ( version & 7 ) ) ) ;
esp - > min_period = ( ( 4 * esp - > ccycle ) / 1000 ) ;
} else {
esp - > min_period = ( ( 5 * esp - > ccycle ) / 1000 ) ;
}
esp - > max_period = ( esp - > max_period + 3 ) > > 2 ;
esp - > min_period = ( esp - > min_period + 3 ) > > 2 ;
sbus_writeb ( esp - > config1 , esp - > eregs + ESP_CFG1 ) ;
switch ( esp - > erev ) {
case esp100 :
/* nothing to do */
break ;
case esp100a :
sbus_writeb ( esp - > config2 , esp - > eregs + ESP_CFG2 ) ;
break ;
case esp236 :
/* Slow 236 */
sbus_writeb ( esp - > config2 , esp - > eregs + ESP_CFG2 ) ;
esp - > prev_cfg3 = esp - > config3 [ 0 ] ;
sbus_writeb ( esp - > prev_cfg3 , esp - > eregs + ESP_CFG3 ) ;
break ;
case fashme :
esp - > config2 | = ( ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB ) ;
/* fallthrough... */
case fas236 :
/* Fast 236 or HME */
sbus_writeb ( esp - > config2 , esp - > eregs + ESP_CFG2 ) ;
for ( i = 0 ; i < 16 ; i + + ) {
if ( esp - > erev = = fashme ) {
u8 cfg3 ;
cfg3 = ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH ;
if ( esp - > scsi_id > = 8 )
cfg3 | = ESP_CONFIG3_IDBIT3 ;
esp - > config3 [ i ] | = cfg3 ;
} else {
esp - > config3 [ i ] | = ESP_CONFIG3_FCLK ;
}
}
esp - > prev_cfg3 = esp - > config3 [ 0 ] ;
sbus_writeb ( esp - > prev_cfg3 , esp - > eregs + ESP_CFG3 ) ;
if ( esp - > erev = = fashme ) {
esp - > radelay = 80 ;
} else {
if ( esp - > diff )
esp - > radelay = 0 ;
else
esp - > radelay = 96 ;
}
break ;
case fas100a :
/* Fast 100a */
sbus_writeb ( esp - > config2 , esp - > eregs + ESP_CFG2 ) ;
for ( i = 0 ; i < 16 ; i + + )
esp - > config3 [ i ] | = ESP_CONFIG3_FCLOCK ;
esp - > prev_cfg3 = esp - > config3 [ 0 ] ;
sbus_writeb ( esp - > prev_cfg3 , esp - > eregs + ESP_CFG3 ) ;
esp - > radelay = 32 ;
break ;
default :
panic ( " esp: what could it be... I wonder... " ) ;
break ;
} ;
/* Eat any bitrot in the chip */
sbus_readb ( esp - > eregs + ESP_INTRPT ) ;
udelay ( 100 ) ;
}
/* This places the ESP into a known state at boot time. */
static void __init esp_bootup_reset ( struct esp * esp )
{
u8 tmp ;
/* Reset the DMA */
esp_reset_dma ( esp ) ;
/* Reset the ESP */
esp_reset_esp ( esp ) ;
/* Reset the SCSI bus, but tell ESP not to generate an irq */
tmp = sbus_readb ( esp - > eregs + ESP_CFG1 ) ;
tmp | = ESP_CONFIG1_SRRDISAB ;
sbus_writeb ( tmp , esp - > eregs + ESP_CFG1 ) ;
esp_cmd ( esp , ESP_CMD_RS ) ;
udelay ( 400 ) ;
sbus_writeb ( esp - > config1 , esp - > eregs + ESP_CFG1 ) ;
/* Eat any bitrot in the chip and we are done... */
sbus_readb ( esp - > eregs + ESP_INTRPT ) ;
}
static void esp_chain_add ( struct esp * esp )
{
spin_lock_irq ( & espchain_lock ) ;
if ( espchain ) {
struct esp * elink = espchain ;
while ( elink - > next )
elink = elink - > next ;
elink - > next = esp ;
} else {
espchain = esp ;
}
esp - > next = NULL ;
spin_unlock_irq ( & espchain_lock ) ;
}
static void esp_chain_del ( struct esp * esp )
{
spin_lock_irq ( & espchain_lock ) ;
if ( espchain = = esp ) {
espchain = esp - > next ;
} else {
struct esp * elink = espchain ;
while ( elink - > next ! = esp )
elink = elink - > next ;
elink - > next = esp - > next ;
}
esp - > next = NULL ;
spin_unlock_irq ( & espchain_lock ) ;
}
static int __init esp_find_dvma ( struct esp * esp , struct sbus_dev * dma_sdev )
{
struct sbus_dev * sdev = esp - > sdev ;
struct sbus_dma * dma ;
if ( dma_sdev ! = NULL ) {
for_each_dvma ( dma ) {
if ( dma - > sdev = = dma_sdev )
break ;
}
} else {
for_each_dvma ( dma ) {
/* If allocated already, can't use it. */
if ( dma - > allocated )
continue ;
if ( dma - > sdev = = NULL )
break ;
/* If bus + slot are the same and it has the
* correct OBP name , it ' s ours .
*/
if ( sdev - > bus = = dma - > sdev - > bus & &
sdev - > slot = = dma - > sdev - > slot & &
( ! strcmp ( dma - > sdev - > prom_name , " dma " ) | |
! strcmp ( dma - > sdev - > prom_name , " espdma " ) ) )
break ;
}
}
/* If we don't know how to handle the dvma,
* do not use this device .
*/
if ( dma = = NULL ) {
printk ( " Cannot find dvma for ESP%d's SCSI \n " , esp - > esp_id ) ;
return - 1 ;
}
if ( dma - > allocated ) {
printk ( " esp%d: can't use my espdma \n " , esp - > esp_id ) ;
return - 1 ;
}
dma - > allocated = 1 ;
esp - > dma = dma ;
esp - > dregs = dma - > regs ;
return 0 ;
}
static int __init esp_map_regs ( struct esp * esp , int hme )
{
struct sbus_dev * sdev = esp - > sdev ;
struct resource * res ;
/* On HME, two reg sets exist, first is DVMA,
* second is ESP registers .
*/
if ( hme )
res = & sdev - > resource [ 1 ] ;
else
res = & sdev - > resource [ 0 ] ;
esp - > eregs = sbus_ioremap ( res , 0 , ESP_REG_SIZE , " ESP Registers " ) ;
if ( esp - > eregs = = 0 )
return - 1 ;
return 0 ;
}
static int __init esp_map_cmdarea ( struct esp * esp )
{
struct sbus_dev * sdev = esp - > sdev ;
esp - > esp_command = sbus_alloc_consistent ( sdev , 16 ,
& esp - > esp_command_dvma ) ;
if ( esp - > esp_command = = NULL | |
esp - > esp_command_dvma = = 0 )
return - 1 ;
return 0 ;
}
static int __init esp_register_irq ( struct esp * esp )
{
esp - > ehost - > irq = esp - > irq = esp - > sdev - > irqs [ 0 ] ;
/* We used to try various overly-clever things to
* reduce the interrupt processing overhead on
* sun4c / sun4m when multiple ESP ' s shared the
* same IRQ . It was too complex and messy to
* sanely maintain .
*/
if ( request_irq ( esp - > ehost - > irq , esp_intr ,
SA_SHIRQ , " ESP SCSI " , esp ) ) {
printk ( " esp%d: Cannot acquire irq line \n " ,
esp - > esp_id ) ;
return - 1 ;
}
printk ( " esp%d: IRQ %s " , esp - > esp_id ,
__irq_itoa ( esp - > ehost - > irq ) ) ;
return 0 ;
}
static void __init esp_get_scsi_id ( struct esp * esp )
{
struct sbus_dev * sdev = esp - > sdev ;
esp - > scsi_id = prom_getintdefault ( esp - > prom_node ,
" initiator-id " ,
- 1 ) ;
if ( esp - > scsi_id = = - 1 )
esp - > scsi_id = prom_getintdefault ( esp - > prom_node ,
" scsi-initiator-id " ,
- 1 ) ;
if ( esp - > scsi_id = = - 1 )
esp - > scsi_id = ( sdev - > bus = = NULL ) ? 7 :
prom_getintdefault ( sdev - > bus - > prom_node ,
" scsi-initiator-id " ,
7 ) ;
esp - > ehost - > this_id = esp - > scsi_id ;
esp - > scsi_id_mask = ( 1 < < esp - > scsi_id ) ;
}
static void __init esp_get_clock_params ( struct esp * esp )
{
struct sbus_dev * sdev = esp - > sdev ;
int prom_node = esp - > prom_node ;
int sbus_prom_node ;
unsigned int fmhz ;
u8 ccf ;
if ( sdev ! = NULL & & sdev - > bus ! = NULL )
sbus_prom_node = sdev - > bus - > prom_node ;
else
sbus_prom_node = 0 ;
/* This is getting messy but it has to be done
* correctly or else you get weird behavior all
* over the place . We are trying to basically
* figure out three pieces of information .
*
* a ) Clock Conversion Factor
*
* This is a representation of the input
* crystal clock frequency going into the
* ESP on this machine . Any operation whose
* timing is longer than 400 ns depends on this
* value being correct . For example , you ' ll
* get blips for arbitration / selection during
* high load or with multiple targets if this
* is not set correctly .
*
* b ) Selection Time - Out
*
* The ESP isn ' t very bright and will arbitrate
* for the bus and try to select a target
* forever if you let it . This value tells
* the ESP when it has taken too long to
* negotiate and that it should interrupt
* the CPU so we can see what happened .
* The value is computed as follows ( from
* NCR / Symbios chip docs ) .
*
* ( Time Out Period ) * ( Input Clock )
* STO = - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* ( 8192 ) * ( Clock Conversion Factor )
*
* You usually want the time out period to be
* around 250 ms , I think we ' ll set it a little
* bit higher to account for fully loaded SCSI
* bus ' s and slow devices that don ' t respond so
* quickly to selection attempts . ( yeah , I know
* this is out of spec . but there is a lot of
* buggy pieces of firmware out there so bite me )
*
* c ) Imperical constants for synchronous offset
* and transfer period register values
*
* This entails the smallest and largest sync
* period we could ever handle on this ESP .
*/
fmhz = prom_getintdefault ( prom_node , " clock-frequency " , - 1 ) ;
if ( fmhz = = - 1 )
fmhz = ( ! sbus_prom_node ) ? 0 :
prom_getintdefault ( sbus_prom_node , " clock-frequency " , - 1 ) ;
if ( fmhz < = ( 5000000 ) )
ccf = 0 ;
else
ccf = ( ( ( 5000000 - 1 ) + ( fmhz ) ) / ( 5000000 ) ) ;
if ( ! ccf | | ccf > 8 ) {
/* If we can't find anything reasonable,
* just assume 20 MHZ . This is the clock
* frequency of the older sun4c ' s where I ' ve
* been unable to find the clock - frequency
* PROM property . All other machines provide
* useful values it seems .
*/
ccf = ESP_CCF_F4 ;
fmhz = ( 20000000 ) ;
}
if ( ccf = = ( ESP_CCF_F7 + 1 ) )
esp - > cfact = ESP_CCF_F0 ;
else if ( ccf = = ESP_CCF_NEVER )
esp - > cfact = ESP_CCF_F2 ;
else
esp - > cfact = ccf ;
esp - > raw_cfact = ccf ;
esp - > cfreq = fmhz ;
esp - > ccycle = ESP_MHZ_TO_CYCLE ( fmhz ) ;
esp - > ctick = ESP_TICK ( ccf , esp - > ccycle ) ;
esp - > neg_defp = ESP_NEG_DEFP ( fmhz , ccf ) ;
esp - > sync_defp = SYNC_DEFP_SLOW ;
printk ( " SCSI ID %d Clk %dMHz CCYC=%d CCF=%d TOut %d " ,
esp - > scsi_id , ( fmhz / 1000000 ) ,
( int ) esp - > ccycle , ( int ) ccf , ( int ) esp - > neg_defp ) ;
}
static void __init esp_get_bursts ( struct esp * esp , struct sbus_dev * dma )
{
struct sbus_dev * sdev = esp - > sdev ;
u8 bursts ;
bursts = prom_getintdefault ( esp - > prom_node , " burst-sizes " , 0xff ) ;
if ( dma ) {
u8 tmp = prom_getintdefault ( dma - > prom_node ,
" burst-sizes " , 0xff ) ;
if ( tmp ! = 0xff )
bursts & = tmp ;
}
if ( sdev - > bus ) {
u8 tmp = prom_getintdefault ( sdev - > bus - > prom_node ,
" burst-sizes " , 0xff ) ;
if ( tmp ! = 0xff )
bursts & = tmp ;
}
if ( bursts = = 0xff | |
( bursts & DMA_BURST16 ) = = 0 | |
( bursts & DMA_BURST32 ) = = 0 )
bursts = ( DMA_BURST32 - 1 ) ;
esp - > bursts = bursts ;
}
static void __init esp_get_revision ( struct esp * esp )
{
u8 tmp ;
esp - > config1 = ( ESP_CONFIG1_PENABLE | ( esp - > scsi_id & 7 ) ) ;
esp - > config2 = ( ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY ) ;
sbus_writeb ( esp - > config2 , esp - > eregs + ESP_CFG2 ) ;
tmp = sbus_readb ( esp - > eregs + ESP_CFG2 ) ;
tmp & = ~ ESP_CONFIG2_MAGIC ;
if ( tmp ! = ( ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY ) ) {
/* If what we write to cfg2 does not come back, cfg2
* is not implemented , therefore this must be a plain
* esp100 .
*/
esp - > erev = esp100 ;
printk ( " NCR53C90(esp100) \n " ) ;
} else {
esp - > config2 = 0 ;
esp - > prev_cfg3 = esp - > config3 [ 0 ] = 5 ;
sbus_writeb ( esp - > config2 , esp - > eregs + ESP_CFG2 ) ;
sbus_writeb ( 0 , esp - > eregs + ESP_CFG3 ) ;
sbus_writeb ( esp - > prev_cfg3 , esp - > eregs + ESP_CFG3 ) ;
tmp = sbus_readb ( esp - > eregs + ESP_CFG3 ) ;
if ( tmp ! = 5 ) {
/* The cfg2 register is implemented, however
* cfg3 is not , must be esp100a .
*/
esp - > erev = esp100a ;
printk ( " NCR53C90A(esp100a) \n " ) ;
} else {
int target ;
for ( target = 0 ; target < 16 ; target + + )
esp - > config3 [ target ] = 0 ;
esp - > prev_cfg3 = 0 ;
sbus_writeb ( esp - > prev_cfg3 , esp - > eregs + ESP_CFG3 ) ;
/* All of cfg{1,2,3} implemented, must be one of
* the fas variants , figure out which one .
*/
if ( esp - > raw_cfact > ESP_CCF_F5 ) {
esp - > erev = fast ;
esp - > sync_defp = SYNC_DEFP_FAST ;
printk ( " NCR53C9XF(espfast) \n " ) ;
} else {
esp - > erev = esp236 ;
printk ( " NCR53C9x(esp236) \n " ) ;
}
esp - > config2 = 0 ;
sbus_writeb ( esp - > config2 , esp - > eregs + ESP_CFG2 ) ;
}
}
}
static void __init esp_init_swstate ( struct esp * esp )
{
int i ;
/* Command queues... */
esp - > current_SC = NULL ;
esp - > disconnected_SC = NULL ;
esp - > issue_SC = NULL ;
/* Target and current command state... */
esp - > targets_present = 0 ;
esp - > resetting_bus = 0 ;
esp - > snip = 0 ;
init_waitqueue_head ( & esp - > reset_queue ) ;
/* Debugging... */
for ( i = 0 ; i < 32 ; i + + )
esp - > espcmdlog [ i ] = 0 ;
esp - > espcmdent = 0 ;
/* MSG phase state... */
for ( i = 0 ; i < 16 ; i + + ) {
esp - > cur_msgout [ i ] = 0 ;
esp - > cur_msgin [ i ] = 0 ;
}
esp - > prevmsgout = esp - > prevmsgin = 0 ;
esp - > msgout_len = esp - > msgin_len = 0 ;
/* Clear the one behind caches to hold unmatchable values. */
esp - > prev_soff = esp - > prev_stp = esp - > prev_cfg3 = 0xff ;
esp - > prev_hme_dmacsr = 0xffffffff ;
}
static int __init detect_one_esp ( struct scsi_host_template * tpnt , struct sbus_dev * esp_dev ,
struct sbus_dev * espdma , struct sbus_bus * sbus ,
int id , int hme )
{
struct Scsi_Host * esp_host = scsi_register ( tpnt , sizeof ( struct esp ) ) ;
struct esp * esp ;
if ( ! esp_host ) {
printk ( " ESP: Cannot register SCSI host \n " ) ;
return - 1 ;
}
if ( hme )
esp_host - > max_id = 16 ;
esp = ( struct esp * ) esp_host - > hostdata ;
esp - > ehost = esp_host ;
esp - > sdev = esp_dev ;
esp - > esp_id = id ;
esp - > prom_node = esp_dev - > prom_node ;
prom_getstring ( esp - > prom_node , " name " , esp - > prom_name ,
sizeof ( esp - > prom_name ) ) ;
esp_chain_add ( esp ) ;
if ( esp_find_dvma ( esp , espdma ) < 0 )
goto fail_unlink ;
if ( esp_map_regs ( esp , hme ) < 0 ) {
printk ( " ESP registers unmappable " ) ;
goto fail_dvma_release ;
}
if ( esp_map_cmdarea ( esp ) < 0 ) {
printk ( " ESP DVMA transport area unmappable " ) ;
goto fail_unmap_regs ;
}
if ( esp_register_irq ( esp ) < 0 )
goto fail_unmap_cmdarea ;
esp_get_scsi_id ( esp ) ;
esp - > diff = prom_getbool ( esp - > prom_node , " differential " ) ;
if ( esp - > diff )
printk ( " Differential " ) ;
esp_get_clock_params ( esp ) ;
esp_get_bursts ( esp , espdma ) ;
esp_get_revision ( esp ) ;
esp_init_swstate ( esp ) ;
esp_bootup_reset ( esp ) ;
return 0 ;
fail_unmap_cmdarea :
sbus_free_consistent ( esp - > sdev , 16 ,
( void * ) esp - > esp_command ,
esp - > esp_command_dvma ) ;
fail_unmap_regs :
sbus_iounmap ( esp - > eregs , ESP_REG_SIZE ) ;
fail_dvma_release :
esp - > dma - > allocated = 0 ;
fail_unlink :
esp_chain_del ( esp ) ;
scsi_unregister ( esp_host ) ;
return - 1 ;
}
/* Detecting ESP chips on the machine. This is the simple and easy
* version .
*/
# ifdef CONFIG_SUN4
# include <asm/sun4paddr.h>
static int __init esp_detect ( struct scsi_host_template * tpnt )
{
static struct sbus_dev esp_dev ;
int esps_in_use = 0 ;
2005-04-26 18:43:42 +04:00
espchain = NULL ;
2005-04-17 02:20:36 +04:00
if ( sun4_esp_physaddr ) {
memset ( & esp_dev , 0 , sizeof ( esp_dev ) ) ;
esp_dev . reg_addrs [ 0 ] . phys_addr = sun4_esp_physaddr ;
esp_dev . irqs [ 0 ] = 4 ;
esp_dev . resource [ 0 ] . start = sun4_esp_physaddr ;
esp_dev . resource [ 0 ] . end = sun4_esp_physaddr + ESP_REG_SIZE - 1 ;
esp_dev . resource [ 0 ] . flags = IORESOURCE_IO ;
if ( ! detect_one_esp ( tpnt , & esp_dev , NULL , NULL , 0 , 0 ) )
esps_in_use + + ;
printk ( " ESP: Total of 1 ESP hosts found, %d actually in use. \n " , esps_in_use ) ;
esps_running = esps_in_use ;
}
return esps_in_use ;
}
# else /* !CONFIG_SUN4 */
static int __init esp_detect ( struct scsi_host_template * tpnt )
{
struct sbus_bus * sbus ;
struct sbus_dev * esp_dev , * sbdev_iter ;
int nesps = 0 , esps_in_use = 0 ;
espchain = 0 ;
if ( ! sbus_root ) {
# ifdef CONFIG_PCI
return 0 ;
# else
panic ( " No SBUS in esp_detect() " ) ;
# endif
}
for_each_sbus ( sbus ) {
for_each_sbusdev ( sbdev_iter , sbus ) {
struct sbus_dev * espdma = NULL ;
int hme = 0 ;
/* Is it an esp sbus device? */
esp_dev = sbdev_iter ;
if ( strcmp ( esp_dev - > prom_name , " esp " ) & &
strcmp ( esp_dev - > prom_name , " SUNW,esp " ) ) {
if ( ! strcmp ( esp_dev - > prom_name , " SUNW,fas " ) ) {
hme = 1 ;
espdma = esp_dev ;
} else {
if ( ! esp_dev - > child | |
( strcmp ( esp_dev - > prom_name , " espdma " ) & &
strcmp ( esp_dev - > prom_name , " dma " ) ) )
continue ; /* nope... */
espdma = esp_dev ;
esp_dev = esp_dev - > child ;
if ( strcmp ( esp_dev - > prom_name , " esp " ) & &
strcmp ( esp_dev - > prom_name , " SUNW,esp " ) )
continue ; /* how can this happen? */
}
}
if ( detect_one_esp ( tpnt , esp_dev , espdma , sbus , nesps + + , hme ) < 0 )
continue ;
esps_in_use + + ;
} /* for each sbusdev */
} /* for each sbus */
printk ( " ESP: Total of %d ESP hosts found, %d actually in use. \n " , nesps ,
esps_in_use ) ;
esps_running = esps_in_use ;
return esps_in_use ;
}
# endif /* !CONFIG_SUN4 */
/*
*/
static int esp_release ( struct Scsi_Host * host )
{
struct esp * esp = ( struct esp * ) host - > hostdata ;
ESP_INTSOFF ( esp - > dregs ) ;
#if 0
esp_reset_dma ( esp ) ;
esp_reset_esp ( esp ) ;
# endif
free_irq ( esp - > ehost - > irq , esp ) ;
sbus_free_consistent ( esp - > sdev , 16 ,
( void * ) esp - > esp_command , esp - > esp_command_dvma ) ;
sbus_iounmap ( esp - > eregs , ESP_REG_SIZE ) ;
esp - > dma - > allocated = 0 ;
esp_chain_del ( esp ) ;
return 0 ;
}
/* The info function will return whatever useful
* information the developer sees fit . If not provided , then
* the name field will be used instead .
*/
static const char * esp_info ( struct Scsi_Host * host )
{
struct esp * esp ;
esp = ( struct esp * ) host - > hostdata ;
switch ( esp - > erev ) {
case esp100 :
return " Sparc ESP100 (NCR53C90) " ;
case esp100a :
return " Sparc ESP100A (NCR53C90A) " ;
case esp236 :
return " Sparc ESP236 " ;
case fas236 :
return " Sparc ESP236-FAST " ;
case fashme :
return " Sparc ESP366-HME " ;
case fas100a :
return " Sparc ESP100A-FAST " ;
default :
return " Bogon ESP revision " ;
} ;
}
/* From Wolfgang Stanglmeier's NCR scsi driver. */
struct info_str
{
char * buffer ;
int length ;
int offset ;
int pos ;
} ;
static void copy_mem_info ( struct info_str * info , char * data , int len )
{
if ( info - > pos + len > info - > length )
len = info - > length - info - > pos ;
if ( info - > pos + len < info - > offset ) {
info - > pos + = len ;
return ;
}
if ( info - > pos < info - > offset ) {
data + = ( info - > offset - info - > pos ) ;
len - = ( info - > offset - info - > pos ) ;
}
if ( len > 0 ) {
memcpy ( info - > buffer + info - > pos , data , len ) ;
info - > pos + = len ;
}
}
static int copy_info ( struct info_str * info , char * fmt , . . . )
{
va_list args ;
char buf [ 81 ] ;
int len ;
va_start ( args , fmt ) ;
len = vsprintf ( buf , fmt , args ) ;
va_end ( args ) ;
copy_mem_info ( info , buf , len ) ;
return len ;
}
static int esp_host_info ( struct esp * esp , char * ptr , off_t offset , int len )
{
struct scsi_device * sdev ;
struct info_str info ;
int i ;
info . buffer = ptr ;
info . length = len ;
info . offset = offset ;
info . pos = 0 ;
copy_info ( & info , " Sparc ESP Host Adapter: \n " ) ;
copy_info ( & info , " \t PROM node \t \t %08x \n " , ( unsigned int ) esp - > prom_node ) ;
copy_info ( & info , " \t PROM name \t \t %s \n " , esp - > prom_name ) ;
copy_info ( & info , " \t ESP Model \t \t " ) ;
switch ( esp - > erev ) {
case esp100 :
copy_info ( & info , " ESP100 \n " ) ;
break ;
case esp100a :
copy_info ( & info , " ESP100A \n " ) ;
break ;
case esp236 :
copy_info ( & info , " ESP236 \n " ) ;
break ;
case fas236 :
copy_info ( & info , " FAS236 \n " ) ;
break ;
case fas100a :
copy_info ( & info , " FAS100A \n " ) ;
break ;
case fast :
copy_info ( & info , " FAST \n " ) ;
break ;
case fashme :
copy_info ( & info , " Happy Meal FAS \n " ) ;
break ;
case espunknown :
default :
copy_info ( & info , " Unknown! \n " ) ;
break ;
} ;
copy_info ( & info , " \t DMA Revision \t \t " ) ;
switch ( esp - > dma - > revision ) {
case dvmarev0 :
copy_info ( & info , " Rev 0 \n " ) ;
break ;
case dvmaesc1 :
copy_info ( & info , " ESC Rev 1 \n " ) ;
break ;
case dvmarev1 :
copy_info ( & info , " Rev 1 \n " ) ;
break ;
case dvmarev2 :
copy_info ( & info , " Rev 2 \n " ) ;
break ;
case dvmarev3 :
copy_info ( & info , " Rev 3 \n " ) ;
break ;
case dvmarevplus :
copy_info ( & info , " Rev 1+ \n " ) ;
break ;
case dvmahme :
copy_info ( & info , " Rev HME/FAS \n " ) ;
break ;
default :
copy_info ( & info , " Unknown! \n " ) ;
break ;
} ;
copy_info ( & info , " \t Live Targets \t \t [ " ) ;
for ( i = 0 ; i < 15 ; i + + ) {
if ( esp - > targets_present & ( 1 < < i ) )
copy_info ( & info , " %d " , i ) ;
}
copy_info ( & info , " ] \n \n " ) ;
/* Now describe the state of each existing target. */
copy_info ( & info , " Target # \t config3 \t \t Sync Capabilities \t Disconnect \t Wide \n " ) ;
shost_for_each_device ( sdev , esp - > ehost ) {
struct esp_device * esp_dev = sdev - > hostdata ;
uint id = sdev - > id ;
if ( ! ( esp - > targets_present & ( 1 < < id ) ) )
continue ;
copy_info ( & info , " %d \t \t " , id ) ;
copy_info ( & info , " %08lx \t " , esp - > config3 [ id ] ) ;
copy_info ( & info , " [%02lx,%02lx] \t \t \t " ,
esp_dev - > sync_max_offset ,
esp_dev - > sync_min_period ) ;
copy_info ( & info , " %s \t \t " ,
esp_dev - > disconnect ? " yes " : " no " ) ;
copy_info ( & info , " %s \n " ,
( esp - > config3 [ id ] & ESP_CONFIG3_EWIDE ) ? " yes " : " no " ) ;
}
return info . pos > info . offset ? info . pos - info . offset : 0 ;
}
/* ESP proc filesystem code. */
static int esp_proc_info ( struct Scsi_Host * host , char * buffer , char * * start , off_t offset ,
int length , int inout )
{
struct esp * esp ;
if ( inout )
return - EINVAL ; /* not yet */
for_each_esp ( esp ) {
if ( esp - > ehost = = host )
break ;
}
if ( ! esp )
return - EINVAL ;
if ( start )
* start = buffer ;
return esp_host_info ( esp , buffer , offset , length ) ;
}
static void esp_get_dmabufs ( struct esp * esp , struct scsi_cmnd * sp )
{
if ( sp - > use_sg = = 0 ) {
sp - > SCp . this_residual = sp - > request_bufflen ;
sp - > SCp . buffer = ( struct scatterlist * ) sp - > request_buffer ;
sp - > SCp . buffers_residual = 0 ;
if ( sp - > request_bufflen ) {
sp - > SCp . have_data_in = sbus_map_single ( esp - > sdev , sp - > SCp . buffer ,
sp - > SCp . this_residual ,
sp - > sc_data_direction ) ;
sp - > SCp . ptr = ( char * ) ( ( unsigned long ) sp - > SCp . have_data_in ) ;
} else {
sp - > SCp . ptr = NULL ;
}
} else {
sp - > SCp . buffer = ( struct scatterlist * ) sp - > buffer ;
sp - > SCp . buffers_residual = sbus_map_sg ( esp - > sdev ,
sp - > SCp . buffer ,
sp - > use_sg ,
sp - > sc_data_direction ) ;
sp - > SCp . this_residual = sg_dma_len ( sp - > SCp . buffer ) ;
sp - > SCp . ptr = ( char * ) ( ( unsigned long ) sg_dma_address ( sp - > SCp . buffer ) ) ;
}
}
static void esp_release_dmabufs ( struct esp * esp , struct scsi_cmnd * sp )
{
if ( sp - > use_sg ) {
sbus_unmap_sg ( esp - > sdev , sp - > buffer , sp - > use_sg ,
sp - > sc_data_direction ) ;
} else if ( sp - > request_bufflen ) {
sbus_unmap_single ( esp - > sdev ,
sp - > SCp . have_data_in ,
sp - > request_bufflen ,
sp - > sc_data_direction ) ;
}
}
static void esp_restore_pointers ( struct esp * esp , struct scsi_cmnd * sp )
{
struct esp_pointers * ep = & esp - > data_pointers [ sp - > device - > id ] ;
sp - > SCp . ptr = ep - > saved_ptr ;
sp - > SCp . buffer = ep - > saved_buffer ;
sp - > SCp . this_residual = ep - > saved_this_residual ;
sp - > SCp . buffers_residual = ep - > saved_buffers_residual ;
}
static void esp_save_pointers ( struct esp * esp , struct scsi_cmnd * sp )
{
struct esp_pointers * ep = & esp - > data_pointers [ sp - > device - > id ] ;
ep - > saved_ptr = sp - > SCp . ptr ;
ep - > saved_buffer = sp - > SCp . buffer ;
ep - > saved_this_residual = sp - > SCp . this_residual ;
ep - > saved_buffers_residual = sp - > SCp . buffers_residual ;
}
/* Some rules:
*
* 1 ) Never ever panic while something is live on the bus .
* If there is to be any chance of syncing the disks this
* rule is to be obeyed .
*
* 2 ) Any target that causes a foul condition will no longer
* have synchronous transfers done to it , no questions
* asked .
*
* 3 ) Keep register accesses to a minimum . Think about some
* day when we have Xbus machines this is running on and
* the ESP chip is on the other end of the machine on a
* different board from the cpu where this is running .
*/
/* Fire off a command. We assume the bus is free and that the only
* case where we could see an interrupt is where we have disconnected
* commands active and they are trying to reselect us .
*/
static inline void esp_check_cmd ( struct esp * esp , struct scsi_cmnd * sp )
{
switch ( sp - > cmd_len ) {
case 6 :
case 10 :
case 12 :
esp - > esp_slowcmd = 0 ;
break ;
default :
esp - > esp_slowcmd = 1 ;
esp - > esp_scmdleft = sp - > cmd_len ;
esp - > esp_scmdp = & sp - > cmnd [ 0 ] ;
break ;
} ;
}
static inline void build_sync_nego_msg ( struct esp * esp , int period , int offset )
{
esp - > cur_msgout [ 0 ] = EXTENDED_MESSAGE ;
esp - > cur_msgout [ 1 ] = 3 ;
esp - > cur_msgout [ 2 ] = EXTENDED_SDTR ;
esp - > cur_msgout [ 3 ] = period ;
esp - > cur_msgout [ 4 ] = offset ;
esp - > msgout_len = 5 ;
}
/* SIZE is in bits, currently HME only supports 16 bit wide transfers. */
static inline void build_wide_nego_msg ( struct esp * esp , int size )
{
esp - > cur_msgout [ 0 ] = EXTENDED_MESSAGE ;
esp - > cur_msgout [ 1 ] = 2 ;
esp - > cur_msgout [ 2 ] = EXTENDED_WDTR ;
switch ( size ) {
case 32 :
esp - > cur_msgout [ 3 ] = 2 ;
break ;
case 16 :
esp - > cur_msgout [ 3 ] = 1 ;
break ;
case 8 :
default :
esp - > cur_msgout [ 3 ] = 0 ;
break ;
} ;
esp - > msgout_len = 4 ;
}
static void esp_exec_cmd ( struct esp * esp )
{
struct scsi_cmnd * SCptr ;
struct scsi_device * SDptr ;
struct esp_device * esp_dev ;
volatile u8 * cmdp = esp - > esp_command ;
u8 the_esp_command ;
int lun , target ;
int i ;
/* Hold off if we have disconnected commands and
* an IRQ is showing . . .
*/
if ( esp - > disconnected_SC & & ESP_IRQ_P ( esp - > dregs ) )
return ;
/* Grab first member of the issue queue. */
SCptr = esp - > current_SC = remove_first_SC ( & esp - > issue_SC ) ;
/* Safe to panic here because current_SC is null. */
if ( ! SCptr )
panic ( " esp: esp_exec_cmd and issue queue is NULL " ) ;
SDptr = SCptr - > device ;
esp_dev = SDptr - > hostdata ;
lun = SCptr - > device - > lun ;
target = SCptr - > device - > id ;
esp - > snip = 0 ;
esp - > msgout_len = 0 ;
/* Send it out whole, or piece by piece? The ESP
* only knows how to automatically send out 6 , 10 ,
* and 12 byte commands . I used to think that the
* Linux SCSI code would never throw anything other
* than that to us , but then again there is the
* SCSI generic driver which can send us anything .
*/
esp_check_cmd ( esp , SCptr ) ;
/* If arbitration/selection is successful, the ESP will leave
* ATN asserted , causing the target to go into message out
* phase . The ESP will feed the target the identify and then
* the target can only legally go to one of command ,
* datain / out , status , or message in phase , or stay in message
* out phase ( should we be trying to send a sync negotiation
* message after the identify ) . It is not allowed to drop
* BSY , but some buggy targets do and we check for this
* condition in the selection complete code . Most of the time
* we ' ll make the command bytes available to the ESP and it
* will not interrupt us until it finishes command phase , we
* cannot do this for command sizes the ESP does not
* understand and in this case we ' ll get interrupted right
* when the target goes into command phase .
*
* It is absolutely _illegal_ in the presence of SCSI - 2 devices
* to use the ESP select w / o ATN command . When SCSI - 2 devices are
* present on the bus we _must_ always go straight to message out
* phase with an identify message for the target . Being that
* selection attempts in SCSI - 1 w / o ATN was an option , doing SCSI - 2
* selections should not confuse SCSI - 1 we hope .
*/
if ( esp_dev - > sync ) {
/* this targets sync is known */
# ifndef __sparc_v9__
do_sync_known :
# endif
if ( esp_dev - > disconnect )
* cmdp + + = IDENTIFY ( 1 , lun ) ;
else
* cmdp + + = IDENTIFY ( 0 , lun ) ;
if ( esp - > esp_slowcmd ) {
the_esp_command = ( ESP_CMD_SELAS | ESP_CMD_DMA ) ;
esp_advance_phase ( SCptr , in_slct_stop ) ;
} else {
the_esp_command = ( ESP_CMD_SELA | ESP_CMD_DMA ) ;
esp_advance_phase ( SCptr , in_slct_norm ) ;
}
} else if ( ! ( esp - > targets_present & ( 1 < < target ) ) | | ! ( esp_dev - > disconnect ) ) {
/* After the bootup SCSI code sends both the
* TEST_UNIT_READY and INQUIRY commands we want
* to at least attempt allowing the device to
* disconnect .
*/
ESPMISC ( ( " esp: Selecting device for first time. target=%d "
" lun=%d \n " , target , SCptr - > device - > lun ) ) ;
if ( ! SDptr - > borken & & ! esp_dev - > disconnect )
esp_dev - > disconnect = 1 ;
* cmdp + + = IDENTIFY ( 0 , lun ) ;
esp - > prevmsgout = NOP ;
esp_advance_phase ( SCptr , in_slct_norm ) ;
the_esp_command = ( ESP_CMD_SELA | ESP_CMD_DMA ) ;
/* Take no chances... */
esp_dev - > sync_max_offset = 0 ;
esp_dev - > sync_min_period = 0 ;
} else {
/* Sorry, I have had way too many problems with
* various CDROM devices on ESP . - DaveM
*/
int cdrom_hwbug_wkaround = 0 ;
# ifndef __sparc_v9__
/* Never allow disconnects or synchronous transfers on
* SparcStation1 and SparcStation1 + . Allowing those
* to be enabled seems to lockup the machine completely .
*/
if ( ( idprom - > id_machtype = = ( SM_SUN4C | SM_4C_SS1 ) ) | |
( idprom - > id_machtype = = ( SM_SUN4C | SM_4C_SS1PLUS ) ) ) {
/* But we are nice and allow tapes and removable
* disks ( but not CDROMs ) to disconnect .
*/
if ( SDptr - > type = = TYPE_TAPE | |
( SDptr - > type ! = TYPE_ROM & & SDptr - > removable ) )
esp_dev - > disconnect = 1 ;
else
esp_dev - > disconnect = 0 ;
esp_dev - > sync_max_offset = 0 ;
esp_dev - > sync_min_period = 0 ;
esp_dev - > sync = 1 ;
esp - > snip = 0 ;
goto do_sync_known ;
}
# endif /* !(__sparc_v9__) */
/* We've talked to this guy before,
* but never negotiated . Let ' s try ,
* need to attempt WIDE first , before
* sync nego , as per SCSI 2 standard .
*/
if ( esp - > erev = = fashme & & ! esp_dev - > wide ) {
if ( ! SDptr - > borken & &
SDptr - > type ! = TYPE_ROM & &
SDptr - > removable = = 0 ) {
build_wide_nego_msg ( esp , 16 ) ;
esp_dev - > wide = 1 ;
esp - > wnip = 1 ;
goto after_nego_msg_built ;
} else {
esp_dev - > wide = 1 ;
/* Fall through and try sync. */
}
}
if ( ! SDptr - > borken ) {
if ( ( SDptr - > type = = TYPE_ROM ) ) {
/* Nice try sucker... */
ESPMISC ( ( " esp%d: Disabling sync for buggy "
" CDROM. \n " , esp - > esp_id ) ) ;
cdrom_hwbug_wkaround = 1 ;
build_sync_nego_msg ( esp , 0 , 0 ) ;
} else if ( SDptr - > removable ! = 0 ) {
ESPMISC ( ( " esp%d: Not negotiating sync/wide but "
" allowing disconnect for removable media. \n " ,
esp - > esp_id ) ) ;
build_sync_nego_msg ( esp , 0 , 0 ) ;
} else {
build_sync_nego_msg ( esp , esp - > sync_defp , 15 ) ;
}
} else {
build_sync_nego_msg ( esp , 0 , 0 ) ;
}
esp_dev - > sync = 1 ;
esp - > snip = 1 ;
after_nego_msg_built :
/* A fix for broken SCSI1 targets, when they disconnect
* they lock up the bus and confuse ESP . So disallow
* disconnects for SCSI1 targets for now until we
* find a better fix .
*
* Addendum : This is funny , I figured out what was going
* on . The blotzed SCSI1 target would disconnect ,
* one of the other SCSI2 targets or both would be
* disconnected as well . The SCSI1 target would
* stay disconnected long enough that we start
* up a command on one of the SCSI2 targets . As
* the ESP is arbitrating for the bus the SCSI1
* target begins to arbitrate as well to reselect
* the ESP . The SCSI1 target refuses to drop it ' s
* ID bit on the data bus even though the ESP is
* at ID 7 and is the obvious winner for any
* arbitration . The ESP is a poor sport and refuses
* to lose arbitration , it will continue indefinitely
* trying to arbitrate for the bus and can only be
* stopped via a chip reset or SCSI bus reset .
* Therefore _no_ disconnects for SCSI1 targets
* thank you very much . ; - )
*/
if ( ( ( SDptr - > scsi_level < 3 ) & &
( SDptr - > type ! = TYPE_TAPE ) & &
SDptr - > removable = = 0 ) | |
cdrom_hwbug_wkaround | | SDptr - > borken ) {
ESPMISC ( ( KERN_INFO " esp%d: Disabling DISCONNECT for target %d "
" lun %d \n " , esp - > esp_id , SCptr - > device - > id , SCptr - > device - > lun ) ) ;
esp_dev - > disconnect = 0 ;
* cmdp + + = IDENTIFY ( 0 , lun ) ;
} else {
* cmdp + + = IDENTIFY ( 1 , lun ) ;
}
/* ESP fifo is only so big...
* Make this look like a slow command .
*/
esp - > esp_slowcmd = 1 ;
esp - > esp_scmdleft = SCptr - > cmd_len ;
esp - > esp_scmdp = & SCptr - > cmnd [ 0 ] ;
the_esp_command = ( ESP_CMD_SELAS | ESP_CMD_DMA ) ;
esp_advance_phase ( SCptr , in_slct_msg ) ;
}
if ( ! esp - > esp_slowcmd )
for ( i = 0 ; i < SCptr - > cmd_len ; i + + )
* cmdp + + = SCptr - > cmnd [ i ] ;
/* HME sucks... */
if ( esp - > erev = = fashme )
sbus_writeb ( ( target & 0xf ) | ( ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT ) ,
esp - > eregs + ESP_BUSID ) ;
else
sbus_writeb ( target & 7 , esp - > eregs + ESP_BUSID ) ;
if ( esp - > prev_soff ! = esp_dev - > sync_max_offset | |
esp - > prev_stp ! = esp_dev - > sync_min_period | |
( esp - > erev > esp100a & &
esp - > prev_cfg3 ! = esp - > config3 [ target ] ) ) {
esp - > prev_soff = esp_dev - > sync_max_offset ;
esp - > prev_stp = esp_dev - > sync_min_period ;
sbus_writeb ( esp - > prev_soff , esp - > eregs + ESP_SOFF ) ;
sbus_writeb ( esp - > prev_stp , esp - > eregs + ESP_STP ) ;
if ( esp - > erev > esp100a ) {
esp - > prev_cfg3 = esp - > config3 [ target ] ;
sbus_writeb ( esp - > prev_cfg3 , esp - > eregs + ESP_CFG3 ) ;
}
}
i = ( cmdp - esp - > esp_command ) ;
if ( esp - > erev = = fashme ) {
esp_cmd ( esp , ESP_CMD_FLUSH ) ; /* Grrr! */
/* Set up the DMA and HME counters */
sbus_writeb ( i , esp - > eregs + ESP_TCLOW ) ;
sbus_writeb ( 0 , esp - > eregs + ESP_TCMED ) ;
sbus_writeb ( 0 , esp - > eregs + FAS_RLO ) ;
sbus_writeb ( 0 , esp - > eregs + FAS_RHI ) ;
esp_cmd ( esp , the_esp_command ) ;
/* Talk about touchy hardware... */
esp - > prev_hme_dmacsr = ( ( esp - > prev_hme_dmacsr |
( DMA_SCSI_DISAB | DMA_ENABLE ) ) &
~ ( DMA_ST_WRITE ) ) ;
sbus_writel ( 16 , esp - > dregs + DMA_COUNT ) ;
sbus_writel ( esp - > esp_command_dvma , esp - > dregs + DMA_ADDR ) ;
sbus_writel ( esp - > prev_hme_dmacsr , esp - > dregs + DMA_CSR ) ;
} else {
u32 tmp ;
/* Set up the DMA and ESP counters */
sbus_writeb ( i , esp - > eregs + ESP_TCLOW ) ;
sbus_writeb ( 0 , esp - > eregs + ESP_TCMED ) ;
tmp = sbus_readl ( esp - > dregs + DMA_CSR ) ;
tmp & = ~ DMA_ST_WRITE ;
tmp | = DMA_ENABLE ;
sbus_writel ( tmp , esp - > dregs + DMA_CSR ) ;
if ( esp - > dma - > revision = = dvmaesc1 ) {
if ( i ) /* Workaround ESC gate array SBUS rerun bug. */
sbus_writel ( PAGE_SIZE , esp - > dregs + DMA_COUNT ) ;
}
sbus_writel ( esp - > esp_command_dvma , esp - > dregs + DMA_ADDR ) ;
/* Tell ESP to "go". */
esp_cmd ( esp , the_esp_command ) ;
}
}
/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */
static int esp_queue ( struct scsi_cmnd * SCpnt , void ( * done ) ( struct scsi_cmnd * ) )
{
struct esp * esp ;
/* Set up func ptr and initial driver cmd-phase. */
SCpnt - > scsi_done = done ;
SCpnt - > SCp . phase = not_issued ;
/* We use the scratch area. */
ESPQUEUE ( ( " esp_queue: target=%d lun=%d " , SCpnt - > device - > id , SCpnt - > device - > lun ) ) ;
ESPDISC ( ( " N<%02x,%02x> " , SCpnt - > device - > id , SCpnt - > device - > lun ) ) ;
esp = ( struct esp * ) SCpnt - > device - > host - > hostdata ;
esp_get_dmabufs ( esp , SCpnt ) ;
esp_save_pointers ( esp , SCpnt ) ; /* FIXME for tag queueing */
SCpnt - > SCp . Status = CHECK_CONDITION ;
SCpnt - > SCp . Message = 0xff ;
SCpnt - > SCp . sent_command = 0 ;
/* Place into our queue. */
if ( SCpnt - > cmnd [ 0 ] = = REQUEST_SENSE ) {
ESPQUEUE ( ( " RQSENSE \n " ) ) ;
prepend_SC ( & esp - > issue_SC , SCpnt ) ;
} else {
ESPQUEUE ( ( " \n " ) ) ;
append_SC ( & esp - > issue_SC , SCpnt ) ;
}
/* Run it now if we can. */
if ( ! esp - > current_SC & & ! esp - > resetting_bus )
esp_exec_cmd ( esp ) ;
return 0 ;
}
/* Dump driver state. */
static void esp_dump_cmd ( struct scsi_cmnd * SCptr )
{
ESPLOG ( ( " [tgt<%02x> lun<%02x> "
" pphase<%s> cphase<%s>] " ,
SCptr - > device - > id , SCptr - > device - > lun ,
phase_string ( SCptr - > SCp . sent_command ) ,
phase_string ( SCptr - > SCp . phase ) ) ) ;
}
static void esp_dump_state ( struct esp * esp )
{
struct scsi_cmnd * SCptr = esp - > current_SC ;
# ifdef DEBUG_ESP_CMDS
int i ;
# endif
ESPLOG ( ( " esp%d: dumping state \n " , esp - > esp_id ) ) ;
ESPLOG ( ( " esp%d: dma -- cond_reg<%08x> addr<%08x> \n " ,
esp - > esp_id ,
sbus_readl ( esp - > dregs + DMA_CSR ) ,
sbus_readl ( esp - > dregs + DMA_ADDR ) ) ) ;
ESPLOG ( ( " esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>] \n " ,
esp - > esp_id , esp - > sreg , esp - > seqreg , esp - > ireg ) ) ;
ESPLOG ( ( " esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>] \n " ,
esp - > esp_id ,
sbus_readb ( esp - > eregs + ESP_STATUS ) ,
sbus_readb ( esp - > eregs + ESP_SSTEP ) ,
sbus_readb ( esp - > eregs + ESP_INTRPT ) ) ) ;
# ifdef DEBUG_ESP_CMDS
printk ( " esp%d: last ESP cmds [ " , esp - > esp_id ) ;
i = ( esp - > espcmdent - 1 ) & 31 ;
printk ( " < " ) ; esp_print_cmd ( esp - > espcmdlog [ i ] ) ; printk ( " > " ) ;
i = ( i - 1 ) & 31 ;
printk ( " < " ) ; esp_print_cmd ( esp - > espcmdlog [ i ] ) ; printk ( " > " ) ;
i = ( i - 1 ) & 31 ;
printk ( " < " ) ; esp_print_cmd ( esp - > espcmdlog [ i ] ) ; printk ( " > " ) ;
i = ( i - 1 ) & 31 ;
printk ( " < " ) ; esp_print_cmd ( esp - > espcmdlog [ i ] ) ; printk ( " > " ) ;
printk ( " ] \n " ) ;
# endif /* (DEBUG_ESP_CMDS) */
if ( SCptr ) {
ESPLOG ( ( " esp%d: current command " , esp - > esp_id ) ) ;
esp_dump_cmd ( SCptr ) ;
}
ESPLOG ( ( " \n " ) ) ;
SCptr = esp - > disconnected_SC ;
ESPLOG ( ( " esp%d: disconnected " , esp - > esp_id ) ) ;
while ( SCptr ) {
esp_dump_cmd ( SCptr ) ;
SCptr = ( struct scsi_cmnd * ) SCptr - > host_scribble ;
}
ESPLOG ( ( " \n " ) ) ;
}
/* Abort a command. The host_lock is acquired by caller. */
static int esp_abort ( struct scsi_cmnd * SCptr )
{
struct esp * esp = ( struct esp * ) SCptr - > device - > host - > hostdata ;
int don ;
ESPLOG ( ( " esp%d: Aborting command \n " , esp - > esp_id ) ) ;
esp_dump_state ( esp ) ;
/* Wheee, if this is the current command on the bus, the
* best we can do is assert ATN and wait for msgout phase .
* This should even fix a hung SCSI bus when we lose state
* in the driver and timeout because the eventual phase change
* will cause the ESP to ( eventually ) give an interrupt .
*/
if ( esp - > current_SC = = SCptr ) {
esp - > cur_msgout [ 0 ] = ABORT ;
esp - > msgout_len = 1 ;
esp - > msgout_ctr = 0 ;
esp_cmd ( esp , ESP_CMD_SATN ) ;
return SUCCESS ;
}
/* If it is still in the issue queue then we can safely
* call the completion routine and report abort success .
*/
don = ( sbus_readl ( esp - > dregs + DMA_CSR ) & DMA_INT_ENAB ) ;
if ( don ) {
ESP_INTSOFF ( esp - > dregs ) ;
}
if ( esp - > issue_SC ) {
struct scsi_cmnd * * prev , * this ;
for ( prev = ( & esp - > issue_SC ) , this = esp - > issue_SC ;
this ! = NULL ;
prev = ( struct scsi_cmnd * * ) & ( this - > host_scribble ) ,
this = ( struct scsi_cmnd * ) this - > host_scribble ) {
if ( this = = SCptr ) {
* prev = ( struct scsi_cmnd * ) this - > host_scribble ;
this - > host_scribble = NULL ;
esp_release_dmabufs ( esp , this ) ;
this - > result = DID_ABORT < < 16 ;
this - > scsi_done ( this ) ;
if ( don )
ESP_INTSON ( esp - > dregs ) ;
return SUCCESS ;
}
}
}
/* Yuck, the command to abort is disconnected, it is not
* worth trying to abort it now if something else is live
* on the bus at this time . So , we let the SCSI code wait
* a little bit and try again later .
*/
if ( esp - > current_SC ) {
if ( don )
ESP_INTSON ( esp - > dregs ) ;
return FAILED ;
}
/* It's disconnected, we have to reconnect to re-establish
* the nexus and tell the device to abort . However , we really
* cannot ' reconnect ' per se . Don ' t try to be fancy , just
* indicate failure , which causes our caller to reset the whole
* bus .
*/
if ( don )
ESP_INTSON ( esp - > dregs ) ;
return FAILED ;
}
/* We've sent ESP_CMD_RS to the ESP, the interrupt had just
* arrived indicating the end of the SCSI bus reset . Our job
* is to clean out the command queues and begin re - execution
* of SCSI commands once more .
*/
static int esp_finish_reset ( struct esp * esp )
{
struct scsi_cmnd * sp = esp - > current_SC ;
/* Clean up currently executing command, if any. */
if ( sp ! = NULL ) {
esp - > current_SC = NULL ;
esp_release_dmabufs ( esp , sp ) ;
sp - > result = ( DID_RESET < < 16 ) ;
sp - > scsi_done ( sp ) ;
}
/* Clean up disconnected queue, they have been invalidated
* by the bus reset .
*/
if ( esp - > disconnected_SC ) {
while ( ( sp = remove_first_SC ( & esp - > disconnected_SC ) ) ! = NULL ) {
esp_release_dmabufs ( esp , sp ) ;
sp - > result = ( DID_RESET < < 16 ) ;
sp - > scsi_done ( sp ) ;
}
}
/* SCSI bus reset is complete. */
esp - > resetting_bus = 0 ;
wake_up ( & esp - > reset_queue ) ;
/* Ok, now it is safe to get commands going once more. */
if ( esp - > issue_SC )
esp_exec_cmd ( esp ) ;
return do_intr_end ;
}
static int esp_do_resetbus ( struct esp * esp )
{
ESPLOG ( ( " esp%d: Resetting scsi bus \n " , esp - > esp_id ) ) ;
esp - > resetting_bus = 1 ;
esp_cmd ( esp , ESP_CMD_RS ) ;
return do_intr_end ;
}
/* Reset ESP chip, reset hanging bus, then kill active and
* disconnected commands for targets without soft reset .
*
* The host_lock is acquired by caller .
*/
static int esp_reset ( struct scsi_cmnd * SCptr )
{
struct esp * esp = ( struct esp * ) SCptr - > device - > host - > hostdata ;
2006-02-23 01:35:52 +03:00
spin_lock_irq ( esp - > ehost - > host_lock ) ;
2005-04-17 02:20:36 +04:00
( void ) esp_do_resetbus ( esp ) ;
spin_unlock_irq ( esp - > ehost - > host_lock ) ;
wait_event ( esp - > reset_queue , ( esp - > resetting_bus = = 0 ) ) ;
return SUCCESS ;
}
/* Internal ESP done function. */
static void esp_done ( struct esp * esp , int error )
{
struct scsi_cmnd * done_SC = esp - > current_SC ;
esp - > current_SC = NULL ;
esp_release_dmabufs ( esp , done_SC ) ;
done_SC - > result = error ;
done_SC - > scsi_done ( done_SC ) ;
/* Bus is free, issue any commands in the queue. */
if ( esp - > issue_SC & & ! esp - > current_SC )
esp_exec_cmd ( esp ) ;
}
/* Wheee, ESP interrupt engine. */
/* Forward declarations. */
static int esp_do_phase_determine ( struct esp * esp ) ;
static int esp_do_data_finale ( struct esp * esp ) ;
static int esp_select_complete ( struct esp * esp ) ;
static int esp_do_status ( struct esp * esp ) ;
static int esp_do_msgin ( struct esp * esp ) ;
static int esp_do_msgindone ( struct esp * esp ) ;
static int esp_do_msgout ( struct esp * esp ) ;
static int esp_do_cmdbegin ( struct esp * esp ) ;
# define sreg_datainp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DIP)
# define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP)
/* Read any bytes found in the FAS366 fifo, storing them into
* the ESP driver software state structure .
*/
static void hme_fifo_read ( struct esp * esp )
{
u8 count = 0 ;
u8 status = esp - > sreg ;
/* Cannot safely frob the fifo for these following cases, but
* we must always read the fifo when the reselect interrupt
* is pending .
*/
if ( ( ( esp - > ireg & ESP_INTR_RSEL ) = = 0 ) & &
( sreg_datainp ( status ) | |
sreg_dataoutp ( status ) | |
( esp - > current_SC & &
esp - > current_SC - > SCp . phase = = in_data_done ) ) ) {
ESPHME ( ( " <wkaround_skipped> " ) ) ;
} else {
unsigned long fcnt = sbus_readb ( esp - > eregs + ESP_FFLAGS ) & ESP_FF_FBYTES ;
/* The HME stores bytes in multiples of 2 in the fifo. */
ESPHME ( ( " hme_fifo[fcnt=%d " , ( int ) fcnt ) ) ;
while ( fcnt ) {
esp - > hme_fifo_workaround_buffer [ count + + ] =
sbus_readb ( esp - > eregs + ESP_FDATA ) ;
esp - > hme_fifo_workaround_buffer [ count + + ] =
sbus_readb ( esp - > eregs + ESP_FDATA ) ;
ESPHME ( ( " <%02x,%02x> " , esp - > hme_fifo_workaround_buffer [ count - 2 ] , esp - > hme_fifo_workaround_buffer [ count - 1 ] ) ) ;
fcnt - - ;
}
if ( sbus_readb ( esp - > eregs + ESP_STATUS2 ) & ESP_STAT2_F1BYTE ) {
ESPHME ( ( " <poke_byte> " ) ) ;
sbus_writeb ( 0 , esp - > eregs + ESP_FDATA ) ;
esp - > hme_fifo_workaround_buffer [ count + + ] =
sbus_readb ( esp - > eregs + ESP_FDATA ) ;
ESPHME ( ( " <%02x,0x00> " , esp - > hme_fifo_workaround_buffer [ count - 1 ] ) ) ;
ESPHME ( ( " CMD_FLUSH " ) ) ;
esp_cmd ( esp , ESP_CMD_FLUSH ) ;
} else {
ESPHME ( ( " no_xtra_byte " ) ) ;
}
}
ESPHME ( ( " wkarnd_cnt=%d] " , ( int ) count ) ) ;
esp - > hme_fifo_workaround_count = count ;
}
static inline void hme_fifo_push ( struct esp * esp , u8 * bytes , u8 count )
{
esp_cmd ( esp , ESP_CMD_FLUSH ) ;
while ( count ) {
u8 tmp = * bytes + + ;
sbus_writeb ( tmp , esp - > eregs + ESP_FDATA ) ;
sbus_writeb ( 0 , esp - > eregs + ESP_FDATA ) ;
count - - ;
}
}
/* We try to avoid some interrupts by jumping ahead and see if the ESP
* has gotten far enough yet . Hence the following .
*/
static inline int skipahead1 ( struct esp * esp , struct scsi_cmnd * scp ,
int prev_phase , int new_phase )
{
if ( scp - > SCp . sent_command ! = prev_phase )
return 0 ;
if ( ESP_IRQ_P ( esp - > dregs ) ) {
/* Yes, we are able to save an interrupt. */
if ( esp - > erev = = fashme )
esp - > sreg2 = sbus_readb ( esp - > eregs + ESP_STATUS2 ) ;
esp - > sreg = ( sbus_readb ( esp - > eregs + ESP_STATUS ) & ~ ( ESP_STAT_INTR ) ) ;
esp - > ireg = sbus_readb ( esp - > eregs + ESP_INTRPT ) ;
if ( esp - > erev = = fashme ) {
/* This chip is really losing. */
ESPHME ( ( " HME[ " ) ) ;
/* Must latch fifo before reading the interrupt
* register else garbage ends up in the FIFO
* which confuses the driver utterly .
* Happy Meal indeed . . . .
*/
ESPHME ( ( " fifo_workaround] " ) ) ;
if ( ! ( esp - > sreg2 & ESP_STAT2_FEMPTY ) | |
( esp - > sreg2 & ESP_STAT2_F1BYTE ) )
hme_fifo_read ( esp ) ;
}
if ( ! ( esp - > ireg & ESP_INTR_SR ) )
return 0 ;
else
return do_reset_complete ;
}
/* Ho hum, target is taking forever... */
scp - > SCp . sent_command = new_phase ; /* so we don't recurse... */
return do_intr_end ;
}
static inline int skipahead2 ( struct esp * esp , struct scsi_cmnd * scp ,
int prev_phase1 , int prev_phase2 , int new_phase )
{
if ( scp - > SCp . sent_command ! = prev_phase1 & &
scp - > SCp . sent_command ! = prev_phase2 )
return 0 ;
if ( ESP_IRQ_P ( esp - > dregs ) ) {
/* Yes, we are able to save an interrupt. */
if ( esp - > erev = = fashme )
esp - > sreg2 = sbus_readb ( esp - > eregs + ESP_STATUS2 ) ;
esp - > sreg = ( sbus_readb ( esp - > eregs + ESP_STATUS ) & ~ ( ESP_STAT_INTR ) ) ;
esp - > ireg = sbus_readb ( esp - > eregs + ESP_INTRPT ) ;
if ( esp - > erev = = fashme ) {
/* This chip is really losing. */
ESPHME ( ( " HME[ " ) ) ;
/* Must latch fifo before reading the interrupt
* register else garbage ends up in the FIFO
* which confuses the driver utterly .
* Happy Meal indeed . . . .
*/
ESPHME ( ( " fifo_workaround] " ) ) ;
if ( ! ( esp - > sreg2 & ESP_STAT2_FEMPTY ) | |
( esp - > sreg2 & ESP_STAT2_F1BYTE ) )
hme_fifo_read ( esp ) ;
}
if ( ! ( esp - > ireg & ESP_INTR_SR ) )
return 0 ;
else
return do_reset_complete ;
}
/* Ho hum, target is taking forever... */
scp - > SCp . sent_command = new_phase ; /* so we don't recurse... */
return do_intr_end ;
}
/* Now some dma helpers. */
static void dma_setup ( struct esp * esp , __u32 addr , int count , int write )
{
u32 nreg = sbus_readl ( esp - > dregs + DMA_CSR ) ;
if ( write )
nreg | = DMA_ST_WRITE ;
else
nreg & = ~ ( DMA_ST_WRITE ) ;
nreg | = DMA_ENABLE ;
sbus_writel ( nreg , esp - > dregs + DMA_CSR ) ;
if ( esp - > dma - > revision = = dvmaesc1 ) {
/* This ESC gate array sucks! */
__u32 src = addr ;
__u32 dest = src + count ;
if ( dest & ( PAGE_SIZE - 1 ) )
count = PAGE_ALIGN ( count ) ;
sbus_writel ( count , esp - > dregs + DMA_COUNT ) ;
}
sbus_writel ( addr , esp - > dregs + DMA_ADDR ) ;
}
static void dma_drain ( struct esp * esp )
{
u32 tmp ;
if ( esp - > dma - > revision = = dvmahme )
return ;
if ( ( tmp = sbus_readl ( esp - > dregs + DMA_CSR ) ) & DMA_FIFO_ISDRAIN ) {
switch ( esp - > dma - > revision ) {
default :
tmp | = DMA_FIFO_STDRAIN ;
sbus_writel ( tmp , esp - > dregs + DMA_CSR ) ;
case dvmarev3 :
case dvmaesc1 :
while ( sbus_readl ( esp - > dregs + DMA_CSR ) & DMA_FIFO_ISDRAIN )
udelay ( 1 ) ;
} ;
}
}
static void dma_invalidate ( struct esp * esp )
{
u32 tmp ;
if ( esp - > dma - > revision = = dvmahme ) {
sbus_writel ( DMA_RST_SCSI , esp - > dregs + DMA_CSR ) ;
esp - > prev_hme_dmacsr = ( ( esp - > prev_hme_dmacsr |
( DMA_PARITY_OFF | DMA_2CLKS |
DMA_SCSI_DISAB | DMA_INT_ENAB ) ) &
~ ( DMA_ST_WRITE | DMA_ENABLE ) ) ;
sbus_writel ( 0 , esp - > dregs + DMA_CSR ) ;
sbus_writel ( esp - > prev_hme_dmacsr , esp - > dregs + DMA_CSR ) ;
/* This is necessary to avoid having the SCSI channel
* engine lock up on us .
*/
sbus_writel ( 0 , esp - > dregs + DMA_ADDR ) ;
} else {
while ( ( tmp = sbus_readl ( esp - > dregs + DMA_CSR ) ) & DMA_PEND_READ )
udelay ( 1 ) ;
tmp & = ~ ( DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB ) ;
tmp | = DMA_FIFO_INV ;
sbus_writel ( tmp , esp - > dregs + DMA_CSR ) ;
tmp & = ~ DMA_FIFO_INV ;
sbus_writel ( tmp , esp - > dregs + DMA_CSR ) ;
}
}
static inline void dma_flashclear ( struct esp * esp )
{
dma_drain ( esp ) ;
dma_invalidate ( esp ) ;
}
static int dma_can_transfer ( struct esp * esp , struct scsi_cmnd * sp )
{
__u32 base , end , sz ;
if ( esp - > dma - > revision = = dvmarev3 ) {
sz = sp - > SCp . this_residual ;
if ( sz > 0x1000000 )
sz = 0x1000000 ;
} else {
base = ( ( __u32 ) ( ( unsigned long ) sp - > SCp . ptr ) ) ;
base & = ( 0x1000000 - 1 ) ;
end = ( base + sp - > SCp . this_residual ) ;
if ( end > 0x1000000 )
end = 0x1000000 ;
sz = ( end - base ) ;
}
return sz ;
}
/* Misc. esp helper macros. */
# define esp_setcount(__eregs, __cnt, __hme) \
sbus_writeb ( ( ( __cnt ) & 0xff ) , ( __eregs ) + ESP_TCLOW ) ; \
sbus_writeb ( ( ( ( __cnt ) > > 8 ) & 0xff ) , ( __eregs ) + ESP_TCMED ) ; \
if ( __hme ) { \
sbus_writeb ( ( ( ( __cnt ) > > 16 ) & 0xff ) , ( __eregs ) + FAS_RLO ) ; \
sbus_writeb ( 0 , ( __eregs ) + FAS_RHI ) ; \
}
# define esp_getcount(__eregs, __hme) \
( ( sbus_readb ( ( __eregs ) + ESP_TCLOW ) & 0xff ) | \
( ( sbus_readb ( ( __eregs ) + ESP_TCMED ) & 0xff ) < < 8 ) | \
( ( __hme ) ? sbus_readb ( ( __eregs ) + FAS_RLO ) < < 16 : 0 ) )
# define fcount(__esp) \
( ( ( __esp ) - > erev = = fashme ) ? \
( __esp ) - > hme_fifo_workaround_count : \
sbus_readb ( ( ( __esp ) - > eregs ) + ESP_FFLAGS ) & ESP_FF_FBYTES )
# define fnzero(__esp) \
( ( ( __esp ) - > erev = = fashme ) ? 0 : \
sbus_readb ( ( ( __esp ) - > eregs ) + ESP_FFLAGS ) & ESP_FF_ONOTZERO )
/* XXX speculative nops unnecessary when continuing amidst a data phase
* XXX even on esp100 ! ! ! another case of flooding the bus with I / O reg
* XXX writes . . .
*/
# define esp_maybe_nop(__esp) \
if ( ( __esp ) - > erev = = esp100 ) \
esp_cmd ( ( __esp ) , ESP_CMD_NULL )
# define sreg_to_dataphase(__sreg) \
( ( ( ( __sreg ) & ESP_STAT_PMASK ) = = ESP_DOP ) ? in_dataout : in_datain )
/* The ESP100 when in synchronous data phase, can mistake a long final
* REQ pulse from the target as an extra byte , it places whatever is on
* the data lines into the fifo . For now , we will assume when this
* happens that the target is a bit quirky and we don ' t want to
* be talking synchronously to it anyways . Regardless , we need to
* tell the ESP to eat the extraneous byte so that we can proceed
* to the next phase .
*/
static int esp100_sync_hwbug ( struct esp * esp , struct scsi_cmnd * sp , int fifocnt )
{
/* Do not touch this piece of code. */
if ( ( ! ( esp - > erev = = esp100 ) ) | |
( ! ( sreg_datainp ( ( esp - > sreg = sbus_readb ( esp - > eregs + ESP_STATUS ) ) ) & &
! fifocnt ) & &
! ( sreg_dataoutp ( esp - > sreg ) & & ! fnzero ( esp ) ) ) ) {
if ( sp - > SCp . phase = = in_dataout )
esp_cmd ( esp , ESP_CMD_FLUSH ) ;
return 0 ;
} else {
/* Async mode for this guy. */
build_sync_nego_msg ( esp , 0 , 0 ) ;
/* Ack the bogus byte, but set ATN first. */
esp_cmd ( esp , ESP_CMD_SATN ) ;
esp_cmd ( esp , ESP_CMD_MOK ) ;
return 1 ;
}
}
/* This closes the window during a selection with a reselect pending, because
* we use DMA for the selection process the FIFO should hold the correct
* contents if we get reselected during this process . So we just need to
* ack the possible illegal cmd interrupt pending on the esp100 .
*/
static inline int esp100_reconnect_hwbug ( struct esp * esp )
{
u8 tmp ;
if ( esp - > erev ! = esp100 )
return 0 ;
tmp = sbus_readb ( esp - > eregs + ESP_INTRPT ) ;
if ( tmp & ESP_INTR_SR )
return 1 ;
return 0 ;
}
/* This verifies the BUSID bits during a reselection so that we know which
* target is talking to us .
*/
static inline int reconnect_target ( struct esp * esp )
{
int it , me = esp - > scsi_id_mask , targ = 0 ;
if ( 2 ! = fcount ( esp ) )
return - 1 ;
if ( esp - > erev = = fashme ) {
/* HME does not latch it's own BUS ID bits during
* a reselection . Also the target number is given
* as an unsigned char , not as a sole bit number
* like the other ESP ' s do .
* Happy Meal indeed . . . .
*/
targ = esp - > hme_fifo_workaround_buffer [ 0 ] ;
} else {
it = sbus_readb ( esp - > eregs + ESP_FDATA ) ;
if ( ! ( it & me ) )
return - 1 ;
it & = ~ me ;
if ( it & ( it - 1 ) )
return - 1 ;
while ( ! ( it & 1 ) )
targ + + , it > > = 1 ;
}
return targ ;
}
/* This verifies the identify from the target so that we know which lun is
* being reconnected .
*/
static inline int reconnect_lun ( struct esp * esp )
{
int lun ;
if ( ( esp - > sreg & ESP_STAT_PMASK ) ! = ESP_MIP )
return - 1 ;
if ( esp - > erev = = fashme )
lun = esp - > hme_fifo_workaround_buffer [ 1 ] ;
else
lun = sbus_readb ( esp - > eregs + ESP_FDATA ) ;
/* Yes, you read this correctly. We report lun of zero
* if we see parity error . ESP reports parity error for
* the lun byte , and this is the only way to hope to recover
* because the target is connected .
*/
if ( esp - > sreg & ESP_STAT_PERR )
return 0 ;
/* Check for illegal bits being set in the lun. */
if ( ( lun & 0x40 ) | | ! ( lun & 0x80 ) )
return - 1 ;
return lun & 7 ;
}
/* This puts the driver in a state where it can revitalize a command that
* is being continued due to reselection .
*/
static inline void esp_connect ( struct esp * esp , struct scsi_cmnd * sp )
{
struct esp_device * esp_dev = sp - > device - > hostdata ;
if ( esp - > prev_soff ! = esp_dev - > sync_max_offset | |
esp - > prev_stp ! = esp_dev - > sync_min_period | |
( esp - > erev > esp100a & &
esp - > prev_cfg3 ! = esp - > config3 [ sp - > device - > id ] ) ) {
esp - > prev_soff = esp_dev - > sync_max_offset ;
esp - > prev_stp = esp_dev - > sync_min_period ;
sbus_writeb ( esp - > prev_soff , esp - > eregs + ESP_SOFF ) ;
sbus_writeb ( esp - > prev_stp , esp - > eregs + ESP_STP ) ;
if ( esp - > erev > esp100a ) {
esp - > prev_cfg3 = esp - > config3 [ sp - > device - > id ] ;
sbus_writeb ( esp - > prev_cfg3 , esp - > eregs + ESP_CFG3 ) ;
}
}
esp - > current_SC = sp ;
}
/* This will place the current working command back into the issue queue
* if we are to receive a reselection amidst a selection attempt .
*/
static inline void esp_reconnect ( struct esp * esp , struct scsi_cmnd * sp )
{
if ( ! esp - > disconnected_SC )
ESPLOG ( ( " esp%d: Weird, being reselected but disconnected "
" command queue is empty. \n " , esp - > esp_id ) ) ;
esp - > snip = 0 ;
2005-04-26 18:43:42 +04:00
esp - > current_SC = NULL ;
2005-04-17 02:20:36 +04:00
sp - > SCp . phase = not_issued ;
append_SC ( & esp - > issue_SC , sp ) ;
}
/* Begin message in phase. */
static int esp_do_msgin ( struct esp * esp )
{
/* Must be very careful with the fifo on the HME */
if ( ( esp - > erev ! = fashme ) | |
! ( sbus_readb ( esp - > eregs + ESP_STATUS2 ) & ESP_STAT2_FEMPTY ) )
esp_cmd ( esp , ESP_CMD_FLUSH ) ;
esp_maybe_nop ( esp ) ;
esp_cmd ( esp , ESP_CMD_TI ) ;
esp - > msgin_len = 1 ;
esp - > msgin_ctr = 0 ;
esp_advance_phase ( esp - > current_SC , in_msgindone ) ;
return do_work_bus ;
}
/* This uses various DMA csr fields and the fifo flags count value to
* determine how many bytes were successfully sent / received by the ESP .
*/
static inline int esp_bytes_sent ( struct esp * esp , int fifo_count )
{
int rval = sbus_readl ( esp - > dregs + DMA_ADDR ) - esp - > esp_command_dvma ;
if ( esp - > dma - > revision = = dvmarev1 )
rval - = ( 4 - ( ( sbus_readl ( esp - > dregs + DMA_CSR ) & DMA_READ_AHEAD ) > > 11 ) ) ;
return rval - fifo_count ;
}
static inline void advance_sg ( struct scsi_cmnd * sp )
{
+ + sp - > SCp . buffer ;
- - sp - > SCp . buffers_residual ;
sp - > SCp . this_residual = sg_dma_len ( sp - > SCp . buffer ) ;
sp - > SCp . ptr = ( char * ) ( ( unsigned long ) sg_dma_address ( sp - > SCp . buffer ) ) ;
}
/* Please note that the way I've coded these routines is that I _always_
* check for a disconnect during any and all information transfer
* phases . The SCSI standard states that the target _can_ cause a BUS
* FREE condition by dropping all MSG / CD / IO / BSY signals . Also note
* that during information transfer phases the target controls every
* change in phase , the only thing the initiator can do is " ask " for
* a message out phase by driving ATN true . The target can , and sometimes
* will , completely ignore this request so we cannot assume anything when
* we try to force a message out phase to abort / reset a target . Most of
* the time the target will eventually be nice and go to message out , so
* we may have to hold on to our state about what we want to tell the target
* for some period of time .
*/
/* I think I have things working here correctly. Even partial transfers
* within a buffer or sub - buffer should not upset us at all no matter
* how bad the target and / or ESP fucks things up .
*/
static int esp_do_data ( struct esp * esp )
{
struct scsi_cmnd * SCptr = esp - > current_SC ;
int thisphase , hmuch ;
ESPDATA ( ( " esp_do_data: " ) ) ;
esp_maybe_nop ( esp ) ;
thisphase = sreg_to_dataphase ( esp - > sreg ) ;
esp_advance_phase ( SCptr , thisphase ) ;
ESPDATA ( ( " newphase<%s> " , ( thisphase = = in_datain ) ? " DATAIN " : " DATAOUT " ) ) ;
hmuch = dma_can_transfer ( esp , SCptr ) ;
if ( hmuch > ( 64 * 1024 ) & & ( esp - > erev ! = fashme ) )
hmuch = ( 64 * 1024 ) ;
ESPDATA ( ( " hmuch<%d> " , hmuch ) ) ;
esp - > current_transfer_size = hmuch ;
if ( esp - > erev = = fashme ) {
u32 tmp = esp - > prev_hme_dmacsr ;
/* Always set the ESP count registers first. */
esp_setcount ( esp - > eregs , hmuch , 1 ) ;
/* Get the DMA csr computed. */
tmp | = ( DMA_SCSI_DISAB | DMA_ENABLE ) ;
if ( thisphase = = in_datain )
tmp | = DMA_ST_WRITE ;
else
tmp & = ~ ( DMA_ST_WRITE ) ;
esp - > prev_hme_dmacsr = tmp ;
ESPDATA ( ( " DMA|TI --> do_intr_end \n " ) ) ;
if ( thisphase = = in_datain ) {
sbus_writel ( hmuch , esp - > dregs + DMA_COUNT ) ;
esp_cmd ( esp , ESP_CMD_DMA | ESP_CMD_TI ) ;
} else {
esp_cmd ( esp , ESP_CMD_DMA | ESP_CMD_TI ) ;
sbus_writel ( hmuch , esp - > dregs + DMA_COUNT ) ;
}
sbus_writel ( ( __u32 ) ( ( unsigned long ) SCptr - > SCp . ptr ) , esp - > dregs + DMA_ADDR ) ;
sbus_writel ( esp - > prev_hme_dmacsr , esp - > dregs + DMA_CSR ) ;
} else {
esp_setcount ( esp - > eregs , hmuch , 0 ) ;
dma_setup ( esp , ( ( __u32 ) ( ( unsigned long ) SCptr - > SCp . ptr ) ) ,
hmuch , ( thisphase = = in_datain ) ) ;
ESPDATA ( ( " DMA|TI --> do_intr_end \n " ) ) ;
esp_cmd ( esp , ESP_CMD_DMA | ESP_CMD_TI ) ;
}
return do_intr_end ;
}
/* See how successful the data transfer was. */
static int esp_do_data_finale ( struct esp * esp )
{
struct scsi_cmnd * SCptr = esp - > current_SC ;
struct esp_device * esp_dev = SCptr - > device - > hostdata ;
int bogus_data = 0 , bytes_sent = 0 , fifocnt , ecount = 0 ;
ESPDATA ( ( " esp_do_data_finale: " ) ) ;
if ( SCptr - > SCp . phase = = in_datain ) {
if ( esp - > sreg & ESP_STAT_PERR ) {
/* Yuck, parity error. The ESP asserts ATN
* so that we can go to message out phase
* immediately and inform the target that
* something bad happened .
*/
ESPLOG ( ( " esp%d: data bad parity detected. \n " ,
esp - > esp_id ) ) ;
esp - > cur_msgout [ 0 ] = INITIATOR_ERROR ;
esp - > msgout_len = 1 ;
}
dma_drain ( esp ) ;
}
dma_invalidate ( esp ) ;
/* This could happen for the above parity error case. */
if ( esp - > ireg ! = ESP_INTR_BSERV ) {
/* Please go to msgout phase, please please please... */
ESPLOG ( ( " esp%d: !BSERV after data, probably to msgout \n " ,
esp - > esp_id ) ) ;
return esp_do_phase_determine ( esp ) ;
}
/* Check for partial transfers and other horrible events.
* Note , here we read the real fifo flags register even
* on HME broken adapters because we skip the HME fifo
* workaround code in esp_handle ( ) if we are doing data
* phase things . We don ' t want to fuck directly with
* the fifo like that , especially if doing synchronous
* transfers ! Also , will need to double the count on
* HME if we are doing wide transfers , as the HME fifo
* will move and count 16 - bit quantities during wide data .
* SMCC _and_ Qlogic can both bite me .
*/
fifocnt = ( sbus_readb ( esp - > eregs + ESP_FFLAGS ) & ESP_FF_FBYTES ) ;
if ( esp - > erev ! = fashme )
ecount = esp_getcount ( esp - > eregs , 0 ) ;
bytes_sent = esp - > current_transfer_size ;
ESPDATA ( ( " trans_sz(%d), " , bytes_sent ) ) ;
if ( esp - > erev = = fashme ) {
if ( ! ( esp - > sreg & ESP_STAT_TCNT ) ) {
ecount = esp_getcount ( esp - > eregs , 1 ) ;
bytes_sent - = ecount ;
}
/* Always subtract any cruft remaining in the FIFO. */
if ( esp - > prev_cfg3 & ESP_CONFIG3_EWIDE )
fifocnt < < = 1 ;
if ( SCptr - > SCp . phase = = in_dataout )
bytes_sent - = fifocnt ;
/* I have an IBM disk which exhibits the following
* behavior during writes to it . It disconnects in
* the middle of a partial transfer , the current sglist
* buffer is 1024 bytes , the disk stops data transfer
* at 512 bytes .
*
* However the FAS366 reports that 32 more bytes were
* transferred than really were . This is precisely
* the size of a fully loaded FIFO in wide scsi mode .
* The FIFO state recorded indicates that it is empty .
*
* I have no idea if this is a bug in the FAS366 chip
* or a bug in the firmware on this IBM disk . In any
* event the following seems to be a good workaround . - DaveM
*/
if ( bytes_sent ! = esp - > current_transfer_size & &
SCptr - > SCp . phase = = in_dataout ) {
int mask = ( 64 - 1 ) ;
if ( ( esp - > prev_cfg3 & ESP_CONFIG3_EWIDE ) = = 0 )
mask > > = 1 ;
if ( bytes_sent & mask )
bytes_sent - = ( bytes_sent & mask ) ;
}
} else {
if ( ! ( esp - > sreg & ESP_STAT_TCNT ) )
bytes_sent - = ecount ;
if ( SCptr - > SCp . phase = = in_dataout )
bytes_sent - = fifocnt ;
}
ESPDATA ( ( " bytes_sent(%d), " , bytes_sent ) ) ;
/* If we were in synchronous mode, check for peculiarities. */
if ( esp - > erev = = fashme ) {
if ( esp_dev - > sync_max_offset ) {
if ( SCptr - > SCp . phase = = in_dataout )
esp_cmd ( esp , ESP_CMD_FLUSH ) ;
} else {
esp_cmd ( esp , ESP_CMD_FLUSH ) ;
}
} else {
if ( esp_dev - > sync_max_offset )
bogus_data = esp100_sync_hwbug ( esp , SCptr , fifocnt ) ;
else
esp_cmd ( esp , ESP_CMD_FLUSH ) ;
}
/* Until we are sure of what has happened, we are certainly
* in the dark .
*/
esp_advance_phase ( SCptr , in_the_dark ) ;
if ( bytes_sent < 0 ) {
/* I've seen this happen due to lost state in this
* driver . No idea why it happened , but allowing
* this value to be negative caused things to
* lock up . This allows greater chance of recovery .
* In fact every time I ' ve seen this , it has been
* a driver bug without question .
*/
ESPLOG ( ( " esp%d: yieee, bytes_sent < 0! \n " , esp - > esp_id ) ) ;
ESPLOG ( ( " esp%d: csz=%d fifocount=%d ecount=%d \n " ,
esp - > esp_id ,
esp - > current_transfer_size , fifocnt , ecount ) ) ;
ESPLOG ( ( " esp%d: use_sg=%d ptr=%p this_residual=%d \n " ,
esp - > esp_id ,
SCptr - > use_sg , SCptr - > SCp . ptr , SCptr - > SCp . this_residual ) ) ;
ESPLOG ( ( " esp%d: Forcing async for target %d \n " , esp - > esp_id ,
SCptr - > device - > id ) ) ;
SCptr - > device - > borken = 1 ;
esp_dev - > sync = 0 ;
bytes_sent = 0 ;
}
/* Update the state of our transfer. */
SCptr - > SCp . ptr + = bytes_sent ;
SCptr - > SCp . this_residual - = bytes_sent ;
if ( SCptr - > SCp . this_residual < 0 ) {
/* shit */
ESPLOG ( ( " esp%d: Data transfer overrun. \n " , esp - > esp_id ) ) ;
SCptr - > SCp . this_residual = 0 ;
}
/* Maybe continue. */
if ( ! bogus_data ) {
ESPDATA ( ( " !bogus_data, " ) ) ;
/* NO MATTER WHAT, we advance the scatterlist,
* if the target should decide to disconnect
* in between scatter chunks ( which is common )
* we could die horribly ! I used to have the sg
* advance occur only if we are going back into
* ( or are staying in ) a data phase , you can
* imagine the hell I went through trying to
* figure this out .
*/
if ( SCptr - > use_sg & & ! SCptr - > SCp . this_residual )
advance_sg ( SCptr ) ;
if ( sreg_datainp ( esp - > sreg ) | | sreg_dataoutp ( esp - > sreg ) ) {
ESPDATA ( ( " to more data \n " ) ) ;
return esp_do_data ( esp ) ;
}
ESPDATA ( ( " to new phase \n " ) ) ;
return esp_do_phase_determine ( esp ) ;
}
/* Bogus data, just wait for next interrupt. */
ESPLOG ( ( " esp%d: bogus_data during end of data phase \n " ,
esp - > esp_id ) ) ;
return do_intr_end ;
}
/* We received a non-good status return at the end of
* running a SCSI command . This is used to decide if
* we should clear our synchronous transfer state for
* such a device when that happens .
*
* The idea is that when spinning up a disk or rewinding
* a tape , we don ' t want to go into a loop re - negotiating
* synchronous capabilities over and over .
*/
static int esp_should_clear_sync ( struct scsi_cmnd * sp )
{
u8 cmd1 = sp - > cmnd [ 0 ] ;
u8 cmd2 = sp - > data_cmnd [ 0 ] ;
/* These cases are for spinning up a disk and
* waiting for that spinup to complete .
*/
if ( cmd1 = = START_STOP | |
cmd2 = = START_STOP )
return 0 ;
if ( cmd1 = = TEST_UNIT_READY | |
cmd2 = = TEST_UNIT_READY )
return 0 ;
/* One more special case for SCSI tape drives,
* this is what is used to probe the device for
* completion of a rewind or tape load operation .
*/
if ( sp - > device - > type = = TYPE_TAPE ) {
if ( cmd1 = = MODE_SENSE | |
cmd2 = = MODE_SENSE )
return 0 ;
}
return 1 ;
}
/* Either a command is completing or a target is dropping off the bus
* to continue the command in the background so we can do other work .
*/
static int esp_do_freebus ( struct esp * esp )
{
struct scsi_cmnd * SCptr = esp - > current_SC ;
struct esp_device * esp_dev = SCptr - > device - > hostdata ;
int rval ;
rval = skipahead2 ( esp , SCptr , in_status , in_msgindone , in_freeing ) ;
if ( rval )
return rval ;
if ( esp - > ireg ! = ESP_INTR_DC ) {
ESPLOG ( ( " esp%d: Target will not disconnect \n " , esp - > esp_id ) ) ;
return do_reset_bus ; /* target will not drop BSY... */
}
esp - > msgout_len = 0 ;
esp - > prevmsgout = NOP ;
if ( esp - > prevmsgin = = COMMAND_COMPLETE ) {
/* Normal end of nexus. */
if ( esp - > disconnected_SC | | ( esp - > erev = = fashme ) )
esp_cmd ( esp , ESP_CMD_ESEL ) ;
if ( SCptr - > SCp . Status ! = GOOD & &
SCptr - > SCp . Status ! = CONDITION_GOOD & &
( ( 1 < < SCptr - > device - > id ) & esp - > targets_present ) & &
esp_dev - > sync & &
esp_dev - > sync_max_offset ) {
/* SCSI standard says that the synchronous capabilities
* should be renegotiated at this point . Most likely
* we are about to request sense from this target
* in which case we want to avoid using sync
* transfers until we are sure of the current target
* state .
*/
ESPMISC ( ( " esp: Status <%d> for target %d lun %d \n " ,
SCptr - > SCp . Status , SCptr - > device - > id , SCptr - > device - > lun ) ) ;
/* But don't do this when spinning up a disk at
* boot time while we poll for completion as it
* fills up the console with messages . Also , tapes
* can report not ready many times right after
* loading up a tape .
*/
if ( esp_should_clear_sync ( SCptr ) ! = 0 )
esp_dev - > sync = 0 ;
}
ESPDISC ( ( " F<%02x,%02x> " , SCptr - > device - > id , SCptr - > device - > lun ) ) ;
esp_done ( esp , ( ( SCptr - > SCp . Status & 0xff ) |
( ( SCptr - > SCp . Message & 0xff ) < < 8 ) |
( DID_OK < < 16 ) ) ) ;
} else if ( esp - > prevmsgin = = DISCONNECT ) {
/* Normal disconnect. */
esp_cmd ( esp , ESP_CMD_ESEL ) ;
ESPDISC ( ( " D<%02x,%02x> " , SCptr - > device - > id , SCptr - > device - > lun ) ) ;
append_SC ( & esp - > disconnected_SC , SCptr ) ;
esp - > current_SC = NULL ;
if ( esp - > issue_SC )
esp_exec_cmd ( esp ) ;
} else {
/* Driver bug, we do not expect a disconnect here
* and should not have advanced the state engine
* to in_freeing .
*/
ESPLOG ( ( " esp%d: last msg not disc and not cmd cmplt. \n " ,
esp - > esp_id ) ) ;
return do_reset_bus ;
}
return do_intr_end ;
}
/* When a reselect occurs, and we cannot find the command to
* reconnect to in our queues , we do this .
*/
static int esp_bad_reconnect ( struct esp * esp )
{
struct scsi_cmnd * sp ;
ESPLOG ( ( " esp%d: Eieeee, reconnecting unknown command! \n " ,
esp - > esp_id ) ) ;
ESPLOG ( ( " QUEUE DUMP \n " ) ) ;
sp = esp - > issue_SC ;
ESPLOG ( ( " esp%d: issue_SC[ " , esp - > esp_id ) ) ;
while ( sp ) {
ESPLOG ( ( " <%02x,%02x> " , sp - > device - > id , sp - > device - > lun ) ) ;
sp = ( struct scsi_cmnd * ) sp - > host_scribble ;
}
ESPLOG ( ( " ] \n " ) ) ;
sp = esp - > current_SC ;
ESPLOG ( ( " esp%d: current_SC[ " , esp - > esp_id ) ) ;
if ( sp )
ESPLOG ( ( " <%02x,%02x> " , sp - > device - > id , sp - > device - > lun ) ) ;
else
ESPLOG ( ( " <NULL> " ) ) ;
ESPLOG ( ( " ] \n " ) ) ;
sp = esp - > disconnected_SC ;
ESPLOG ( ( " esp%d: disconnected_SC[ " , esp - > esp_id ) ) ;
while ( sp ) {
ESPLOG ( ( " <%02x,%02x> " , sp - > device - > id , sp - > device - > lun ) ) ;
sp = ( struct scsi_cmnd * ) sp - > host_scribble ;
}
ESPLOG ( ( " ] \n " ) ) ;
return do_reset_bus ;
}
/* Do the needy when a target tries to reconnect to us. */
static int esp_do_reconnect ( struct esp * esp )
{
int lun , target ;
struct scsi_cmnd * SCptr ;
/* Check for all bogus conditions first. */
target = reconnect_target ( esp ) ;
if ( target < 0 ) {
ESPDISC ( ( " bad bus bits \n " ) ) ;
return do_reset_bus ;
}
lun = reconnect_lun ( esp ) ;
if ( lun < 0 ) {
ESPDISC ( ( " target=%2x, bad identify msg \n " , target ) ) ;
return do_reset_bus ;
}
/* Things look ok... */
ESPDISC ( ( " R<%02x,%02x> " , target , lun ) ) ;
/* Must not flush FIFO or DVMA on HME. */
if ( esp - > erev ! = fashme ) {
esp_cmd ( esp , ESP_CMD_FLUSH ) ;
if ( esp100_reconnect_hwbug ( esp ) )
return do_reset_bus ;
esp_cmd ( esp , ESP_CMD_NULL ) ;
}
SCptr = remove_SC ( & esp - > disconnected_SC , ( u8 ) target , ( u8 ) lun ) ;
if ( ! SCptr )
return esp_bad_reconnect ( esp ) ;
esp_connect ( esp , SCptr ) ;
esp_cmd ( esp , ESP_CMD_MOK ) ;
if ( esp - > erev = = fashme )
sbus_writeb ( ( ( SCptr - > device - > id & 0xf ) |
( ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT ) ) ,
esp - > eregs + ESP_BUSID ) ;
/* Reconnect implies a restore pointers operation. */
esp_restore_pointers ( esp , SCptr ) ;
esp - > snip = 0 ;
esp_advance_phase ( SCptr , in_the_dark ) ;
return do_intr_end ;
}
/* End of NEXUS (hopefully), pick up status + message byte then leave if
* all goes well .
*/
static int esp_do_status ( struct esp * esp )
{
struct scsi_cmnd * SCptr = esp - > current_SC ;
int intr , rval ;
rval = skipahead1 ( esp , SCptr , in_the_dark , in_status ) ;
if ( rval )
return rval ;
intr = esp - > ireg ;
ESPSTAT ( ( " esp_do_status: " ) ) ;
if ( intr ! = ESP_INTR_DC ) {
int message_out = 0 ; /* for parity problems */
/* Ack the message. */
ESPSTAT ( ( " ack msg, " ) ) ;
esp_cmd ( esp , ESP_CMD_MOK ) ;
if ( esp - > erev ! = fashme ) {
dma_flashclear ( esp ) ;
/* Wait till the first bits settle. */
while ( esp - > esp_command [ 0 ] = = 0xff )
udelay ( 1 ) ;
} else {
esp - > esp_command [ 0 ] = esp - > hme_fifo_workaround_buffer [ 0 ] ;
esp - > esp_command [ 1 ] = esp - > hme_fifo_workaround_buffer [ 1 ] ;
}
ESPSTAT ( ( " got something, " ) ) ;
/* ESP chimes in with one of
*
* 1 ) function done interrupt :
* both status and message in bytes
* are available
*
* 2 ) bus service interrupt :
* only status byte was acquired
*
* 3 ) Anything else :
* can ' t happen , but we test for it
* anyways
*
* ALSO : If bad parity was detected on either
* the status _or_ the message byte then
* the ESP has asserted ATN on the bus
* and we must therefore wait for the
* next phase change .
*/
if ( intr & ESP_INTR_FDONE ) {
/* We got it all, hallejulia. */
ESPSTAT ( ( " got both, " ) ) ;
SCptr - > SCp . Status = esp - > esp_command [ 0 ] ;
SCptr - > SCp . Message = esp - > esp_command [ 1 ] ;
esp - > prevmsgin = SCptr - > SCp . Message ;
esp - > cur_msgin [ 0 ] = SCptr - > SCp . Message ;
if ( esp - > sreg & ESP_STAT_PERR ) {
/* There was bad parity for the
* message byte , the status byte
* was ok .
*/
message_out = MSG_PARITY_ERROR ;
}
} else if ( intr = = ESP_INTR_BSERV ) {
/* Only got status byte. */
ESPLOG ( ( " esp%d: got status only, " , esp - > esp_id ) ) ;
if ( ! ( esp - > sreg & ESP_STAT_PERR ) ) {
SCptr - > SCp . Status = esp - > esp_command [ 0 ] ;
SCptr - > SCp . Message = 0xff ;
} else {
/* The status byte had bad parity.
* we leave the scsi_pointer Status
* field alone as we set it to a default
* of CHECK_CONDITION in esp_queue .
*/
message_out = INITIATOR_ERROR ;
}
} else {
/* This shouldn't happen ever. */
ESPSTAT ( ( " got bolixed \n " ) ) ;
esp_advance_phase ( SCptr , in_the_dark ) ;
return esp_do_phase_determine ( esp ) ;
}
if ( ! message_out ) {
ESPSTAT ( ( " status=%2x msg=%2x, " , SCptr - > SCp . Status ,
SCptr - > SCp . Message ) ) ;
if ( SCptr - > SCp . Message = = COMMAND_COMPLETE ) {
ESPSTAT ( ( " and was COMMAND_COMPLETE \n " ) ) ;
esp_advance_phase ( SCptr , in_freeing ) ;
return esp_do_freebus ( esp ) ;
} else {
ESPLOG ( ( " esp%d: and _not_ COMMAND_COMPLETE \n " ,
esp - > esp_id ) ) ;
esp - > msgin_len = esp - > msgin_ctr = 1 ;
esp_advance_phase ( SCptr , in_msgindone ) ;
return esp_do_msgindone ( esp ) ;
}
} else {
/* With luck we'll be able to let the target
* know that bad parity happened , it will know
* which byte caused the problems and send it
* again . For the case where the status byte
* receives bad parity , I do not believe most
* targets recover very well . We ' ll see .
*/
ESPLOG ( ( " esp%d: bad parity somewhere mout=%2x \n " ,
esp - > esp_id , message_out ) ) ;
esp - > cur_msgout [ 0 ] = message_out ;
esp - > msgout_len = esp - > msgout_ctr = 1 ;
esp_advance_phase ( SCptr , in_the_dark ) ;
return esp_do_phase_determine ( esp ) ;
}
} else {
/* If we disconnect now, all hell breaks loose. */
ESPLOG ( ( " esp%d: whoops, disconnect \n " , esp - > esp_id ) ) ;
esp_advance_phase ( SCptr , in_the_dark ) ;
return esp_do_phase_determine ( esp ) ;
}
}
static int esp_enter_status ( struct esp * esp )
{
u8 thecmd = ESP_CMD_ICCSEQ ;
esp_cmd ( esp , ESP_CMD_FLUSH ) ;
if ( esp - > erev ! = fashme ) {
u32 tmp ;
esp - > esp_command [ 0 ] = esp - > esp_command [ 1 ] = 0xff ;
sbus_writeb ( 2 , esp - > eregs + ESP_TCLOW ) ;
sbus_writeb ( 0 , esp - > eregs + ESP_TCMED ) ;
tmp = sbus_readl ( esp - > dregs + DMA_CSR ) ;
tmp | = ( DMA_ST_WRITE | DMA_ENABLE ) ;
sbus_writel ( tmp , esp - > dregs + DMA_CSR ) ;
if ( esp - > dma - > revision = = dvmaesc1 )
sbus_writel ( 0x100 , esp - > dregs + DMA_COUNT ) ;
sbus_writel ( esp - > esp_command_dvma , esp - > dregs + DMA_ADDR ) ;
thecmd | = ESP_CMD_DMA ;
}
esp_cmd ( esp , thecmd ) ;
esp_advance_phase ( esp - > current_SC , in_status ) ;
return esp_do_status ( esp ) ;
}
static int esp_disconnect_amidst_phases ( struct esp * esp )
{
struct scsi_cmnd * sp = esp - > current_SC ;
struct esp_device * esp_dev = sp - > device - > hostdata ;
/* This means real problems if we see this
* here . Unless we were actually trying
* to force the device to abort / reset .
*/
ESPLOG ( ( " esp%d Disconnect amidst phases, " , esp - > esp_id ) ) ;
ESPLOG ( ( " pphase<%s> cphase<%s>, " ,
phase_string ( sp - > SCp . phase ) ,
phase_string ( sp - > SCp . sent_command ) ) ) ;
if ( esp - > disconnected_SC ! = NULL | | ( esp - > erev = = fashme ) )
esp_cmd ( esp , ESP_CMD_ESEL ) ;
switch ( esp - > cur_msgout [ 0 ] ) {
default :
/* We didn't expect this to happen at all. */
ESPLOG ( ( " device is bolixed \n " ) ) ;
esp_advance_phase ( sp , in_tgterror ) ;
esp_done ( esp , ( DID_ERROR < < 16 ) ) ;
break ;
case BUS_DEVICE_RESET :
ESPLOG ( ( " device reset successful \n " ) ) ;
esp_dev - > sync_max_offset = 0 ;
esp_dev - > sync_min_period = 0 ;
esp_dev - > sync = 0 ;
esp_advance_phase ( sp , in_resetdev ) ;
esp_done ( esp , ( DID_RESET < < 16 ) ) ;
break ;
case ABORT :
ESPLOG ( ( " device abort successful \n " ) ) ;
esp_advance_phase ( sp , in_abortone ) ;
esp_done ( esp , ( DID_ABORT < < 16 ) ) ;
break ;
} ;
return do_intr_end ;
}
static int esp_enter_msgout ( struct esp * esp )
{
esp_advance_phase ( esp - > current_SC , in_msgout ) ;
return esp_do_msgout ( esp ) ;
}
static int esp_enter_msgin ( struct esp * esp )
{
esp_advance_phase ( esp - > current_SC , in_msgin ) ;
return esp_do_msgin ( esp ) ;
}
static int esp_enter_cmd ( struct esp * esp )
{
esp_advance_phase ( esp - > current_SC , in_cmdbegin ) ;
return esp_do_cmdbegin ( esp ) ;
}
static int esp_enter_badphase ( struct esp * esp )
{
ESPLOG ( ( " esp%d: Bizarre bus phase %2x. \n " , esp - > esp_id ,
esp - > sreg & ESP_STAT_PMASK ) ) ;
return do_reset_bus ;
}
typedef int ( * espfunc_t ) ( struct esp * ) ;
static espfunc_t phase_vector [ ] = {
esp_do_data , /* ESP_DOP */
esp_do_data , /* ESP_DIP */
esp_enter_cmd , /* ESP_CMDP */
esp_enter_status , /* ESP_STATP */
esp_enter_badphase , /* ESP_STAT_PMSG */
esp_enter_badphase , /* ESP_STAT_PMSG | ESP_STAT_PIO */
esp_enter_msgout , /* ESP_MOP */
esp_enter_msgin , /* ESP_MIP */
} ;
/* The target has control of the bus and we have to see where it has
* taken us .
*/
static int esp_do_phase_determine ( struct esp * esp )
{
if ( ( esp - > ireg & ESP_INTR_DC ) ! = 0 )
return esp_disconnect_amidst_phases ( esp ) ;
return phase_vector [ esp - > sreg & ESP_STAT_PMASK ] ( esp ) ;
}
/* First interrupt after exec'ing a cmd comes here. */
static int esp_select_complete ( struct esp * esp )
{
struct scsi_cmnd * SCptr = esp - > current_SC ;
struct esp_device * esp_dev = SCptr - > device - > hostdata ;
int cmd_bytes_sent , fcnt ;
if ( esp - > erev ! = fashme )
esp - > seqreg = ( sbus_readb ( esp - > eregs + ESP_SSTEP ) & ESP_STEP_VBITS ) ;
if ( esp - > erev = = fashme )
fcnt = esp - > hme_fifo_workaround_count ;
else
fcnt = ( sbus_readb ( esp - > eregs + ESP_FFLAGS ) & ESP_FF_FBYTES ) ;
cmd_bytes_sent = esp_bytes_sent ( esp , fcnt ) ;
dma_invalidate ( esp ) ;
/* Let's check to see if a reselect happened
* while we we ' re trying to select . This must
* be checked first .
*/
if ( esp - > ireg = = ( ESP_INTR_RSEL | ESP_INTR_FDONE ) ) {
esp_reconnect ( esp , SCptr ) ;
return esp_do_reconnect ( esp ) ;
}
/* Looks like things worked, we should see a bus service &
* a function complete interrupt at this point . Note we
* are doing a direct comparison because we don ' t want to
* be fooled into thinking selection was successful if
* ESP_INTR_DC is set , see below .
*/
if ( esp - > ireg = = ( ESP_INTR_FDONE | ESP_INTR_BSERV ) ) {
/* target speaks... */
esp - > targets_present | = ( 1 < < SCptr - > device - > id ) ;
/* What if the target ignores the sdtr? */
if ( esp - > snip )
esp_dev - > sync = 1 ;
/* See how far, if at all, we got in getting
* the information out to the target .
*/
switch ( esp - > seqreg ) {
default :
case ESP_STEP_ASEL :
/* Arbitration won, target selected, but
* we are in some phase which is not command
* phase nor is it message out phase .
*
* XXX We ' ve confused the target , obviously .
* XXX So clear it ' s state , but we also end
* XXX up clearing everyone elses . That isn ' t
* XXX so nice . I ' d like to just reset this
* XXX target , but if I cannot even get it ' s
* XXX attention and finish selection to talk
* XXX to it , there is not much more I can do .
* XXX If we have a loaded bus we ' re going to
* XXX spend the next second or so renegotiating
* XXX for synchronous transfers .
*/
ESPLOG ( ( " esp%d: STEP_ASEL for tgt %d \n " ,
esp - > esp_id , SCptr - > device - > id ) ) ;
case ESP_STEP_SID :
/* Arbitration won, target selected, went
* to message out phase , sent one message
* byte , then we stopped . ATN is asserted
* on the SCSI bus and the target is still
* there hanging on . This is a legal
* sequence step if we gave the ESP a select
* and stop command .
*
* XXX See above , I could set the borken flag
* XXX in the device struct and retry the
* XXX command . But would that help for
* XXX tagged capable targets ?
*/
case ESP_STEP_NCMD :
/* Arbitration won, target selected, maybe
* sent the one message byte in message out
* phase , but we did not go to command phase
* in the end . Actually , we could have sent
* only some of the message bytes if we tried
* to send out the entire identify and tag
* message using ESP_CMD_SA3 .
*/
cmd_bytes_sent = 0 ;
break ;
case ESP_STEP_PPC :
/* No, not the powerPC pinhead. Arbitration
* won , all message bytes sent if we went to
* message out phase , went to command phase
* but only part of the command was sent .
*
* XXX I ' ve seen this , but usually in conjunction
* XXX with a gross error which appears to have
* XXX occurred between the time I told the
* XXX ESP to arbitrate and when I got the
* XXX interrupt . Could I have misloaded the
* XXX command bytes into the fifo ? Actually ,
* XXX I most likely missed a phase , and therefore
* XXX went into never never land and didn ' t even
* XXX know it . That was the old driver though .
* XXX What is even more peculiar is that the ESP
* XXX showed the proper function complete and
* XXX bus service bits in the interrupt register .
*/
case ESP_STEP_FINI4 :
case ESP_STEP_FINI5 :
case ESP_STEP_FINI6 :
case ESP_STEP_FINI7 :
/* Account for the identify message */
if ( SCptr - > SCp . phase = = in_slct_norm )
cmd_bytes_sent - = 1 ;
} ;
if ( esp - > erev ! = fashme )
esp_cmd ( esp , ESP_CMD_NULL ) ;
/* Be careful, we could really get fucked during synchronous
* data transfers if we try to flush the fifo now .
*/
if ( ( esp - > erev ! = fashme ) & & /* not a Happy Meal and... */
! fcnt & & /* Fifo is empty and... */
/* either we are not doing synchronous transfers or... */
( ! esp_dev - > sync_max_offset | |
/* We are not going into data in phase. */
( ( esp - > sreg & ESP_STAT_PMASK ) ! = ESP_DIP ) ) )
esp_cmd ( esp , ESP_CMD_FLUSH ) ; /* flush is safe */
/* See how far we got if this is not a slow command. */
if ( ! esp - > esp_slowcmd ) {
if ( cmd_bytes_sent < 0 )
cmd_bytes_sent = 0 ;
if ( cmd_bytes_sent ! = SCptr - > cmd_len ) {
/* Crapola, mark it as a slowcmd
* so that we have some chance of
* keeping the command alive with
* good luck .
*
* XXX Actually , if we didn ' t send it all
* XXX this means either we didn ' t set things
* XXX up properly ( driver bug ) or the target
* XXX or the ESP detected parity on one of
* XXX the command bytes . This makes much
* XXX more sense , and therefore this code
* XXX should be changed to send out a
* XXX parity error message or if the status
* XXX register shows no parity error then
* XXX just expect the target to bring the
* XXX bus into message in phase so that it
* XXX can send us the parity error message .
* XXX SCSI sucks . . .
*/
esp - > esp_slowcmd = 1 ;
esp - > esp_scmdp = & ( SCptr - > cmnd [ cmd_bytes_sent ] ) ;
esp - > esp_scmdleft = ( SCptr - > cmd_len - cmd_bytes_sent ) ;
}
}
/* Now figure out where we went. */
esp_advance_phase ( SCptr , in_the_dark ) ;
return esp_do_phase_determine ( esp ) ;
}
/* Did the target even make it? */
if ( esp - > ireg = = ESP_INTR_DC ) {
/* wheee... nobody there or they didn't like
* what we told it to do , clean up .
*/
/* If anyone is off the bus, but working on
* a command in the background for us , tell
* the ESP to listen for them .
*/
if ( esp - > disconnected_SC )
esp_cmd ( esp , ESP_CMD_ESEL ) ;
if ( ( ( 1 < < SCptr - > device - > id ) & esp - > targets_present ) & &
esp - > seqreg ! = 0 & &
( esp - > cur_msgout [ 0 ] = = EXTENDED_MESSAGE ) & &
( SCptr - > SCp . phase = = in_slct_msg | |
SCptr - > SCp . phase = = in_slct_stop ) ) {
/* shit */
esp - > snip = 0 ;
ESPLOG ( ( " esp%d: Failed synchronous negotiation for target %d "
" lun %d \n " , esp - > esp_id , SCptr - > device - > id , SCptr - > device - > lun ) ) ;
esp_dev - > sync_max_offset = 0 ;
esp_dev - > sync_min_period = 0 ;
esp_dev - > sync = 1 ; /* so we don't negotiate again */
/* Run the command again, this time though we
* won ' t try to negotiate for synchronous transfers .
*
* XXX I ' d like to do something like send an
* XXX INITIATOR_ERROR or ABORT message to the
* XXX target to tell it , " Sorry I confused you,
* XXX please come back and I will be nicer next
* XXX time " . But that requires having the target
* XXX on the bus , and it has dropped BSY on us .
*/
esp - > current_SC = NULL ;
esp_advance_phase ( SCptr , not_issued ) ;
prepend_SC ( & esp - > issue_SC , SCptr ) ;
esp_exec_cmd ( esp ) ;
return do_intr_end ;
}
/* Ok, this is normal, this is what we see during boot
* or whenever when we are scanning the bus for targets .
* But first make sure that is really what is happening .
*/
if ( ( ( 1 < < SCptr - > device - > id ) & esp - > targets_present ) ) {
ESPLOG ( ( " esp%d: Warning, live target %d not responding to "
" selection. \n " , esp - > esp_id , SCptr - > device - > id ) ) ;
/* This _CAN_ happen. The SCSI standard states that
* the target is to _not_ respond to selection if
* _it_ detects bad parity on the bus for any reason .
* Therefore , we assume that if we ' ve talked successfully
* to this target before , bad parity is the problem .
*/
esp_done ( esp , ( DID_PARITY < < 16 ) ) ;
} else {
/* Else, there really isn't anyone there. */
ESPMISC ( ( " esp: selection failure, maybe nobody there? \n " ) ) ;
ESPMISC ( ( " esp: target %d lun %d \n " ,
SCptr - > device - > id , SCptr - > device - > lun ) ) ;
esp_done ( esp , ( DID_BAD_TARGET < < 16 ) ) ;
}
return do_intr_end ;
}
ESPLOG ( ( " esp%d: Selection failure. \n " , esp - > esp_id ) ) ;
printk ( " esp%d: Currently -- " , esp - > esp_id ) ;
esp_print_ireg ( esp - > ireg ) ; printk ( " " ) ;
esp_print_statreg ( esp - > sreg ) ; printk ( " " ) ;
esp_print_seqreg ( esp - > seqreg ) ; printk ( " \n " ) ;
printk ( " esp%d: New -- " , esp - > esp_id ) ;
esp - > sreg = sbus_readb ( esp - > eregs + ESP_STATUS ) ;
esp - > seqreg = sbus_readb ( esp - > eregs + ESP_SSTEP ) ;
esp - > ireg = sbus_readb ( esp - > eregs + ESP_INTRPT ) ;
esp_print_ireg ( esp - > ireg ) ; printk ( " " ) ;
esp_print_statreg ( esp - > sreg ) ; printk ( " " ) ;
esp_print_seqreg ( esp - > seqreg ) ; printk ( " \n " ) ;
ESPLOG ( ( " esp%d: resetting bus \n " , esp - > esp_id ) ) ;
return do_reset_bus ; /* ugh... */
}
/* Continue reading bytes for msgin phase. */
static int esp_do_msgincont ( struct esp * esp )
{
if ( esp - > ireg & ESP_INTR_BSERV ) {
/* in the right phase too? */
if ( ( esp - > sreg & ESP_STAT_PMASK ) = = ESP_MIP ) {
/* phew... */
esp_cmd ( esp , ESP_CMD_TI ) ;
esp_advance_phase ( esp - > current_SC , in_msgindone ) ;
return do_intr_end ;
}
/* We changed phase but ESP shows bus service,
* in this case it is most likely that we , the
* hacker who has been up for 20 hrs straight
* staring at the screen , drowned in coffee
* smelling like retched cigarette ashes
* have miscoded something . . . . . so , try to
* recover as best we can .
*/
ESPLOG ( ( " esp%d: message in mis-carriage. \n " , esp - > esp_id ) ) ;
}
esp_advance_phase ( esp - > current_SC , in_the_dark ) ;
return do_phase_determine ;
}
static int check_singlebyte_msg ( struct esp * esp )
{
esp - > prevmsgin = esp - > cur_msgin [ 0 ] ;
if ( esp - > cur_msgin [ 0 ] & 0x80 ) {
/* wheee... */
ESPLOG ( ( " esp%d: target sends identify amidst phases \n " ,
esp - > esp_id ) ) ;
esp_advance_phase ( esp - > current_SC , in_the_dark ) ;
return 0 ;
} else if ( ( ( esp - > cur_msgin [ 0 ] & 0xf0 ) = = 0x20 ) | |
( esp - > cur_msgin [ 0 ] = = EXTENDED_MESSAGE ) ) {
esp - > msgin_len = 2 ;
esp_advance_phase ( esp - > current_SC , in_msgincont ) ;
return 0 ;
}
esp_advance_phase ( esp - > current_SC , in_the_dark ) ;
switch ( esp - > cur_msgin [ 0 ] ) {
default :
/* We don't want to hear about it. */
ESPLOG ( ( " esp%d: msg %02x which we don't know about \n " , esp - > esp_id ,
esp - > cur_msgin [ 0 ] ) ) ;
return MESSAGE_REJECT ;
case NOP :
ESPLOG ( ( " esp%d: target %d sends a nop \n " , esp - > esp_id ,
esp - > current_SC - > device - > id ) ) ;
return 0 ;
case RESTORE_POINTERS :
/* In this case we might also have to backup the
* " slow command " pointer . It is rare to get such
* a save / restore pointer sequence so early in the
* bus transition sequences , but cover it .
*/
if ( esp - > esp_slowcmd ) {
esp - > esp_scmdleft = esp - > current_SC - > cmd_len ;
esp - > esp_scmdp = & esp - > current_SC - > cmnd [ 0 ] ;
}
esp_restore_pointers ( esp , esp - > current_SC ) ;
return 0 ;
case SAVE_POINTERS :
esp_save_pointers ( esp , esp - > current_SC ) ;
return 0 ;
case COMMAND_COMPLETE :
case DISCONNECT :
/* Freeing the bus, let it go. */
esp - > current_SC - > SCp . phase = in_freeing ;
return 0 ;
case MESSAGE_REJECT :
ESPMISC ( ( " msg reject, " ) ) ;
if ( esp - > prevmsgout = = EXTENDED_MESSAGE ) {
struct esp_device * esp_dev = esp - > current_SC - > device - > hostdata ;
/* Doesn't look like this target can
* do synchronous or WIDE transfers .
*/
ESPSDTR ( ( " got reject, was trying nego, clearing sync/WIDE \n " ) ) ;
esp_dev - > sync = 1 ;
esp_dev - > wide = 1 ;
esp_dev - > sync_min_period = 0 ;
esp_dev - > sync_max_offset = 0 ;
return 0 ;
} else {
ESPMISC ( ( " not sync nego, sending ABORT \n " ) ) ;
return ABORT ;
}
} ;
}
/* Target negotiates for synchronous transfers before we do, this
* is legal although very strange . What is even funnier is that
* the SCSI2 standard specifically recommends against targets doing
* this because so many initiators cannot cope with this occurring .
*/
static int target_with_ants_in_pants ( struct esp * esp ,
struct scsi_cmnd * SCptr ,
struct esp_device * esp_dev )
{
if ( esp_dev - > sync | | SCptr - > device - > borken ) {
/* sorry, no can do */
ESPSDTR ( ( " forcing to async, " ) ) ;
build_sync_nego_msg ( esp , 0 , 0 ) ;
esp_dev - > sync = 1 ;
esp - > snip = 1 ;
ESPLOG ( ( " esp%d: hoping for msgout \n " , esp - > esp_id ) ) ;
esp_advance_phase ( SCptr , in_the_dark ) ;
return EXTENDED_MESSAGE ;
}
/* Ok, we'll check them out... */
return 0 ;
}
static void sync_report ( struct esp * esp )
{
int msg3 , msg4 ;
char * type ;
msg3 = esp - > cur_msgin [ 3 ] ;
msg4 = esp - > cur_msgin [ 4 ] ;
if ( msg4 ) {
int hz = 1000000000 / ( msg3 * 4 ) ;
int integer = hz / 1000000 ;
int fraction = ( hz - ( integer * 1000000 ) ) / 10000 ;
if ( ( esp - > erev = = fashme ) & &
( esp - > config3 [ esp - > current_SC - > device - > id ] & ESP_CONFIG3_EWIDE ) ) {
type = " FAST-WIDE " ;
integer < < = 1 ;
fraction < < = 1 ;
} else if ( ( msg3 * 4 ) < 200 ) {
type = " FAST " ;
} else {
type = " synchronous " ;
}
/* Do not transform this back into one big printk
* again , it triggers a bug in our sparc64 - gcc272
* sibling call optimization . - DaveM
*/
ESPLOG ( ( KERN_INFO " esp%d: target %d " ,
esp - > esp_id , esp - > current_SC - > device - > id ) ) ;
ESPLOG ( ( " [period %dns offset %d %d.%02dMHz " ,
( int ) msg3 * 4 , ( int ) msg4 ,
integer , fraction ) ) ;
ESPLOG ( ( " %s SCSI%s] \n " , type ,
( ( ( msg3 * 4 ) < 200 ) ? " -II " : " " ) ) ) ;
} else {
ESPLOG ( ( KERN_INFO " esp%d: target %d asynchronous \n " ,
esp - > esp_id , esp - > current_SC - > device - > id ) ) ;
}
}
static int check_multibyte_msg ( struct esp * esp )
{
struct scsi_cmnd * SCptr = esp - > current_SC ;
struct esp_device * esp_dev = SCptr - > device - > hostdata ;
u8 regval = 0 ;
int message_out = 0 ;
ESPSDTR ( ( " chk multibyte msg: " ) ) ;
if ( esp - > cur_msgin [ 2 ] = = EXTENDED_SDTR ) {
int period = esp - > cur_msgin [ 3 ] ;
int offset = esp - > cur_msgin [ 4 ] ;
ESPSDTR ( ( " is sync nego response, " ) ) ;
if ( ! esp - > snip ) {
int rval ;
/* Target negotiates first! */
ESPSDTR ( ( " target jumps the gun, " ) ) ;
message_out = EXTENDED_MESSAGE ; /* we must respond */
rval = target_with_ants_in_pants ( esp , SCptr , esp_dev ) ;
if ( rval )
return rval ;
}
ESPSDTR ( ( " examining sdtr, " ) ) ;
/* Offset cannot be larger than ESP fifo size. */
if ( offset > 15 ) {
ESPSDTR ( ( " offset too big %2x, " , offset ) ) ;
offset = 15 ;
ESPSDTR ( ( " sending back new offset \n " ) ) ;
build_sync_nego_msg ( esp , period , offset ) ;
return EXTENDED_MESSAGE ;
}
if ( offset & & period > esp - > max_period ) {
/* Yeee, async for this slow device. */
ESPSDTR ( ( " period too long %2x, " , period ) ) ;
build_sync_nego_msg ( esp , 0 , 0 ) ;
ESPSDTR ( ( " hoping for msgout \n " ) ) ;
esp_advance_phase ( esp - > current_SC , in_the_dark ) ;
return EXTENDED_MESSAGE ;
} else if ( offset & & period < esp - > min_period ) {
ESPSDTR ( ( " period too short %2x, " , period ) ) ;
period = esp - > min_period ;
if ( esp - > erev > esp236 )
regval = 4 ;
else
regval = 5 ;
} else if ( offset ) {
int tmp ;
ESPSDTR ( ( " period is ok, " ) ) ;
tmp = esp - > ccycle / 1000 ;
regval = ( ( ( period < < 2 ) + tmp - 1 ) / tmp ) ;
if ( regval & & ( ( esp - > erev = = fas100a | |
esp - > erev = = fas236 | |
esp - > erev = = fashme ) ) ) {
if ( period > = 50 )
regval - - ;
}
}
if ( offset ) {
u8 bit ;
esp_dev - > sync_min_period = ( regval & 0x1f ) ;
esp_dev - > sync_max_offset = ( offset | esp - > radelay ) ;
if ( esp - > erev = = fas100a | | esp - > erev = = fas236 | | esp - > erev = = fashme ) {
if ( ( esp - > erev = = fas100a ) | | ( esp - > erev = = fashme ) )
bit = ESP_CONFIG3_FAST ;
else
bit = ESP_CONFIG3_FSCSI ;
if ( period < 50 ) {
/* On FAS366, if using fast-20 synchronous transfers
* we need to make sure the REQ / ACK assert / deassert
* control bits are clear .
*/
if ( esp - > erev = = fashme )
esp_dev - > sync_max_offset & = ~ esp - > radelay ;
esp - > config3 [ SCptr - > device - > id ] | = bit ;
} else {
esp - > config3 [ SCptr - > device - > id ] & = ~ bit ;
}
esp - > prev_cfg3 = esp - > config3 [ SCptr - > device - > id ] ;
sbus_writeb ( esp - > prev_cfg3 , esp - > eregs + ESP_CFG3 ) ;
}
esp - > prev_soff = esp_dev - > sync_max_offset ;
esp - > prev_stp = esp_dev - > sync_min_period ;
sbus_writeb ( esp - > prev_soff , esp - > eregs + ESP_SOFF ) ;
sbus_writeb ( esp - > prev_stp , esp - > eregs + ESP_STP ) ;
ESPSDTR ( ( " soff=%2x stp=%2x cfg3=%2x \n " ,
esp_dev - > sync_max_offset ,
esp_dev - > sync_min_period ,
esp - > config3 [ SCptr - > device - > id ] ) ) ;
esp - > snip = 0 ;
} else if ( esp_dev - > sync_max_offset ) {
u8 bit ;
/* back to async mode */
ESPSDTR ( ( " unaccaptable sync nego, forcing async \n " ) ) ;
esp_dev - > sync_max_offset = 0 ;
esp_dev - > sync_min_period = 0 ;
esp - > prev_soff = 0 ;
esp - > prev_stp = 0 ;
sbus_writeb ( esp - > prev_soff , esp - > eregs + ESP_SOFF ) ;
sbus_writeb ( esp - > prev_stp , esp - > eregs + ESP_STP ) ;
if ( esp - > erev = = fas100a | | esp - > erev = = fas236 | | esp - > erev = = fashme ) {
if ( ( esp - > erev = = fas100a ) | | ( esp - > erev = = fashme ) )
bit = ESP_CONFIG3_FAST ;
else
bit = ESP_CONFIG3_FSCSI ;
esp - > config3 [ SCptr - > device - > id ] & = ~ bit ;
esp - > prev_cfg3 = esp - > config3 [ SCptr - > device - > id ] ;
sbus_writeb ( esp - > prev_cfg3 , esp - > eregs + ESP_CFG3 ) ;
}
}
sync_report ( esp ) ;
ESPSDTR ( ( " chk multibyte msg: sync is known, " ) ) ;
esp_dev - > sync = 1 ;
if ( message_out ) {
ESPLOG ( ( " esp%d: sending sdtr back, hoping for msgout \n " ,
esp - > esp_id ) ) ;
build_sync_nego_msg ( esp , period , offset ) ;
esp_advance_phase ( SCptr , in_the_dark ) ;
return EXTENDED_MESSAGE ;
}
ESPSDTR ( ( " returning zero \n " ) ) ;
esp_advance_phase ( SCptr , in_the_dark ) ; /* ...or else! */
return 0 ;
} else if ( esp - > cur_msgin [ 2 ] = = EXTENDED_WDTR ) {
int size = 8 < < esp - > cur_msgin [ 3 ] ;
esp - > wnip = 0 ;
if ( esp - > erev ! = fashme ) {
ESPLOG ( ( " esp%d: AIEEE wide msg received and not HME. \n " ,
esp - > esp_id ) ) ;
message_out = MESSAGE_REJECT ;
} else if ( size > 16 ) {
ESPLOG ( ( " esp%d: AIEEE wide transfer for %d size "
" not supported. \n " , esp - > esp_id , size ) ) ;
message_out = MESSAGE_REJECT ;
} else {
/* Things look good; let's see what we got. */
if ( size = = 16 ) {
/* Set config 3 register for this target. */
esp - > config3 [ SCptr - > device - > id ] | = ESP_CONFIG3_EWIDE ;
} else {
/* Just make sure it was one byte sized. */
if ( size ! = 8 ) {
ESPLOG ( ( " esp%d: Aieee, wide nego of %d size. \n " ,
esp - > esp_id , size ) ) ;
message_out = MESSAGE_REJECT ;
goto finish ;
}
/* Pure paranoia. */
esp - > config3 [ SCptr - > device - > id ] & = ~ ( ESP_CONFIG3_EWIDE ) ;
}
esp - > prev_cfg3 = esp - > config3 [ SCptr - > device - > id ] ;
sbus_writeb ( esp - > prev_cfg3 , esp - > eregs + ESP_CFG3 ) ;
/* Regardless, next try for sync transfers. */
build_sync_nego_msg ( esp , esp - > sync_defp , 15 ) ;
esp_dev - > sync = 1 ;
esp - > snip = 1 ;
message_out = EXTENDED_MESSAGE ;
}
} else if ( esp - > cur_msgin [ 2 ] = = EXTENDED_MODIFY_DATA_POINTER ) {
ESPLOG ( ( " esp%d: rejecting modify data ptr msg \n " , esp - > esp_id ) ) ;
message_out = MESSAGE_REJECT ;
}
finish :
esp_advance_phase ( SCptr , in_the_dark ) ;
return message_out ;
}
static int esp_do_msgindone ( struct esp * esp )
{
struct scsi_cmnd * SCptr = esp - > current_SC ;
int message_out = 0 , it = 0 , rval ;
rval = skipahead1 ( esp , SCptr , in_msgin , in_msgindone ) ;
if ( rval )
return rval ;
if ( SCptr - > SCp . sent_command ! = in_status ) {
if ( ! ( esp - > ireg & ESP_INTR_DC ) ) {
if ( esp - > msgin_len & & ( esp - > sreg & ESP_STAT_PERR ) ) {
message_out = MSG_PARITY_ERROR ;
esp_cmd ( esp , ESP_CMD_FLUSH ) ;
} else if ( esp - > erev ! = fashme & &
( it = ( sbus_readb ( esp - > eregs + ESP_FFLAGS ) & ESP_FF_FBYTES ) ) ! = 1 ) {
/* We certainly dropped the ball somewhere. */
message_out = INITIATOR_ERROR ;
esp_cmd ( esp , ESP_CMD_FLUSH ) ;
} else if ( ! esp - > msgin_len ) {
if ( esp - > erev = = fashme )
it = esp - > hme_fifo_workaround_buffer [ 0 ] ;
else
it = sbus_readb ( esp - > eregs + ESP_FDATA ) ;
esp_advance_phase ( SCptr , in_msgincont ) ;
} else {
/* it is ok and we want it */
if ( esp - > erev = = fashme )
it = esp - > cur_msgin [ esp - > msgin_ctr ] =
esp - > hme_fifo_workaround_buffer [ 0 ] ;
else
it = esp - > cur_msgin [ esp - > msgin_ctr ] =
sbus_readb ( esp - > eregs + ESP_FDATA ) ;
esp - > msgin_ctr + + ;
}
} else {
esp_advance_phase ( SCptr , in_the_dark ) ;
return do_work_bus ;
}
} else {
it = esp - > cur_msgin [ 0 ] ;
}
if ( ! message_out & & esp - > msgin_len ) {
if ( esp - > msgin_ctr < esp - > msgin_len ) {
esp_advance_phase ( SCptr , in_msgincont ) ;
} else if ( esp - > msgin_len = = 1 ) {
message_out = check_singlebyte_msg ( esp ) ;
} else if ( esp - > msgin_len = = 2 ) {
if ( esp - > cur_msgin [ 0 ] = = EXTENDED_MESSAGE ) {
if ( ( it + 2 ) > = 15 ) {
message_out = MESSAGE_REJECT ;
} else {
esp - > msgin_len = ( it + 2 ) ;
esp_advance_phase ( SCptr , in_msgincont ) ;
}
} else {
message_out = MESSAGE_REJECT ; /* foo on you */
}
} else {
message_out = check_multibyte_msg ( esp ) ;
}
}
if ( message_out < 0 ) {
return - message_out ;
} else if ( message_out ) {
if ( ( ( message_out ! = 1 ) & &
( ( message_out < 0x20 ) | | ( message_out & 0x80 ) ) ) )
esp - > msgout_len = 1 ;
esp - > cur_msgout [ 0 ] = message_out ;
esp_cmd ( esp , ESP_CMD_SATN ) ;
esp_advance_phase ( SCptr , in_the_dark ) ;
esp - > msgin_len = 0 ;
}
esp - > sreg = sbus_readb ( esp - > eregs + ESP_STATUS ) ;
esp - > sreg & = ~ ( ESP_STAT_INTR ) ;
if ( ( esp - > sreg & ( ESP_STAT_PMSG | ESP_STAT_PCD ) ) = = ( ESP_STAT_PMSG | ESP_STAT_PCD ) )
esp_cmd ( esp , ESP_CMD_MOK ) ;
if ( ( SCptr - > SCp . sent_command = = in_msgindone ) & &
( SCptr - > SCp . phase = = in_freeing ) )
return esp_do_freebus ( esp ) ;
return do_intr_end ;
}
static int esp_do_cmdbegin ( struct esp * esp )
{
struct scsi_cmnd * SCptr = esp - > current_SC ;
esp_advance_phase ( SCptr , in_cmdend ) ;
if ( esp - > erev = = fashme ) {
u32 tmp = sbus_readl ( esp - > dregs + DMA_CSR ) ;
int i ;
for ( i = 0 ; i < esp - > esp_scmdleft ; i + + )
esp - > esp_command [ i ] = * esp - > esp_scmdp + + ;
esp - > esp_scmdleft = 0 ;
esp_cmd ( esp , ESP_CMD_FLUSH ) ;
esp_setcount ( esp - > eregs , i , 1 ) ;
esp_cmd ( esp , ( ESP_CMD_DMA | ESP_CMD_TI ) ) ;
tmp | = ( DMA_SCSI_DISAB | DMA_ENABLE ) ;
tmp & = ~ ( DMA_ST_WRITE ) ;
sbus_writel ( i , esp - > dregs + DMA_COUNT ) ;
sbus_writel ( esp - > esp_command_dvma , esp - > dregs + DMA_ADDR ) ;
sbus_writel ( tmp , esp - > dregs + DMA_CSR ) ;
} else {
u8 tmp ;
esp_cmd ( esp , ESP_CMD_FLUSH ) ;
tmp = * esp - > esp_scmdp + + ;
esp - > esp_scmdleft - - ;
sbus_writeb ( tmp , esp - > eregs + ESP_FDATA ) ;
esp_cmd ( esp , ESP_CMD_TI ) ;
}
return do_intr_end ;
}
static int esp_do_cmddone ( struct esp * esp )
{
if ( esp - > erev = = fashme )
dma_invalidate ( esp ) ;
else
esp_cmd ( esp , ESP_CMD_NULL ) ;
if ( esp - > ireg & ESP_INTR_BSERV ) {
esp_advance_phase ( esp - > current_SC , in_the_dark ) ;
return esp_do_phase_determine ( esp ) ;
}
ESPLOG ( ( " esp%d: in do_cmddone() but didn't get BSERV interrupt. \n " ,
esp - > esp_id ) ) ;
return do_reset_bus ;
}
static int esp_do_msgout ( struct esp * esp )
{
esp_cmd ( esp , ESP_CMD_FLUSH ) ;
switch ( esp - > msgout_len ) {
case 1 :
if ( esp - > erev = = fashme )
hme_fifo_push ( esp , & esp - > cur_msgout [ 0 ] , 1 ) ;
else
sbus_writeb ( esp - > cur_msgout [ 0 ] , esp - > eregs + ESP_FDATA ) ;
esp_cmd ( esp , ESP_CMD_TI ) ;
break ;
case 2 :
esp - > esp_command [ 0 ] = esp - > cur_msgout [ 0 ] ;
esp - > esp_command [ 1 ] = esp - > cur_msgout [ 1 ] ;
if ( esp - > erev = = fashme ) {
hme_fifo_push ( esp , & esp - > cur_msgout [ 0 ] , 2 ) ;
esp_cmd ( esp , ESP_CMD_TI ) ;
} else {
dma_setup ( esp , esp - > esp_command_dvma , 2 , 0 ) ;
esp_setcount ( esp - > eregs , 2 , 0 ) ;
esp_cmd ( esp , ESP_CMD_DMA | ESP_CMD_TI ) ;
}
break ;
case 4 :
esp - > esp_command [ 0 ] = esp - > cur_msgout [ 0 ] ;
esp - > esp_command [ 1 ] = esp - > cur_msgout [ 1 ] ;
esp - > esp_command [ 2 ] = esp - > cur_msgout [ 2 ] ;
esp - > esp_command [ 3 ] = esp - > cur_msgout [ 3 ] ;
esp - > snip = 1 ;
if ( esp - > erev = = fashme ) {
hme_fifo_push ( esp , & esp - > cur_msgout [ 0 ] , 4 ) ;
esp_cmd ( esp , ESP_CMD_TI ) ;
} else {
dma_setup ( esp , esp - > esp_command_dvma , 4 , 0 ) ;
esp_setcount ( esp - > eregs , 4 , 0 ) ;
esp_cmd ( esp , ESP_CMD_DMA | ESP_CMD_TI ) ;
}
break ;
case 5 :
esp - > esp_command [ 0 ] = esp - > cur_msgout [ 0 ] ;
esp - > esp_command [ 1 ] = esp - > cur_msgout [ 1 ] ;
esp - > esp_command [ 2 ] = esp - > cur_msgout [ 2 ] ;
esp - > esp_command [ 3 ] = esp - > cur_msgout [ 3 ] ;
esp - > esp_command [ 4 ] = esp - > cur_msgout [ 4 ] ;
esp - > snip = 1 ;
if ( esp - > erev = = fashme ) {
hme_fifo_push ( esp , & esp - > cur_msgout [ 0 ] , 5 ) ;
esp_cmd ( esp , ESP_CMD_TI ) ;
} else {
dma_setup ( esp , esp - > esp_command_dvma , 5 , 0 ) ;
esp_setcount ( esp - > eregs , 5 , 0 ) ;
esp_cmd ( esp , ESP_CMD_DMA | ESP_CMD_TI ) ;
}
break ;
default :
/* whoops */
ESPMISC ( ( " bogus msgout sending NOP \n " ) ) ;
esp - > cur_msgout [ 0 ] = NOP ;
if ( esp - > erev = = fashme ) {
hme_fifo_push ( esp , & esp - > cur_msgout [ 0 ] , 1 ) ;
} else {
sbus_writeb ( esp - > cur_msgout [ 0 ] , esp - > eregs + ESP_FDATA ) ;
}
esp - > msgout_len = 1 ;
esp_cmd ( esp , ESP_CMD_TI ) ;
break ;
} ;
esp_advance_phase ( esp - > current_SC , in_msgoutdone ) ;
return do_intr_end ;
}
static int esp_do_msgoutdone ( struct esp * esp )
{
if ( esp - > msgout_len > 1 ) {
/* XXX HME/FAS ATN deassert workaround required,
* XXX no DMA flushing , only possible ESP_CMD_FLUSH
* XXX to kill the fifo .
*/
if ( esp - > erev ! = fashme ) {
u32 tmp ;
while ( ( tmp = sbus_readl ( esp - > dregs + DMA_CSR ) ) & DMA_PEND_READ )
udelay ( 1 ) ;
tmp & = ~ DMA_ENABLE ;
sbus_writel ( tmp , esp - > dregs + DMA_CSR ) ;
dma_invalidate ( esp ) ;
} else {
esp_cmd ( esp , ESP_CMD_FLUSH ) ;
}
}
if ( ! ( esp - > ireg & ESP_INTR_DC ) ) {
if ( esp - > erev ! = fashme )
esp_cmd ( esp , ESP_CMD_NULL ) ;
switch ( esp - > sreg & ESP_STAT_PMASK ) {
case ESP_MOP :
/* whoops, parity error */
ESPLOG ( ( " esp%d: still in msgout, parity error assumed \n " ,
esp - > esp_id ) ) ;
if ( esp - > msgout_len > 1 )
esp_cmd ( esp , ESP_CMD_SATN ) ;
esp_advance_phase ( esp - > current_SC , in_msgout ) ;
return do_work_bus ;
case ESP_DIP :
break ;
default :
/* Happy Meal fifo is touchy... */
if ( ( esp - > erev ! = fashme ) & &
! fcount ( esp ) & &
! ( ( ( struct esp_device * ) esp - > current_SC - > device - > hostdata ) - > sync_max_offset ) )
esp_cmd ( esp , ESP_CMD_FLUSH ) ;
break ;
} ;
} else {
ESPLOG ( ( " esp%d: disconnect, resetting bus \n " , esp - > esp_id ) ) ;
return do_reset_bus ;
}
/* If we sent out a synchronous negotiation message, update
* our state .
*/
if ( esp - > cur_msgout [ 2 ] = = EXTENDED_MESSAGE & &
esp - > cur_msgout [ 4 ] = = EXTENDED_SDTR ) {
esp - > snip = 1 ; /* anal retentiveness... */
}
esp - > prevmsgout = esp - > cur_msgout [ 0 ] ;
esp - > msgout_len = 0 ;
esp_advance_phase ( esp - > current_SC , in_the_dark ) ;
return esp_do_phase_determine ( esp ) ;
}
static int esp_bus_unexpected ( struct esp * esp )
{
ESPLOG ( ( " esp%d: command in weird state %2x \n " ,
esp - > esp_id , esp - > current_SC - > SCp . phase ) ) ;
return do_reset_bus ;
}
static espfunc_t bus_vector [ ] = {
esp_do_data_finale ,
esp_do_data_finale ,
esp_bus_unexpected ,
esp_do_msgin ,
esp_do_msgincont ,
esp_do_msgindone ,
esp_do_msgout ,
esp_do_msgoutdone ,
esp_do_cmdbegin ,
esp_do_cmddone ,
esp_do_status ,
esp_do_freebus ,
esp_do_phase_determine ,
esp_bus_unexpected ,
esp_bus_unexpected ,
esp_bus_unexpected ,
} ;
/* This is the second tier in our dual-level SCSI state machine. */
static int esp_work_bus ( struct esp * esp )
{
struct scsi_cmnd * SCptr = esp - > current_SC ;
unsigned int phase ;
ESPBUS ( ( " esp_work_bus: " ) ) ;
if ( ! SCptr ) {
ESPBUS ( ( " reconnect \n " ) ) ;
return esp_do_reconnect ( esp ) ;
}
phase = SCptr - > SCp . phase ;
if ( ( phase & 0xf0 ) = = in_phases_mask )
return bus_vector [ ( phase & 0x0f ) ] ( esp ) ;
else if ( ( phase & 0xf0 ) = = in_slct_mask )
return esp_select_complete ( esp ) ;
else
return esp_bus_unexpected ( esp ) ;
}
static espfunc_t isvc_vector [ ] = {
2005-04-26 18:43:42 +04:00
NULL ,
2005-04-17 02:20:36 +04:00
esp_do_phase_determine ,
esp_do_resetbus ,
esp_finish_reset ,
esp_work_bus
} ;
/* Main interrupt handler for an esp adapter. */
static void esp_handle ( struct esp * esp )
{
struct scsi_cmnd * SCptr ;
int what_next = do_intr_end ;
SCptr = esp - > current_SC ;
/* Check for errors. */
esp - > sreg = sbus_readb ( esp - > eregs + ESP_STATUS ) ;
esp - > sreg & = ( ~ ESP_STAT_INTR ) ;
if ( esp - > erev = = fashme ) {
esp - > sreg2 = sbus_readb ( esp - > eregs + ESP_STATUS2 ) ;
esp - > seqreg = ( sbus_readb ( esp - > eregs + ESP_SSTEP ) & ESP_STEP_VBITS ) ;
}
if ( esp - > sreg & ( ESP_STAT_SPAM ) ) {
/* Gross error, could be due to one of:
*
* - top of fifo overwritten , could be because
* we tried to do a synchronous transfer with
* an offset greater than ESP fifo size
*
* - top of command register overwritten
*
* - DMA setup to go in one direction , SCSI
* bus points in the other , whoops
*
* - weird phase change during asynchronous
* data phase while we are initiator
*/
ESPLOG ( ( " esp%d: Gross error sreg=%2x \n " , esp - > esp_id , esp - > sreg ) ) ;
/* If a command is live on the bus we cannot safely
* reset the bus , so we ' ll just let the pieces fall
* where they may . Here we are hoping that the
* target will be able to cleanly go away soon
* so we can safely reset things .
*/
if ( ! SCptr ) {
ESPLOG ( ( " esp%d: No current cmd during gross error, "
" resetting bus \n " , esp - > esp_id ) ) ;
what_next = do_reset_bus ;
goto state_machine ;
}
}
if ( sbus_readl ( esp - > dregs + DMA_CSR ) & DMA_HNDL_ERROR ) {
/* A DMA gate array error. Here we must
* be seeing one of two things . Either the
* virtual to physical address translation
* on the SBUS could not occur , else the
* translation it did get pointed to a bogus
* page . Ho hum . . .
*/
ESPLOG ( ( " esp%d: DMA error %08x \n " , esp - > esp_id ,
sbus_readl ( esp - > dregs + DMA_CSR ) ) ) ;
/* DMA gate array itself must be reset to clear the
* error condition .
*/
esp_reset_dma ( esp ) ;
what_next = do_reset_bus ;
goto state_machine ;
}
esp - > ireg = sbus_readb ( esp - > eregs + ESP_INTRPT ) ; /* Unlatch intr reg */
if ( esp - > erev = = fashme ) {
/* This chip is really losing. */
ESPHME ( ( " HME[ " ) ) ;
ESPHME ( ( " sreg2=%02x, " , esp - > sreg2 ) ) ;
/* Must latch fifo before reading the interrupt
* register else garbage ends up in the FIFO
* which confuses the driver utterly .
*/
if ( ! ( esp - > sreg2 & ESP_STAT2_FEMPTY ) | |
( esp - > sreg2 & ESP_STAT2_F1BYTE ) ) {
ESPHME ( ( " fifo_workaround] " ) ) ;
hme_fifo_read ( esp ) ;
} else {
ESPHME ( ( " no_fifo_workaround] " ) ) ;
}
}
/* No current cmd is only valid at this point when there are
* commands off the bus or we are trying a reset .
*/
if ( ! SCptr & & ! esp - > disconnected_SC & & ! ( esp - > ireg & ESP_INTR_SR ) ) {
/* Panic is safe, since current_SC is null. */
ESPLOG ( ( " esp%d: no command in esp_handle() \n " , esp - > esp_id ) ) ;
panic ( " esp_handle: current_SC == penguin within interrupt! " ) ;
}
if ( esp - > ireg & ( ESP_INTR_IC ) ) {
/* Illegal command fed to ESP. Outside of obvious
* software bugs that could cause this , there is
* a condition with esp100 where we can confuse the
* ESP into an erroneous illegal command interrupt
* because it does not scrape the FIFO properly
* for reselection . See esp100_reconnect_hwbug ( )
* to see how we try very hard to avoid this .
*/
ESPLOG ( ( " esp%d: invalid command \n " , esp - > esp_id ) ) ;
esp_dump_state ( esp ) ;
if ( SCptr ! = NULL ) {
/* Devices with very buggy firmware can drop BSY
* during a scatter list interrupt when using sync
* mode transfers . We continue the transfer as
* expected , the target drops the bus , the ESP
* gets confused , and we get a illegal command
* interrupt because the bus is in the disconnected
* state now and ESP_CMD_TI is only allowed when
* a nexus is alive on the bus .
*/
ESPLOG ( ( " esp%d: Forcing async and disabling disconnect for "
" target %d \n " , esp - > esp_id , SCptr - > device - > id ) ) ;
SCptr - > device - > borken = 1 ; /* foo on you */
}
what_next = do_reset_bus ;
} else if ( ! ( esp - > ireg & ~ ( ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC ) ) ) {
if ( SCptr ) {
unsigned int phase = SCptr - > SCp . phase ;
if ( phase & in_phases_mask ) {
what_next = esp_work_bus ( esp ) ;
} else if ( phase & in_slct_mask ) {
what_next = esp_select_complete ( esp ) ;
} else {
ESPLOG ( ( " esp%d: interrupt for no good reason... \n " ,
esp - > esp_id ) ) ;
what_next = do_intr_end ;
}
} else {
ESPLOG ( ( " esp%d: BSERV or FDONE or DC while SCptr==NULL \n " ,
esp - > esp_id ) ) ;
what_next = do_reset_bus ;
}
} else if ( esp - > ireg & ESP_INTR_SR ) {
ESPLOG ( ( " esp%d: SCSI bus reset interrupt \n " , esp - > esp_id ) ) ;
what_next = do_reset_complete ;
} else if ( esp - > ireg & ( ESP_INTR_S | ESP_INTR_SATN ) ) {
ESPLOG ( ( " esp%d: AIEEE we have been selected by another initiator! \n " ,
esp - > esp_id ) ) ;
what_next = do_reset_bus ;
} else if ( esp - > ireg & ESP_INTR_RSEL ) {
if ( SCptr = = NULL ) {
/* This is ok. */
what_next = esp_do_reconnect ( esp ) ;
} else if ( SCptr - > SCp . phase & in_slct_mask ) {
/* Only selection code knows how to clean
* up properly .
*/
ESPDISC ( ( " Reselected during selection attempt \n " ) ) ;
what_next = esp_select_complete ( esp ) ;
} else {
ESPLOG ( ( " esp%d: Reselected while bus is busy \n " ,
esp - > esp_id ) ) ;
what_next = do_reset_bus ;
}
}
/* This is tier-one in our dual level SCSI state machine. */
state_machine :
while ( what_next ! = do_intr_end ) {
if ( what_next > = do_phase_determine & &
what_next < do_intr_end ) {
what_next = isvc_vector [ what_next ] ( esp ) ;
} else {
/* state is completely lost ;-( */
ESPLOG ( ( " esp%d: interrupt engine loses state, resetting bus \n " ,
esp - > esp_id ) ) ;
what_next = do_reset_bus ;
}
}
}
/* Service only the ESP described by dev_id. */
static irqreturn_t esp_intr ( int irq , void * dev_id , struct pt_regs * pregs )
{
struct esp * esp = dev_id ;
unsigned long flags ;
spin_lock_irqsave ( esp - > ehost - > host_lock , flags ) ;
if ( ESP_IRQ_P ( esp - > dregs ) ) {
ESP_INTSOFF ( esp - > dregs ) ;
ESPIRQ ( ( " I[%d:%d]( " , smp_processor_id ( ) , esp - > esp_id ) ) ;
esp_handle ( esp ) ;
ESPIRQ ( ( " ) " ) ) ;
ESP_INTSON ( esp - > dregs ) ;
}
spin_unlock_irqrestore ( esp - > ehost - > host_lock , flags ) ;
return IRQ_HANDLED ;
}
static int esp_slave_alloc ( struct scsi_device * SDptr )
{
struct esp_device * esp_dev =
kmalloc ( sizeof ( struct esp_device ) , GFP_ATOMIC ) ;
if ( ! esp_dev )
return - ENOMEM ;
memset ( esp_dev , 0 , sizeof ( struct esp_device ) ) ;
SDptr - > hostdata = esp_dev ;
return 0 ;
}
static void esp_slave_destroy ( struct scsi_device * SDptr )
{
struct esp * esp = ( struct esp * ) SDptr - > host - > hostdata ;
esp - > targets_present & = ~ ( 1 < < SDptr - > id ) ;
kfree ( SDptr - > hostdata ) ;
SDptr - > hostdata = NULL ;
}
static struct scsi_host_template driver_template = {
. proc_name = " esp " ,
. proc_info = esp_proc_info ,
. name = " Sun ESP 100/100a/200 " ,
. detect = esp_detect ,
. slave_alloc = esp_slave_alloc ,
. slave_destroy = esp_slave_destroy ,
. release = esp_release ,
. info = esp_info ,
. queuecommand = esp_queue ,
. eh_abort_handler = esp_abort ,
. eh_bus_reset_handler = esp_reset ,
. can_queue = 7 ,
. this_id = 7 ,
. sg_tablesize = SG_ALL ,
. cmd_per_lun = 1 ,
. use_clustering = ENABLE_CLUSTERING ,
} ;
# include "scsi_module.c"
2005-04-25 07:35:20 +04:00
MODULE_DESCRIPTION ( " EnhancedScsiProcessor Sun SCSI driver " ) ;
MODULE_AUTHOR ( " David S. Miller (davem@redhat.com) " ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;
2005-04-25 07:35:20 +04:00
MODULE_VERSION ( DRV_VERSION ) ;
2005-04-17 02:20:36 +04:00