2005-04-17 02:20:36 +04:00
/*
* Generic Macintosh NCR5380 driver
*
* Copyright 1998 , Michael Schmitz < mschmitz @ lbl . gov >
*
* derived in part from :
*/
/*
* Generic Generic NCR5380 driver
*
* Copyright 1995 , Russell King
*/
# include <linux/types.h>
# include <linux/module.h>
# include <linux/ioport.h>
# include <linux/init.h>
# include <linux/blkdev.h>
# include <linux/interrupt.h>
2014-11-12 08:12:07 +03:00
# include <linux/platform_device.h>
2005-04-17 02:20:36 +04:00
2014-11-12 08:12:07 +03:00
# include <asm/hwtest.h>
2005-04-17 02:20:36 +04:00
# include <asm/io.h>
# include <asm/macints.h>
2014-11-12 08:12:07 +03:00
# include <asm/setup.h>
2005-04-17 02:20:36 +04:00
# include <scsi/scsi_host.h>
2014-11-12 08:12:04 +03:00
/* Definitions for the core NCR5380 driver. */
2007-10-16 12:25:01 +04:00
# define PSEUDO_DMA
2014-11-12 08:12:07 +03:00
# define NCR5380_implementation_fields unsigned char *pdma_base
2014-11-12 08:12:04 +03:00
2016-01-03 08:05:06 +03:00
# define NCR5380_read(reg) macscsi_read(instance, reg)
# define NCR5380_write(reg, value) macscsi_write(instance, reg, value)
2014-11-12 08:12:04 +03:00
# define NCR5380_pread macscsi_pread
# define NCR5380_pwrite macscsi_pwrite
2016-01-03 08:05:25 +03:00
# define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
2014-11-12 08:12:04 +03:00
# define NCR5380_intr macscsi_intr
# define NCR5380_queue_command macscsi_queue_command
# define NCR5380_abort macscsi_abort
# define NCR5380_bus_reset macscsi_bus_reset
# define NCR5380_info macscsi_info
# define NCR5380_show_info macscsi_show_info
# define NCR5380_write_info macscsi_write_info
2005-04-17 02:20:36 +04:00
# include "NCR5380.h"
static int setup_can_queue = - 1 ;
2014-11-12 08:12:05 +03:00
module_param ( setup_can_queue , int , 0 ) ;
2005-04-17 02:20:36 +04:00
static int setup_cmd_per_lun = - 1 ;
2014-11-12 08:12:05 +03:00
module_param ( setup_cmd_per_lun , int , 0 ) ;
2005-04-17 02:20:36 +04:00
static int setup_sg_tablesize = - 1 ;
2014-11-12 08:12:05 +03:00
module_param ( setup_sg_tablesize , int , 0 ) ;
2005-04-17 02:20:36 +04:00
static int setup_use_pdma = - 1 ;
2014-11-12 08:12:05 +03:00
module_param ( setup_use_pdma , int , 0 ) ;
2005-04-17 02:20:36 +04:00
static int setup_use_tagged_queuing = - 1 ;
2014-11-12 08:12:05 +03:00
module_param ( setup_use_tagged_queuing , int , 0 ) ;
2005-04-17 02:20:36 +04:00
static int setup_hostid = - 1 ;
2014-11-12 08:12:05 +03:00
module_param ( setup_hostid , int , 0 ) ;
2016-01-03 08:05:11 +03:00
static int setup_toshiba_delay = - 1 ;
module_param ( setup_toshiba_delay , int , 0 ) ;
2005-04-17 02:20:36 +04:00
/*
* NCR 5380 register access functions
*/
2014-11-12 08:12:07 +03:00
static inline char macscsi_read ( struct Scsi_Host * instance , int reg )
2005-04-17 02:20:36 +04:00
{
2014-11-12 08:12:07 +03:00
return in_8 ( instance - > base + ( reg < < 4 ) ) ;
2005-04-17 02:20:36 +04:00
}
2014-11-12 08:12:07 +03:00
static inline void macscsi_write ( struct Scsi_Host * instance , int reg , int value )
2005-04-17 02:20:36 +04:00
{
2014-11-12 08:12:07 +03:00
out_8 ( instance - > base + ( reg < < 4 ) , value ) ;
2005-04-17 02:20:36 +04:00
}
2014-11-12 08:12:05 +03:00
# ifndef MODULE
static int __init mac_scsi_setup ( char * str )
{
2016-01-03 08:05:11 +03:00
int ints [ 8 ] ;
2014-11-12 08:12:05 +03:00
( void ) get_options ( str , ARRAY_SIZE ( ints ) , ints ) ;
2016-01-03 08:05:11 +03:00
if ( ints [ 0 ] < 1 ) {
pr_err ( " Usage: mac5380=<can_queue>[,<cmd_per_lun>[,<sg_tablesize>[,<hostid>[,<use_tags>[,<use_pdma>[,<toshiba_delay>]]]]]] \n " ) ;
2014-11-12 08:12:05 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2014-11-12 08:12:05 +03:00
if ( ints [ 0 ] > = 1 )
setup_can_queue = ints [ 1 ] ;
if ( ints [ 0 ] > = 2 )
setup_cmd_per_lun = ints [ 2 ] ;
if ( ints [ 0 ] > = 3 )
setup_sg_tablesize = ints [ 3 ] ;
if ( ints [ 0 ] > = 4 )
setup_hostid = ints [ 4 ] ;
if ( ints [ 0 ] > = 5 )
setup_use_tagged_queuing = ints [ 5 ] ;
if ( ints [ 0 ] > = 6 )
2005-04-17 02:20:36 +04:00
setup_use_pdma = ints [ 6 ] ;
2016-01-03 08:05:11 +03:00
if ( ints [ 0 ] > = 7 )
setup_toshiba_delay = ints [ 7 ] ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
__setup ( " mac5380= " , mac_scsi_setup ) ;
2014-11-12 08:12:05 +03:00
# endif /* !MODULE */
2005-04-17 02:20:36 +04:00
2014-11-12 08:12:06 +03:00
# ifdef PSEUDO_DMA
2005-04-17 02:20:36 +04:00
/*
Pseudo - DMA : ( Ove Edlund )
The code attempts to catch bus errors that occur if one for example
" trips over the cable " .
XXX : Since bus errors in the PDMA routines never happen on my
computer , the bus error code is untested .
If the code works as intended , a bus error results in Pseudo - DMA
2014-10-03 05:42:17 +04:00
being disabled , meaning that the driver switches to slow handshake .
2005-04-17 02:20:36 +04:00
If bus errors are NOT extremely rare , this has to be changed .
*/
# define CP_IO_TO_MEM(s,d,len) \
__asm__ __volatile__ \
( " cmp.w #4,%2 \n " \
" bls 8f \n " \
" move.w %1,%%d0 \n " \
" neg.b %%d0 \n " \
" and.w #3,%%d0 \n " \
" sub.w %%d0,%2 \n " \
" bra 2f \n " \
" 1: move.b (%0),(%1)+ \n " \
" 2: dbf %%d0,1b \n " \
" move.w %2,%%d0 \n " \
" lsr.w #5,%%d0 \n " \
" bra 4f \n " \
" 3: move.l (%0),(%1)+ \n " \
" 31: move.l (%0),(%1)+ \n " \
" 32: move.l (%0),(%1)+ \n " \
" 33: move.l (%0),(%1)+ \n " \
" 34: move.l (%0),(%1)+ \n " \
" 35: move.l (%0),(%1)+ \n " \
" 36: move.l (%0),(%1)+ \n " \
" 37: move.l (%0),(%1)+ \n " \
" 4: dbf %%d0,3b \n " \
" move.w %2,%%d0 \n " \
" lsr.w #2,%%d0 \n " \
" and.w #7,%%d0 \n " \
" bra 6f \n " \
" 5: move.l (%0),(%1)+ \n " \
" 6: dbf %%d0,5b \n " \
" and.w #3,%2 \n " \
" bra 8f \n " \
" 7: move.b (%0),(%1)+ \n " \
" 8: dbf %2,7b \n " \
" moveq.l #0, %2 \n " \
" 9: \n " \
" .section .fixup, \" ax \" \n " \
" .even \n " \
" 90: moveq.l #1, %2 \n " \
" jra 9b \n " \
" .previous \n " \
" .section __ex_table, \" a \" \n " \
" .align 4 \n " \
" .long 1b,90b \n " \
" .long 3b,90b \n " \
" .long 31b,90b \n " \
" .long 32b,90b \n " \
" .long 33b,90b \n " \
" .long 34b,90b \n " \
" .long 35b,90b \n " \
" .long 36b,90b \n " \
" .long 37b,90b \n " \
" .long 5b,90b \n " \
" .long 7b,90b \n " \
" .previous " \
: " =a " ( s ) , " =a " ( d ) , " =d " ( len ) \
: " 0 " ( s ) , " 1 " ( d ) , " 2 " ( len ) \
: " d0 " )
2014-11-12 08:12:06 +03:00
static int macscsi_pread ( struct Scsi_Host * instance ,
unsigned char * dst , int len )
2005-04-17 02:20:36 +04:00
{
2014-11-12 08:12:07 +03:00
struct NCR5380_hostdata * hostdata = shost_priv ( instance ) ;
2014-11-12 08:12:06 +03:00
unsigned char * d ;
unsigned char * s ;
2014-11-12 08:12:07 +03:00
s = hostdata - > pdma_base + ( INPUT_DATA_REG < < 4 ) ;
2014-11-12 08:12:06 +03:00
d = dst ;
/* These conditions are derived from MacOS */
while ( ! ( NCR5380_read ( BUS_AND_STATUS_REG ) & BASR_DRQ ) & &
! ( NCR5380_read ( STATUS_REG ) & SR_REQ ) )
;
if ( ! ( NCR5380_read ( BUS_AND_STATUS_REG ) & BASR_DRQ ) & &
( NCR5380_read ( BUS_AND_STATUS_REG ) & BASR_PHASE_MATCH ) ) {
pr_err ( " Error in macscsi_pread \n " ) ;
return - 1 ;
}
CP_IO_TO_MEM ( s , d , len ) ;
if ( len ! = 0 ) {
pr_notice ( " Bus error in macscsi_pread \n " ) ;
return - 1 ;
}
return 0 ;
2005-04-17 02:20:36 +04:00
}
# define CP_MEM_TO_IO(s,d,len) \
__asm__ __volatile__ \
( " cmp.w #4,%2 \n " \
" bls 8f \n " \
" move.w %0,%%d0 \n " \
" neg.b %%d0 \n " \
" and.w #3,%%d0 \n " \
" sub.w %%d0,%2 \n " \
" bra 2f \n " \
" 1: move.b (%0)+,(%1) \n " \
" 2: dbf %%d0,1b \n " \
" move.w %2,%%d0 \n " \
" lsr.w #5,%%d0 \n " \
" bra 4f \n " \
" 3: move.l (%0)+,(%1) \n " \
" 31: move.l (%0)+,(%1) \n " \
" 32: move.l (%0)+,(%1) \n " \
" 33: move.l (%0)+,(%1) \n " \
" 34: move.l (%0)+,(%1) \n " \
" 35: move.l (%0)+,(%1) \n " \
" 36: move.l (%0)+,(%1) \n " \
" 37: move.l (%0)+,(%1) \n " \
" 4: dbf %%d0,3b \n " \
" move.w %2,%%d0 \n " \
" lsr.w #2,%%d0 \n " \
" and.w #7,%%d0 \n " \
" bra 6f \n " \
" 5: move.l (%0)+,(%1) \n " \
" 6: dbf %%d0,5b \n " \
" and.w #3,%2 \n " \
" bra 8f \n " \
" 7: move.b (%0)+,(%1) \n " \
" 8: dbf %2,7b \n " \
" moveq.l #0, %2 \n " \
" 9: \n " \
" .section .fixup, \" ax \" \n " \
" .even \n " \
" 90: moveq.l #1, %2 \n " \
" jra 9b \n " \
" .previous \n " \
" .section __ex_table, \" a \" \n " \
" .align 4 \n " \
" .long 1b,90b \n " \
" .long 3b,90b \n " \
" .long 31b,90b \n " \
" .long 32b,90b \n " \
" .long 33b,90b \n " \
" .long 34b,90b \n " \
" .long 35b,90b \n " \
" .long 36b,90b \n " \
" .long 37b,90b \n " \
" .long 5b,90b \n " \
" .long 7b,90b \n " \
" .previous " \
: " =a " ( s ) , " =a " ( d ) , " =d " ( len ) \
: " 0 " ( s ) , " 1 " ( d ) , " 2 " ( len ) \
: " d0 " )
2014-11-12 08:12:06 +03:00
static int macscsi_pwrite ( struct Scsi_Host * instance ,
unsigned char * src , int len )
2005-04-17 02:20:36 +04:00
{
2014-11-12 08:12:07 +03:00
struct NCR5380_hostdata * hostdata = shost_priv ( instance ) ;
2014-11-12 08:12:06 +03:00
unsigned char * s ;
unsigned char * d ;
2005-04-17 02:20:36 +04:00
2014-11-12 08:12:06 +03:00
s = src ;
2014-11-12 08:12:07 +03:00
d = hostdata - > pdma_base + ( OUTPUT_DATA_REG < < 4 ) ;
2014-11-12 08:12:06 +03:00
/* These conditions are derived from MacOS */
while ( ! ( NCR5380_read ( BUS_AND_STATUS_REG ) & BASR_DRQ ) & &
( ! ( NCR5380_read ( STATUS_REG ) & SR_REQ ) | |
( NCR5380_read ( BUS_AND_STATUS_REG ) & BASR_PHASE_MATCH ) ) )
;
if ( ! ( NCR5380_read ( BUS_AND_STATUS_REG ) & BASR_DRQ ) ) {
pr_err ( " Error in macscsi_pwrite \n " ) ;
return - 1 ;
}
CP_MEM_TO_IO ( s , d , len ) ;
if ( len ! = 0 ) {
pr_notice ( " Bus error in macscsi_pwrite \n " ) ;
return - 1 ;
}
return 0 ;
}
# endif
2005-04-17 02:20:36 +04:00
# include "NCR5380.c"
2014-11-12 08:12:07 +03:00
# define DRV_MODULE_NAME "mac_scsi"
# define PFX DRV_MODULE_NAME ": "
static struct scsi_host_template mac_scsi_template = {
. module = THIS_MODULE ,
. proc_name = DRV_MODULE_NAME ,
2013-03-31 09:15:54 +04:00
. show_info = macscsi_show_info ,
. write_info = macscsi_write_info ,
2005-04-17 02:20:36 +04:00
. name = " Macintosh NCR5380 SCSI " ,
. info = macscsi_info ,
. queuecommand = macscsi_queue_command ,
. eh_abort_handler = macscsi_abort ,
. eh_bus_reset_handler = macscsi_bus_reset ,
2014-11-12 08:12:00 +03:00
. can_queue = 16 ,
2005-04-17 02:20:36 +04:00
. this_id = 7 ,
. sg_tablesize = SG_ALL ,
2014-11-12 08:12:00 +03:00
. cmd_per_lun = 2 ,
2005-04-17 02:20:36 +04:00
. use_clustering = DISABLE_CLUSTERING
} ;
2014-11-12 08:12:07 +03:00
static int __init mac_scsi_probe ( struct platform_device * pdev )
{
struct Scsi_Host * instance ;
int error ;
int host_flags = 0 ;
struct resource * irq , * pio_mem , * pdma_mem = NULL ;
pio_mem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! pio_mem )
return - ENODEV ;
# ifdef PSEUDO_DMA
pdma_mem = platform_get_resource ( pdev , IORESOURCE_MEM , 1 ) ;
# endif
irq = platform_get_resource ( pdev , IORESOURCE_IRQ , 0 ) ;
if ( ! hwreg_present ( ( unsigned char * ) pio_mem - > start +
( STATUS_REG < < 4 ) ) ) {
pr_info ( PFX " no device detected at %pap \n " , & pio_mem - > start ) ;
return - ENODEV ;
}
if ( setup_can_queue > 0 )
mac_scsi_template . can_queue = setup_can_queue ;
if ( setup_cmd_per_lun > 0 )
mac_scsi_template . cmd_per_lun = setup_cmd_per_lun ;
if ( setup_sg_tablesize > = 0 )
mac_scsi_template . sg_tablesize = setup_sg_tablesize ;
if ( setup_hostid > = 0 )
mac_scsi_template . this_id = setup_hostid & 7 ;
if ( setup_use_pdma < 0 )
setup_use_pdma = 0 ;
instance = scsi_host_alloc ( & mac_scsi_template ,
sizeof ( struct NCR5380_hostdata ) ) ;
if ( ! instance )
return - ENOMEM ;
instance - > base = pio_mem - > start ;
if ( irq )
instance - > irq = irq - > start ;
else
instance - > irq = NO_IRQ ;
if ( pdma_mem & & setup_use_pdma ) {
struct NCR5380_hostdata * hostdata = shost_priv ( instance ) ;
hostdata - > pdma_base = ( unsigned char * ) pdma_mem - > start ;
} else
host_flags | = FLAG_NO_PSEUDO_DMA ;
2014-11-12 08:12:19 +03:00
# ifdef SUPPORT_TAGS
host_flags | = setup_use_tagged_queuing > 0 ? FLAG_TAGGED_QUEUING : 0 ;
# endif
2016-01-03 08:05:11 +03:00
host_flags | = setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0 ;
2014-11-12 08:12:19 +03:00
2016-01-03 08:05:21 +03:00
error = NCR5380_init ( instance , host_flags ) ;
if ( error )
goto fail_init ;
2014-11-12 08:12:07 +03:00
if ( instance - > irq ! = NO_IRQ ) {
error = request_irq ( instance - > irq , macscsi_intr , IRQF_SHARED ,
" NCR5380 " , instance ) ;
if ( error )
goto fail_irq ;
}
2016-01-03 08:05:11 +03:00
NCR5380_maybe_reset_bus ( instance ) ;
2014-11-12 08:12:07 +03:00
error = scsi_add_host ( instance , NULL ) ;
if ( error )
goto fail_host ;
platform_set_drvdata ( pdev , instance ) ;
scsi_scan_host ( instance ) ;
return 0 ;
fail_host :
if ( instance - > irq ! = NO_IRQ )
free_irq ( instance - > irq , instance ) ;
fail_irq :
NCR5380_exit ( instance ) ;
2016-01-03 08:05:21 +03:00
fail_init :
2014-11-12 08:12:07 +03:00
scsi_host_put ( instance ) ;
return error ;
}
static int __exit mac_scsi_remove ( struct platform_device * pdev )
{
struct Scsi_Host * instance = platform_get_drvdata ( pdev ) ;
scsi_remove_host ( instance ) ;
if ( instance - > irq ! = NO_IRQ )
free_irq ( instance - > irq , instance ) ;
NCR5380_exit ( instance ) ;
scsi_host_put ( instance ) ;
return 0 ;
}
static struct platform_driver mac_scsi_driver = {
. remove = __exit_p ( mac_scsi_remove ) ,
. driver = {
. name = DRV_MODULE_NAME ,
} ,
} ;
2005-04-17 02:20:36 +04:00
2014-11-12 08:12:07 +03:00
module_platform_driver_probe ( mac_scsi_driver , mac_scsi_probe ) ;
2014-11-12 08:12:05 +03:00
2014-11-12 08:12:07 +03:00
MODULE_ALIAS ( " platform: " DRV_MODULE_NAME ) ;
2014-11-12 08:12:05 +03:00
MODULE_LICENSE ( " GPL " ) ;