2005-04-17 02:20:36 +04:00
/* ppa.c -- low level driver for the IOMEGA PPA3
* parallel port SCSI host adapter .
*
* ( The PPA3 is the embedded controller in the ZIP drive . )
*
* ( c ) 1995 , 1996 Grant R . Guenther , grant @ torque . net ,
* under the terms of the GNU General Public License .
*
*/
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/blkdev.h>
# include <linux/parport.h>
# include <linux/workqueue.h>
2005-05-28 15:56:31 +04:00
# include <linux/delay.h>
2006-03-28 13:56:47 +04:00
# include <linux/jiffies.h>
2005-04-17 02:20:36 +04:00
# include <asm/io.h>
# include <scsi/scsi.h>
# include <scsi/scsi_cmnd.h>
# include <scsi/scsi_device.h>
# include <scsi/scsi_host.h>
static void ppa_reset_pulse ( unsigned int base ) ;
typedef struct {
struct pardevice * dev ; /* Parport device entry */
int base ; /* Actual port address */
int mode ; /* Transfer mode */
struct scsi_cmnd * cur_cmd ; /* Current queued command */
2006-11-22 17:57:56 +03:00
struct delayed_work ppa_tq ; /* Polling interrupt stuff */
2005-04-17 02:20:36 +04:00
unsigned long jstart ; /* Jiffies at start */
unsigned long recon_tmo ; /* How many usecs to wait for reconnection (6th bit) */
unsigned int failed : 1 ; /* Failure flag */
unsigned wanted : 1 ; /* Parport sharing busy flag */
wait_queue_head_t * waiting ;
struct Scsi_Host * host ;
struct list_head list ;
} ppa_struct ;
# include "ppa.h"
static inline ppa_struct * ppa_dev ( struct Scsi_Host * host )
{
return * ( ppa_struct * * ) & host - > hostdata ;
}
static DEFINE_SPINLOCK ( arbitration_lock ) ;
static void got_it ( ppa_struct * dev )
{
dev - > base = dev - > dev - > port - > base ;
if ( dev - > cur_cmd )
dev - > cur_cmd - > SCp . phase = 1 ;
else
wake_up ( dev - > waiting ) ;
}
static void ppa_wakeup ( void * ref )
{
ppa_struct * dev = ( ppa_struct * ) ref ;
unsigned long flags ;
spin_lock_irqsave ( & arbitration_lock , flags ) ;
if ( dev - > wanted ) {
parport_claim ( dev - > dev ) ;
got_it ( dev ) ;
dev - > wanted = 0 ;
}
spin_unlock_irqrestore ( & arbitration_lock , flags ) ;
return ;
}
static int ppa_pb_claim ( ppa_struct * dev )
{
unsigned long flags ;
int res = 1 ;
spin_lock_irqsave ( & arbitration_lock , flags ) ;
if ( parport_claim ( dev - > dev ) = = 0 ) {
got_it ( dev ) ;
res = 0 ;
}
dev - > wanted = res ;
spin_unlock_irqrestore ( & arbitration_lock , flags ) ;
return res ;
}
static void ppa_pb_dismiss ( ppa_struct * dev )
{
unsigned long flags ;
int wanted ;
spin_lock_irqsave ( & arbitration_lock , flags ) ;
wanted = dev - > wanted ;
dev - > wanted = 0 ;
spin_unlock_irqrestore ( & arbitration_lock , flags ) ;
if ( ! wanted )
parport_release ( dev - > dev ) ;
}
static inline void ppa_pb_release ( ppa_struct * dev )
{
parport_release ( dev - > dev ) ;
}
/*
* Start of Chipset kludges
*/
/* This is to give the ppa driver a way to modify the timings (and other
* parameters ) by writing to the / proc / scsi / ppa / 0 file .
* Very simple method really . . . ( To simple , no error checking : ( )
* Reason : Kernel hackers HATE having to unload and reload modules for
* testing . . .
* Also gives a method to use a script to obtain optimum timings ( TODO )
*/
static inline int ppa_proc_write ( ppa_struct * dev , char * buffer , int length )
{
unsigned long x ;
if ( ( length > 5 ) & & ( strncmp ( buffer , " mode= " , 5 ) = = 0 ) ) {
x = simple_strtoul ( buffer + 5 , NULL , 0 ) ;
dev - > mode = x ;
return length ;
}
if ( ( length > 10 ) & & ( strncmp ( buffer , " recon_tmo= " , 10 ) = = 0 ) ) {
x = simple_strtoul ( buffer + 10 , NULL , 0 ) ;
dev - > recon_tmo = x ;
2007-07-09 23:00:10 +04:00
printk ( KERN_INFO " ppa: recon_tmo set to %ld \n " , x ) ;
2005-04-17 02:20:36 +04:00
return length ;
}
2007-07-09 23:00:10 +04:00
printk ( KERN_WARNING " ppa /proc: invalid variable \n " ) ;
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
static int ppa_proc_info ( struct Scsi_Host * host , char * buffer , char * * start , off_t offset , int length , int inout )
{
int len = 0 ;
ppa_struct * dev = ppa_dev ( host ) ;
if ( inout )
return ppa_proc_write ( dev , buffer , length ) ;
len + = sprintf ( buffer + len , " Version : %s \n " , PPA_VERSION ) ;
len + =
sprintf ( buffer + len , " Parport : %s \n " ,
dev - > dev - > port - > name ) ;
len + =
sprintf ( buffer + len , " Mode : %s \n " ,
PPA_MODE_STRING [ dev - > mode ] ) ;
# if PPA_DEBUG > 0
len + =
sprintf ( buffer + len , " recon_tmo : %lu \n " , dev - > recon_tmo ) ;
# endif
/* Request for beyond end of buffer */
if ( offset > length )
return 0 ;
* start = buffer + offset ;
len - = offset ;
if ( len > length )
len = length ;
return len ;
}
static int device_check ( ppa_struct * dev ) ;
# if PPA_DEBUG > 0
# define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\
2008-07-04 10:47:27 +04:00
y , __func__ , __LINE__ ) ; ppa_fail_func ( x , y ) ;
2005-04-17 02:20:36 +04:00
static inline void ppa_fail_func ( ppa_struct * dev , int error_code )
# else
static inline void ppa_fail ( ppa_struct * dev , int error_code )
# endif
{
/* If we fail a device then we trash status / message bytes */
if ( dev - > cur_cmd ) {
dev - > cur_cmd - > result = error_code < < 16 ;
dev - > failed = 1 ;
}
}
/*
* Wait for the high bit to be set .
*
* In principle , this could be tied to an interrupt , but the adapter
* doesn ' t appear to be designed to support interrupts . We spin on
* the 0x80 ready bit .
*/
static unsigned char ppa_wait ( ppa_struct * dev )
{
int k ;
unsigned short ppb = dev - > base ;
unsigned char r ;
k = PPA_SPIN_TMO ;
/* Wait for bit 6 and 7 - PJC */
for ( r = r_str ( ppb ) ; ( ( r & 0xc0 ) ! = 0xc0 ) & & ( k ) ; k - - ) {
udelay ( 1 ) ;
r = r_str ( ppb ) ;
}
/*
* return some status information .
* Semantics : 0xc0 = ZIP wants more data
* 0xd0 = ZIP wants to send more data
* 0xe0 = ZIP is expecting SCSI command data
* 0xf0 = end of transfer , ZIP is sending status
*/
if ( k )
return ( r & 0xf0 ) ;
/* Counter expired - Time out occurred */
ppa_fail ( dev , DID_TIME_OUT ) ;
2007-07-09 23:00:10 +04:00
printk ( KERN_WARNING " ppa timeout in ppa_wait \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ; /* command timed out */
}
/*
* Clear EPP Timeout Bit
*/
static inline void epp_reset ( unsigned short ppb )
{
int i ;
i = r_str ( ppb ) ;
w_str ( ppb , i ) ;
w_str ( ppb , i & 0xfe ) ;
}
/*
* Wait for empty ECP fifo ( if we are in ECP fifo mode only )
*/
static inline void ecp_sync ( ppa_struct * dev )
{
int i , ppb_hi = dev - > dev - > port - > base_hi ;
if ( ppb_hi = = 0 )
return ;
if ( ( r_ecr ( ppb_hi ) & 0xe0 ) = = 0x60 ) { /* mode 011 == ECP fifo mode */
for ( i = 0 ; i < 100 ; i + + ) {
if ( r_ecr ( ppb_hi ) & 0x01 )
return ;
udelay ( 5 ) ;
}
2007-07-09 23:00:10 +04:00
printk ( KERN_WARNING " ppa: ECP sync failed as data still present in FIFO. \n " ) ;
2005-04-17 02:20:36 +04:00
}
}
static int ppa_byte_out ( unsigned short base , const char * buffer , int len )
{
int i ;
for ( i = len ; i ; i - - ) {
w_dtr ( base , * buffer + + ) ;
w_ctr ( base , 0xe ) ;
w_ctr ( base , 0xc ) ;
}
return 1 ; /* All went well - we hope! */
}
static int ppa_byte_in ( unsigned short base , char * buffer , int len )
{
int i ;
for ( i = len ; i ; i - - ) {
* buffer + + = r_dtr ( base ) ;
w_ctr ( base , 0x27 ) ;
w_ctr ( base , 0x25 ) ;
}
return 1 ; /* All went well - we hope! */
}
static int ppa_nibble_in ( unsigned short base , char * buffer , int len )
{
for ( ; len ; len - - ) {
unsigned char h ;
w_ctr ( base , 0x4 ) ;
h = r_str ( base ) & 0xf0 ;
w_ctr ( base , 0x6 ) ;
* buffer + + = h | ( ( r_str ( base ) & 0xf0 ) > > 4 ) ;
}
return 1 ; /* All went well - we hope! */
}
static int ppa_out ( ppa_struct * dev , char * buffer , int len )
{
int r ;
unsigned short ppb = dev - > base ;
r = ppa_wait ( dev ) ;
if ( ( r & 0x50 ) ! = 0x40 ) {
ppa_fail ( dev , DID_ERROR ) ;
return 0 ;
}
switch ( dev - > mode ) {
case PPA_NIBBLE :
case PPA_PS2 :
/* 8 bit output, with a loop */
r = ppa_byte_out ( ppb , buffer , len ) ;
break ;
case PPA_EPP_32 :
case PPA_EPP_16 :
case PPA_EPP_8 :
epp_reset ( ppb ) ;
w_ctr ( ppb , 0x4 ) ;
# ifdef CONFIG_SCSI_IZIP_EPP16
if ( ! ( ( ( long ) buffer | len ) & 0x01 ) )
outsw ( ppb + 4 , buffer , len > > 1 ) ;
# else
if ( ! ( ( ( long ) buffer | len ) & 0x03 ) )
outsl ( ppb + 4 , buffer , len > > 2 ) ;
# endif
else
outsb ( ppb + 4 , buffer , len ) ;
w_ctr ( ppb , 0xc ) ;
r = ! ( r_str ( ppb ) & 0x01 ) ;
w_ctr ( ppb , 0xc ) ;
ecp_sync ( dev ) ;
break ;
default :
2007-07-09 23:00:10 +04:00
printk ( KERN_ERR " PPA: bug in ppa_out() \n " ) ;
2005-04-17 02:20:36 +04:00
r = 0 ;
}
return r ;
}
static int ppa_in ( ppa_struct * dev , char * buffer , int len )
{
int r ;
unsigned short ppb = dev - > base ;
r = ppa_wait ( dev ) ;
if ( ( r & 0x50 ) ! = 0x50 ) {
ppa_fail ( dev , DID_ERROR ) ;
return 0 ;
}
switch ( dev - > mode ) {
case PPA_NIBBLE :
/* 4 bit input, with a loop */
r = ppa_nibble_in ( ppb , buffer , len ) ;
w_ctr ( ppb , 0xc ) ;
break ;
case PPA_PS2 :
/* 8 bit input, with a loop */
w_ctr ( ppb , 0x25 ) ;
r = ppa_byte_in ( ppb , buffer , len ) ;
w_ctr ( ppb , 0x4 ) ;
w_ctr ( ppb , 0xc ) ;
break ;
case PPA_EPP_32 :
case PPA_EPP_16 :
case PPA_EPP_8 :
epp_reset ( ppb ) ;
w_ctr ( ppb , 0x24 ) ;
# ifdef CONFIG_SCSI_IZIP_EPP16
if ( ! ( ( ( long ) buffer | len ) & 0x01 ) )
insw ( ppb + 4 , buffer , len > > 1 ) ;
# else
if ( ! ( ( ( long ) buffer | len ) & 0x03 ) )
insl ( ppb + 4 , buffer , len > > 2 ) ;
# endif
else
insb ( ppb + 4 , buffer , len ) ;
w_ctr ( ppb , 0x2c ) ;
r = ! ( r_str ( ppb ) & 0x01 ) ;
w_ctr ( ppb , 0x2c ) ;
ecp_sync ( dev ) ;
break ;
default :
2007-07-09 23:00:10 +04:00
printk ( KERN_ERR " PPA: bug in ppa_ins() \n " ) ;
2005-04-17 02:20:36 +04:00
r = 0 ;
break ;
}
return r ;
}
/* end of ppa_io.h */
static inline void ppa_d_pulse ( unsigned short ppb , unsigned char b )
{
w_dtr ( ppb , b ) ;
w_ctr ( ppb , 0xc ) ;
w_ctr ( ppb , 0xe ) ;
w_ctr ( ppb , 0xc ) ;
w_ctr ( ppb , 0x4 ) ;
w_ctr ( ppb , 0xc ) ;
}
static void ppa_disconnect ( ppa_struct * dev )
{
unsigned short ppb = dev - > base ;
ppa_d_pulse ( ppb , 0 ) ;
ppa_d_pulse ( ppb , 0x3c ) ;
ppa_d_pulse ( ppb , 0x20 ) ;
ppa_d_pulse ( ppb , 0xf ) ;
}
static inline void ppa_c_pulse ( unsigned short ppb , unsigned char b )
{
w_dtr ( ppb , b ) ;
w_ctr ( ppb , 0x4 ) ;
w_ctr ( ppb , 0x6 ) ;
w_ctr ( ppb , 0x4 ) ;
w_ctr ( ppb , 0xc ) ;
}
static inline void ppa_connect ( ppa_struct * dev , int flag )
{
unsigned short ppb = dev - > base ;
ppa_c_pulse ( ppb , 0 ) ;
ppa_c_pulse ( ppb , 0x3c ) ;
ppa_c_pulse ( ppb , 0x20 ) ;
if ( ( flag = = CONNECT_EPP_MAYBE ) & & IN_EPP_MODE ( dev - > mode ) )
ppa_c_pulse ( ppb , 0xcf ) ;
else
ppa_c_pulse ( ppb , 0x8f ) ;
}
static int ppa_select ( ppa_struct * dev , int target )
{
int k ;
unsigned short ppb = dev - > base ;
/*
* Bit 6 ( 0x40 ) is the device selected bit .
* First we must wait till the current device goes off line . . .
*/
k = PPA_SELECT_TMO ;
do {
k - - ;
udelay ( 1 ) ;
} while ( ( r_str ( ppb ) & 0x40 ) & & ( k ) ) ;
if ( ! k )
return 0 ;
w_dtr ( ppb , ( 1 < < target ) ) ;
w_ctr ( ppb , 0xe ) ;
w_ctr ( ppb , 0xc ) ;
w_dtr ( ppb , 0x80 ) ; /* This is NOT the initator */
w_ctr ( ppb , 0x8 ) ;
k = PPA_SELECT_TMO ;
do {
k - - ;
udelay ( 1 ) ;
}
while ( ! ( r_str ( ppb ) & 0x40 ) & & ( k ) ) ;
if ( ! k )
return 0 ;
return 1 ;
}
/*
* This is based on a trace of what the Iomega DOS ' guest ' driver does .
* I ' ve tried several different kinds of parallel ports with guest and
* coded this to react in the same ways that it does .
*
* The return value from this function is just a hint about where the
* handshaking failed .
*
*/
static int ppa_init ( ppa_struct * dev )
{
int retv ;
unsigned short ppb = dev - > base ;
ppa_disconnect ( dev ) ;
ppa_connect ( dev , CONNECT_NORMAL ) ;
retv = 2 ; /* Failed */
w_ctr ( ppb , 0xe ) ;
if ( ( r_str ( ppb ) & 0x08 ) = = 0x08 )
retv - - ;
w_ctr ( ppb , 0xc ) ;
if ( ( r_str ( ppb ) & 0x08 ) = = 0x00 )
retv - - ;
if ( ! retv )
ppa_reset_pulse ( ppb ) ;
udelay ( 1000 ) ; /* Allow devices to settle down */
ppa_disconnect ( dev ) ;
udelay ( 1000 ) ; /* Another delay to allow devices to settle */
if ( retv )
return - EIO ;
return device_check ( dev ) ;
}
static inline int ppa_send_command ( struct scsi_cmnd * cmd )
{
ppa_struct * dev = ppa_dev ( cmd - > device - > host ) ;
int k ;
w_ctr ( dev - > base , 0x0c ) ;
for ( k = 0 ; k < cmd - > cmd_len ; k + + )
if ( ! ppa_out ( dev , & cmd - > cmnd [ k ] , 1 ) )
return 0 ;
return 1 ;
}
/*
* The bulk flag enables some optimisations in the data transfer loops ,
* it should be true for any command that transfers data in integral
* numbers of sectors .
*
* The driver appears to remain stable if we speed up the parallel port
* i / o in this function , but not elsewhere .
*/
static int ppa_completion ( struct scsi_cmnd * cmd )
{
/* Return codes:
* - 1 Error
* 0 Told to schedule
* 1 Finished data transfer
*/
ppa_struct * dev = ppa_dev ( cmd - > device - > host ) ;
unsigned short ppb = dev - > base ;
unsigned long start_jiffies = jiffies ;
unsigned char r , v ;
int fast , bulk , status ;
v = cmd - > cmnd [ 0 ] ;
bulk = ( ( v = = READ_6 ) | |
( v = = READ_10 ) | | ( v = = WRITE_6 ) | | ( v = = WRITE_10 ) ) ;
/*
* We only get here if the drive is ready to comunicate ,
* hence no need for a full ppa_wait .
*/
r = ( r_str ( ppb ) & 0xf0 ) ;
while ( r ! = ( unsigned char ) 0xf0 ) {
/*
* If we have been running for more than a full timer tick
* then take a rest .
*/
if ( time_after ( jiffies , start_jiffies + 1 ) )
return 0 ;
if ( ( cmd - > SCp . this_residual < = 0 ) ) {
ppa_fail ( dev , DID_ERROR ) ;
return - 1 ; /* ERROR_RETURN */
}
/* On some hardware we have SCSI disconnected (6th bit low)
* for about 100u secs . It is too expensive to wait a
* tick on every loop so we busy wait for no more than
* 500u secs to give the drive a chance first . We do not
* change things for " normal " hardware since generally
* the 6 th bit is always high .
* This makes the CPU load higher on some hardware
* but otherwise we can not get more than 50 K / secs
* on this problem hardware .
*/
if ( ( r & 0xc0 ) ! = 0xc0 ) {
/* Wait for reconnection should be no more than
* jiffy / 2 = 5 ms = 5000 loops
*/
unsigned long k = dev - > recon_tmo ;
for ( ; k & & ( ( r = ( r_str ( ppb ) & 0xf0 ) ) & 0xc0 ) ! = 0xc0 ;
k - - )
udelay ( 1 ) ;
if ( ! k )
return 0 ;
}
/* determine if we should use burst I/O */
fast = ( bulk & & ( cmd - > SCp . this_residual > = PPA_BURST_SIZE ) )
? PPA_BURST_SIZE : 1 ;
if ( r = = ( unsigned char ) 0xc0 )
status = ppa_out ( dev , cmd - > SCp . ptr , fast ) ;
else
status = ppa_in ( dev , cmd - > SCp . ptr , fast ) ;
cmd - > SCp . ptr + = fast ;
cmd - > SCp . this_residual - = fast ;
if ( ! status ) {
ppa_fail ( dev , DID_BUS_BUSY ) ;
return - 1 ; /* ERROR_RETURN */
}
if ( cmd - > SCp . buffer & & ! cmd - > SCp . this_residual ) {
/* if scatter/gather, advance to the next segment */
if ( cmd - > SCp . buffers_residual - - ) {
cmd - > SCp . buffer + + ;
cmd - > SCp . this_residual =
cmd - > SCp . buffer - > length ;
2007-10-22 23:19:53 +04:00
cmd - > SCp . ptr = sg_virt ( cmd - > SCp . buffer ) ;
2005-04-17 02:20:36 +04:00
}
}
/* Now check to see if the drive is ready to comunicate */
r = ( r_str ( ppb ) & 0xf0 ) ;
/* If not, drop back down to the scheduler and wait a timer tick */
if ( ! ( r & 0x80 ) )
return 0 ;
}
return 1 ; /* FINISH_RETURN */
}
/*
* Since the PPA itself doesn ' t generate interrupts , we use
* the scheduler ' s task queue to generate a stream of call - backs and
* complete the request when the drive is ready .
*/
2006-11-22 17:57:56 +03:00
static void ppa_interrupt ( struct work_struct * work )
2005-04-17 02:20:36 +04:00
{
2006-11-22 17:57:56 +03:00
ppa_struct * dev = container_of ( work , ppa_struct , ppa_tq . work ) ;
2005-04-17 02:20:36 +04:00
struct scsi_cmnd * cmd = dev - > cur_cmd ;
if ( ! cmd ) {
2007-07-09 23:00:10 +04:00
printk ( KERN_ERR " PPA: bug in ppa_interrupt \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
if ( ppa_engine ( dev , cmd ) ) {
schedule_delayed_work ( & dev - > ppa_tq , 1 ) ;
return ;
}
/* Command must of completed hence it is safe to let go... */
# if PPA_DEBUG > 0
switch ( ( cmd - > result > > 16 ) & 0xff ) {
case DID_OK :
break ;
case DID_NO_CONNECT :
2007-07-09 23:00:10 +04:00
printk ( KERN_DEBUG " ppa: no device at SCSI ID %i \n " , cmd - > device - > target ) ;
2005-04-17 02:20:36 +04:00
break ;
case DID_BUS_BUSY :
2007-07-09 23:00:10 +04:00
printk ( KERN_DEBUG " ppa: BUS BUSY - EPP timeout detected \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
case DID_TIME_OUT :
2007-07-09 23:00:10 +04:00
printk ( KERN_DEBUG " ppa: unknown timeout \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
case DID_ABORT :
2007-07-09 23:00:10 +04:00
printk ( KERN_DEBUG " ppa: told to abort \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
case DID_PARITY :
2007-07-09 23:00:10 +04:00
printk ( KERN_DEBUG " ppa: parity error (???) \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
case DID_ERROR :
2007-07-09 23:00:10 +04:00
printk ( KERN_DEBUG " ppa: internal driver error \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
case DID_RESET :
2007-07-09 23:00:10 +04:00
printk ( KERN_DEBUG " ppa: told to reset device \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
case DID_BAD_INTR :
2007-07-09 23:00:10 +04:00
printk ( KERN_WARNING " ppa: bad interrupt (???) \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
2007-07-09 23:00:10 +04:00
printk ( KERN_WARNING " ppa: bad return code (%02x) \n " ,
2005-04-17 02:20:36 +04:00
( cmd - > result > > 16 ) & 0xff ) ;
}
# endif
if ( cmd - > SCp . phase > 1 )
ppa_disconnect ( dev ) ;
ppa_pb_dismiss ( dev ) ;
dev - > cur_cmd = NULL ;
cmd - > scsi_done ( cmd ) ;
}
static int ppa_engine ( ppa_struct * dev , struct scsi_cmnd * cmd )
{
unsigned short ppb = dev - > base ;
unsigned char l = 0 , h = 0 ;
int retv ;
/* First check for any errors that may of occurred
* Here we check for internal errors
*/
if ( dev - > failed )
return 0 ;
switch ( cmd - > SCp . phase ) {
case 0 : /* Phase 0 - Waiting for parport */
if ( time_after ( jiffies , dev - > jstart + HZ ) ) {
/*
* We waited more than a second
* for parport to call us
*/
ppa_fail ( dev , DID_BUS_BUSY ) ;
return 0 ;
}
return 1 ; /* wait until ppa_wakeup claims parport */
case 1 : /* Phase 1 - Connected */
{ /* Perform a sanity check for cable unplugged */
int retv = 2 ; /* Failed */
ppa_connect ( dev , CONNECT_EPP_MAYBE ) ;
w_ctr ( ppb , 0xe ) ;
if ( ( r_str ( ppb ) & 0x08 ) = = 0x08 )
retv - - ;
w_ctr ( ppb , 0xc ) ;
if ( ( r_str ( ppb ) & 0x08 ) = = 0x00 )
retv - - ;
if ( retv ) {
2006-03-28 13:56:47 +04:00
if ( time_after ( jiffies , dev - > jstart + ( 1 * HZ ) ) ) {
2007-07-09 23:00:10 +04:00
printk ( KERN_ERR " ppa: Parallel port cable is unplugged. \n " ) ;
2005-04-17 02:20:36 +04:00
ppa_fail ( dev , DID_BUS_BUSY ) ;
return 0 ;
} else {
ppa_disconnect ( dev ) ;
return 1 ; /* Try again in a jiffy */
}
}
cmd - > SCp . phase + + ;
}
case 2 : /* Phase 2 - We are now talking to the scsi bus */
2005-10-25 02:05:09 +04:00
if ( ! ppa_select ( dev , scmd_id ( cmd ) ) ) {
2005-04-17 02:20:36 +04:00
ppa_fail ( dev , DID_NO_CONNECT ) ;
return 0 ;
}
cmd - > SCp . phase + + ;
case 3 : /* Phase 3 - Ready to accept a command */
w_ctr ( ppb , 0x0c ) ;
if ( ! ( r_str ( ppb ) & 0x80 ) )
return 1 ;
if ( ! ppa_send_command ( cmd ) )
return 0 ;
cmd - > SCp . phase + + ;
case 4 : /* Phase 4 - Setup scatter/gather buffers */
2007-09-09 22:16:58 +04:00
if ( scsi_bufflen ( cmd ) ) {
cmd - > SCp . buffer = scsi_sglist ( cmd ) ;
2005-04-17 02:20:36 +04:00
cmd - > SCp . this_residual = cmd - > SCp . buffer - > length ;
2007-10-22 23:19:53 +04:00
cmd - > SCp . ptr = sg_virt ( cmd - > SCp . buffer ) ;
2005-04-17 02:20:36 +04:00
} else {
cmd - > SCp . buffer = NULL ;
2007-09-09 22:16:58 +04:00
cmd - > SCp . this_residual = 0 ;
cmd - > SCp . ptr = NULL ;
2005-04-17 02:20:36 +04:00
}
2007-09-09 22:16:58 +04:00
cmd - > SCp . buffers_residual = scsi_sg_count ( cmd ) - 1 ;
2005-04-17 02:20:36 +04:00
cmd - > SCp . phase + + ;
case 5 : /* Phase 5 - Data transfer stage */
w_ctr ( ppb , 0x0c ) ;
if ( ! ( r_str ( ppb ) & 0x80 ) )
return 1 ;
retv = ppa_completion ( cmd ) ;
if ( retv = = - 1 )
return 0 ;
if ( retv = = 0 )
return 1 ;
cmd - > SCp . phase + + ;
case 6 : /* Phase 6 - Read status/message */
cmd - > result = DID_OK < < 16 ;
/* Check for data overrun */
if ( ppa_wait ( dev ) ! = ( unsigned char ) 0xf0 ) {
ppa_fail ( dev , DID_ERROR ) ;
return 0 ;
}
if ( ppa_in ( dev , & l , 1 ) ) { /* read status byte */
/* Check for optional message byte */
if ( ppa_wait ( dev ) = = ( unsigned char ) 0xf0 )
ppa_in ( dev , & h , 1 ) ;
cmd - > result =
( DID_OK < < 16 ) + ( h < < 8 ) + ( l & STATUS_MASK ) ;
}
return 0 ; /* Finished */
break ;
default :
2007-07-09 23:00:10 +04:00
printk ( KERN_ERR " ppa: Invalid scsi phase \n " ) ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
static int ppa_queuecommand ( struct scsi_cmnd * cmd ,
void ( * done ) ( struct scsi_cmnd * ) )
{
ppa_struct * dev = ppa_dev ( cmd - > device - > host ) ;
if ( dev - > cur_cmd ) {
2007-07-09 23:00:10 +04:00
printk ( KERN_ERR " PPA: bug in ppa_queuecommand \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
dev - > failed = 0 ;
dev - > jstart = jiffies ;
dev - > cur_cmd = cmd ;
cmd - > scsi_done = done ;
cmd - > result = DID_ERROR < < 16 ; /* default return code */
cmd - > SCp . phase = 0 ; /* bus free */
2006-11-22 17:57:56 +03:00
schedule_delayed_work ( & dev - > ppa_tq , 0 ) ;
2005-04-17 02:20:36 +04:00
ppa_pb_claim ( dev ) ;
return 0 ;
}
/*
* Apparently the disk - > capacity attribute is off by 1 sector
* for all disk drives . We add the one here , but it should really
* be done in sd . c . Even if it gets fixed there , this will still
* work .
*/
static int ppa_biosparam ( struct scsi_device * sdev , struct block_device * dev ,
sector_t capacity , int ip [ ] )
{
ip [ 0 ] = 0x40 ;
ip [ 1 ] = 0x20 ;
ip [ 2 ] = ( ( unsigned long ) capacity + 1 ) / ( ip [ 0 ] * ip [ 1 ] ) ;
if ( ip [ 2 ] > 1024 ) {
ip [ 0 ] = 0xff ;
ip [ 1 ] = 0x3f ;
ip [ 2 ] = ( ( unsigned long ) capacity + 1 ) / ( ip [ 0 ] * ip [ 1 ] ) ;
if ( ip [ 2 ] > 1023 )
ip [ 2 ] = 1023 ;
}
return 0 ;
}
static int ppa_abort ( struct scsi_cmnd * cmd )
{
ppa_struct * dev = ppa_dev ( cmd - > device - > host ) ;
/*
* There is no method for aborting commands since Iomega
* have tied the SCSI_MESSAGE line high in the interface
*/
switch ( cmd - > SCp . phase ) {
case 0 : /* Do not have access to parport */
case 1 : /* Have not connected to interface */
dev - > cur_cmd = NULL ; /* Forget the problem */
return SUCCESS ;
break ;
default : /* SCSI command sent, can not abort */
return FAILED ;
break ;
}
}
static void ppa_reset_pulse ( unsigned int base )
{
w_dtr ( base , 0x40 ) ;
w_ctr ( base , 0x8 ) ;
udelay ( 30 ) ;
w_ctr ( base , 0xc ) ;
}
static int ppa_reset ( struct scsi_cmnd * cmd )
{
ppa_struct * dev = ppa_dev ( cmd - > device - > host ) ;
if ( cmd - > SCp . phase )
ppa_disconnect ( dev ) ;
dev - > cur_cmd = NULL ; /* Forget the problem */
ppa_connect ( dev , CONNECT_NORMAL ) ;
ppa_reset_pulse ( dev - > base ) ;
2005-05-28 15:56:31 +04:00
mdelay ( 1 ) ; /* device settle delay */
2005-04-17 02:20:36 +04:00
ppa_disconnect ( dev ) ;
2005-05-28 15:56:31 +04:00
mdelay ( 1 ) ; /* device settle delay */
2005-04-17 02:20:36 +04:00
return SUCCESS ;
}
static int device_check ( ppa_struct * dev )
{
/* This routine looks for a device and then attempts to use EPP
to send a command . If all goes as planned then EPP is available . */
2007-07-09 23:00:10 +04:00
static u8 cmd [ 6 ] = { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
2005-04-17 02:20:36 +04:00
int loop , old_mode , status , k , ppb = dev - > base ;
unsigned char l ;
old_mode = dev - > mode ;
for ( loop = 0 ; loop < 8 ; loop + + ) {
/* Attempt to use EPP for Test Unit Ready */
if ( ( ppb & 0x0007 ) = = 0x0000 )
dev - > mode = PPA_EPP_32 ;
2007-07-09 23:00:10 +04:00
second_pass :
2005-04-17 02:20:36 +04:00
ppa_connect ( dev , CONNECT_EPP_MAYBE ) ;
/* Select SCSI device */
if ( ! ppa_select ( dev , loop ) ) {
ppa_disconnect ( dev ) ;
continue ;
}
2007-07-09 23:00:10 +04:00
printk ( KERN_INFO " ppa: Found device at ID %i, Attempting to use %s \n " ,
2005-04-17 02:20:36 +04:00
loop , PPA_MODE_STRING [ dev - > mode ] ) ;
/* Send SCSI command */
status = 1 ;
w_ctr ( ppb , 0x0c ) ;
for ( l = 0 ; ( l < 6 ) & & ( status ) ; l + + )
status = ppa_out ( dev , cmd , 1 ) ;
if ( ! status ) {
ppa_disconnect ( dev ) ;
ppa_connect ( dev , CONNECT_EPP_MAYBE ) ;
w_dtr ( ppb , 0x40 ) ;
w_ctr ( ppb , 0x08 ) ;
udelay ( 30 ) ;
w_ctr ( ppb , 0x0c ) ;
udelay ( 1000 ) ;
ppa_disconnect ( dev ) ;
udelay ( 1000 ) ;
if ( dev - > mode = = PPA_EPP_32 ) {
dev - > mode = old_mode ;
goto second_pass ;
}
return - EIO ;
}
w_ctr ( ppb , 0x0c ) ;
k = 1000000 ; /* 1 Second */
do {
l = r_str ( ppb ) ;
k - - ;
udelay ( 1 ) ;
} while ( ! ( l & 0x80 ) & & ( k ) ) ;
l & = 0xf0 ;
if ( l ! = 0xf0 ) {
ppa_disconnect ( dev ) ;
ppa_connect ( dev , CONNECT_EPP_MAYBE ) ;
ppa_reset_pulse ( ppb ) ;
udelay ( 1000 ) ;
ppa_disconnect ( dev ) ;
udelay ( 1000 ) ;
if ( dev - > mode = = PPA_EPP_32 ) {
dev - > mode = old_mode ;
goto second_pass ;
}
return - EIO ;
}
ppa_disconnect ( dev ) ;
2007-07-09 23:00:10 +04:00
printk ( KERN_INFO " ppa: Communication established with ID %i using %s \n " ,
2005-04-17 02:20:36 +04:00
loop , PPA_MODE_STRING [ dev - > mode ] ) ;
ppa_connect ( dev , CONNECT_EPP_MAYBE ) ;
ppa_reset_pulse ( ppb ) ;
udelay ( 1000 ) ;
ppa_disconnect ( dev ) ;
udelay ( 1000 ) ;
return 0 ;
}
return - ENODEV ;
}
2006-05-19 21:11:02 +04:00
static int ppa_adjust_queue ( struct scsi_device * device )
{
blk_queue_bounce_limit ( device - > request_queue , BLK_BOUNCE_HIGH ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
static struct scsi_host_template ppa_template = {
. module = THIS_MODULE ,
. proc_name = " ppa " ,
. proc_info = ppa_proc_info ,
. name = " Iomega VPI0 (ppa) interface " ,
. queuecommand = ppa_queuecommand ,
. eh_abort_handler = ppa_abort ,
. eh_bus_reset_handler = ppa_reset ,
. eh_host_reset_handler = ppa_reset ,
. bios_param = ppa_biosparam ,
. this_id = - 1 ,
. sg_tablesize = SG_ALL ,
. cmd_per_lun = 1 ,
. use_clustering = ENABLE_CLUSTERING ,
. can_queue = 1 ,
2006-05-19 21:11:02 +04:00
. slave_alloc = ppa_adjust_queue ,
2005-04-17 02:20:36 +04:00
} ;
/***************************************************************************
* Parallel port probing routines *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static LIST_HEAD ( ppa_hosts ) ;
static int __ppa_attach ( struct parport * pb )
{
struct Scsi_Host * host ;
2006-10-30 09:46:36 +03:00
DECLARE_WAIT_QUEUE_HEAD_ONSTACK ( waiting ) ;
2005-04-17 02:20:36 +04:00
DEFINE_WAIT ( wait ) ;
ppa_struct * dev ;
int ports ;
int modes , ppb , ppb_hi ;
int err = - ENOMEM ;
some kmalloc/memset ->kzalloc (tree wide)
Transform some calls to kmalloc/memset to a single kzalloc (or kcalloc).
Here is a short excerpt of the semantic patch performing
this transformation:
@@
type T2;
expression x;
identifier f,fld;
expression E;
expression E1,E2;
expression e1,e2,e3,y;
statement S;
@@
x =
- kmalloc
+ kzalloc
(E1,E2)
... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\)
- memset((T2)x,0,E1);
@@
expression E1,E2,E3;
@@
- kzalloc(E1 * E2,E3)
+ kcalloc(E1,E2,E3)
[akpm@linux-foundation.org: get kcalloc args the right way around]
Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Cc: Bryan Wu <bryan.wu@analog.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Acked-by: Roland Dreier <rolandd@cisco.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Acked-by: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: "David S. Miller" <davem@davemloft.net>
Acked-by: Greg KH <greg@kroah.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 12:49:03 +04:00
dev = kzalloc ( sizeof ( ppa_struct ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev )
return - ENOMEM ;
dev - > base = - 1 ;
dev - > mode = PPA_AUTODETECT ;
dev - > recon_tmo = PPA_RECON_TMO ;
init_waitqueue_head ( & waiting ) ;
dev - > dev = parport_register_device ( pb , " ppa " , NULL , ppa_wakeup ,
NULL , 0 , dev ) ;
if ( ! dev - > dev )
goto out ;
/* Claim the bus so it remembers what we do to the control
* registers . [ CTR and ECP ]
*/
err = - EBUSY ;
dev - > waiting = & waiting ;
prepare_to_wait ( & waiting , & wait , TASK_UNINTERRUPTIBLE ) ;
if ( ppa_pb_claim ( dev ) )
schedule_timeout ( 3 * HZ ) ;
if ( dev - > wanted ) {
printk ( KERN_ERR " ppa%d: failed to claim parport because "
" a pardevice is owning the port for too long "
" time! \n " , pb - > number ) ;
ppa_pb_dismiss ( dev ) ;
dev - > waiting = NULL ;
finish_wait ( & waiting , & wait ) ;
goto out1 ;
}
dev - > waiting = NULL ;
finish_wait ( & waiting , & wait ) ;
ppb = dev - > base = dev - > dev - > port - > base ;
ppb_hi = dev - > dev - > port - > base_hi ;
w_ctr ( ppb , 0x0c ) ;
modes = dev - > dev - > port - > modes ;
/* Mode detection works up the chain of speed
* This avoids a nasty if - then - else - if - . . . tree
*/
dev - > mode = PPA_NIBBLE ;
if ( modes & PARPORT_MODE_TRISTATE )
dev - > mode = PPA_PS2 ;
if ( modes & PARPORT_MODE_ECP ) {
w_ecr ( ppb_hi , 0x20 ) ;
dev - > mode = PPA_PS2 ;
}
if ( ( modes & PARPORT_MODE_EPP ) & & ( modes & PARPORT_MODE_ECP ) )
w_ecr ( ppb_hi , 0x80 ) ;
/* Done configuration */
err = ppa_init ( dev ) ;
ppa_pb_release ( dev ) ;
if ( err )
goto out1 ;
/* now the glue ... */
if ( dev - > mode = = PPA_NIBBLE | | dev - > mode = = PPA_PS2 )
ports = 3 ;
else
ports = 8 ;
2006-11-22 17:57:56 +03:00
INIT_DELAYED_WORK ( & dev - > ppa_tq , ppa_interrupt ) ;
2005-04-17 02:20:36 +04:00
err = - ENOMEM ;
host = scsi_host_alloc ( & ppa_template , sizeof ( ppa_struct * ) ) ;
if ( ! host )
goto out1 ;
host - > io_port = pb - > base ;
host - > n_io_port = ports ;
host - > dma_channel = - 1 ;
host - > unique_id = pb - > number ;
* ( ppa_struct * * ) & host - > hostdata = dev ;
dev - > host = host ;
list_add_tail ( & dev - > list , & ppa_hosts ) ;
err = scsi_add_host ( host , NULL ) ;
if ( err )
goto out2 ;
scsi_scan_host ( host ) ;
return 0 ;
out2 :
list_del_init ( & dev - > list ) ;
scsi_host_put ( host ) ;
out1 :
parport_unregister_device ( dev - > dev ) ;
out :
kfree ( dev ) ;
return err ;
}
static void ppa_attach ( struct parport * pb )
{
__ppa_attach ( pb ) ;
}
static void ppa_detach ( struct parport * pb )
{
ppa_struct * dev ;
list_for_each_entry ( dev , & ppa_hosts , list ) {
if ( dev - > dev - > port = = pb ) {
list_del_init ( & dev - > list ) ;
scsi_remove_host ( dev - > host ) ;
scsi_host_put ( dev - > host ) ;
parport_unregister_device ( dev - > dev ) ;
kfree ( dev ) ;
break ;
}
}
}
static struct parport_driver ppa_driver = {
. name = " ppa " ,
. attach = ppa_attach ,
. detach = ppa_detach ,
} ;
static int __init ppa_driver_init ( void )
{
2007-07-09 23:00:10 +04:00
printk ( KERN_INFO " ppa: Version %s \n " , PPA_VERSION ) ;
2005-04-17 02:20:36 +04:00
return parport_register_driver ( & ppa_driver ) ;
}
static void __exit ppa_driver_exit ( void )
{
parport_unregister_driver ( & ppa_driver ) ;
}
module_init ( ppa_driver_init ) ;
module_exit ( ppa_driver_exit ) ;
MODULE_LICENSE ( " GPL " ) ;