2005-04-17 02:20:36 +04:00
# ifndef CCISS_H
# define CCISS_H
# include <linux/genhd.h>
2009-09-17 22:46:58 +04:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
# include "cciss_cmd.h"
# define NWD_SHIFT 4
# define MAX_PART (1 << NWD_SHIFT)
# define IO_OK 0
# define IO_ERROR 1
2009-06-09 01:05:56 +04:00
# define IO_NEEDS_RETRY 3
2005-04-17 02:20:36 +04:00
2009-06-02 16:48:39 +04:00
# define VENDOR_LEN 8
# define MODEL_LEN 16
# define REV_LEN 4
2005-04-17 02:20:36 +04:00
struct ctlr_info ;
typedef struct ctlr_info ctlr_info_t ;
struct access_method {
void ( * submit_command ) ( ctlr_info_t * h , CommandList_struct * c ) ;
void ( * set_intr_mask ) ( ctlr_info_t * h , unsigned long val ) ;
unsigned long ( * fifo_full ) ( ctlr_info_t * h ) ;
2010-06-02 23:58:04 +04:00
bool ( * intr_pending ) ( ctlr_info_t * h ) ;
2005-04-17 02:20:36 +04:00
unsigned long ( * command_completed ) ( ctlr_info_t * h ) ;
} ;
typedef struct _drive_info_struct
{
2009-09-17 22:48:00 +04:00
unsigned char LunID [ 8 ] ;
2005-04-17 02:20:36 +04:00
int usage_count ;
2005-07-28 12:07:31 +04:00
struct request_queue * queue ;
2005-04-17 02:20:36 +04:00
sector_t nr_blocks ;
int block_size ;
int heads ;
int sectors ;
int cylinders ;
2005-09-13 12:25:22 +04:00
int raid_level ; /* set to -1 to indicate that
* the drive is not in use / configured
2009-06-02 16:48:39 +04:00
*/
int busy_configuring ; /* This is set when a drive is being removed
* to prevent it from being opened or it ' s
* queue from being started .
*/
2009-09-17 22:48:31 +04:00
struct device dev ;
2009-06-02 16:48:39 +04:00
__u8 serial_no [ 16 ] ; /* from inquiry page 0x83,
* not necc . null terminated .
*/
char vendor [ VENDOR_LEN + 1 ] ; /* SCSI vendor string */
char model [ MODEL_LEN + 1 ] ; /* SCSI model string */
char rev [ REV_LEN + 1 ] ; /* SCSI revision string */
2009-09-17 22:48:31 +04:00
char device_initialized ; /* indicates whether dev is initialized */
2005-04-17 02:20:36 +04:00
} drive_info_struct ;
2009-11-12 21:50:01 +03:00
struct ctlr_info
2005-04-17 02:20:36 +04:00
{
int ctlr ;
char devname [ 8 ] ;
char * product_name ;
2010-02-18 02:53:31 +03:00
char firm_ver [ 4 ] ; /* Firmware version */
2005-04-17 02:20:36 +04:00
struct pci_dev * pdev ;
__u32 board_id ;
void __iomem * vaddr ;
unsigned long paddr ;
2006-12-07 07:35:01 +03:00
int nr_cmds ; /* Number of commands allowed on this controller */
2005-04-17 02:20:36 +04:00
CfgTable_struct __iomem * cfgtable ;
int interrupts_enabled ;
int major ;
int max_commands ;
int commands_outstanding ;
int max_outstanding ; /* Debug */
int num_luns ;
int highest_lun ;
int usage_count ; /* number of opens all all minor devices */
2009-11-12 21:50:01 +03:00
/* Need space for temp sg list
* number of scatter / gathers supported
* number of scatter / gathers in chained block
*/
struct scatterlist * * scatter_list ;
int maxsgentries ;
int chainsize ;
int max_cmd_sgentries ;
2010-02-27 01:01:27 +03:00
SGDescriptor_struct * * cmd_sg_list ;
2009-11-12 21:50:01 +03:00
2010-06-02 23:58:06 +04:00
# define PERF_MODE_INT 0
# define DOORBELL_INT 1
2006-01-08 12:03:50 +03:00
# define SIMPLE_MODE_INT 2
# define MEMQ_MODE_INT 3
unsigned int intr [ 4 ] ;
unsigned int msix_vector ;
unsigned int msi_vector ;
2011-08-08 13:40:15 +04:00
int intr_mode ;
2006-12-07 07:35:06 +03:00
int cciss_max_sectors ;
2006-10-01 10:27:23 +04:00
BYTE cciss_read ;
BYTE cciss_write ;
BYTE cciss_read_capacity ;
2005-04-17 02:20:36 +04:00
2010-02-18 02:53:31 +03:00
/* information about each logical volume */
2009-09-17 22:48:31 +04:00
drive_info_struct * drv [ CISS_MAX_LUN ] ;
2005-04-17 02:20:36 +04:00
struct access_method access ;
/* queue and queue Info */
2011-01-10 23:50:33 +03:00
struct list_head reqQ ;
struct list_head cmpQ ;
2005-04-17 02:20:36 +04:00
unsigned int Qdepth ;
unsigned int maxQsinceinit ;
unsigned int maxSG ;
spinlock_t lock ;
2010-02-18 02:53:31 +03:00
/* pointers to command and error info pool */
2005-04-17 02:20:36 +04:00
CommandList_struct * cmd_pool ;
dma_addr_t cmd_pool_dhandle ;
ErrorInfo_struct * errinfo_pool ;
dma_addr_t errinfo_pool_dhandle ;
unsigned long * cmd_pool_bits ;
int nr_allocs ;
int nr_frees ;
int busy_configuring ;
2005-09-13 12:25:21 +04:00
int busy_initializing ;
2009-09-17 22:46:58 +04:00
int busy_scanning ;
struct mutex busy_shutting_down ;
2005-04-17 02:20:36 +04:00
/* This element holds the zero based queue number of the last
* queue to be started . It is used for fairness .
*/
int next_to_run ;
2010-02-18 02:53:31 +03:00
/* Disk structures we need to pass back */
2006-12-07 07:35:12 +03:00
struct gendisk * gendisk [ CISS_MAX_LUN ] ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_CISS_SCSI_TAPE
2010-02-27 01:01:42 +03:00
struct cciss_scsi_adapter_data_t * scsi_ctlr ;
2005-04-17 02:20:36 +04:00
# endif
2005-09-13 12:25:22 +04:00
unsigned char alive ;
2009-09-17 22:46:58 +04:00
struct list_head scan_list ;
struct completion scan_wait ;
2009-06-02 16:48:39 +04:00
struct device dev ;
2010-06-02 23:58:06 +04:00
/*
* Performant mode tables .
*/
u32 trans_support ;
u32 trans_offset ;
struct TransTable_struct * transtable ;
unsigned long transMethod ;
/*
* Performant mode completion buffer
*/
u64 * reply_pool ;
dma_addr_t reply_pool_dhandle ;
u64 * reply_pool_head ;
size_t reply_pool_size ;
unsigned char reply_pool_wraparound ;
u32 * blockFetchTable ;
2005-04-17 02:20:36 +04:00
} ;
2010-06-02 23:58:06 +04:00
/* Defining the diffent access_methods
*
2005-04-17 02:20:36 +04:00
* Memory mapped FIFO interface ( SMART 53 xx cards )
*/
# define SA5_DOORBELL 0x20
# define SA5_REQUEST_PORT_OFFSET 0x40
# define SA5_REPLY_INTR_MASK_OFFSET 0x34
# define SA5_REPLY_PORT_OFFSET 0x44
# define SA5_INTR_STATUS 0x30
# define SA5_SCRATCHPAD_OFFSET 0xB0
# define SA5_CTCFG_OFFSET 0xB4
# define SA5_CTMEM_OFFSET 0xB8
# define SA5_INTR_OFF 0x08
# define SA5B_INTR_OFF 0x04
# define SA5_INTR_PENDING 0x08
# define SA5B_INTR_PENDING 0x04
# define FIFO_EMPTY 0xffffffff
# define CCISS_FIRMWARE_READY 0xffff0000 /* value in scratchpad register */
2010-06-02 23:58:06 +04:00
/* Perf. mode flags */
# define SA5_PERF_INTR_PENDING 0x04
# define SA5_PERF_INTR_OFF 0x05
# define SA5_OUTDB_STATUS_PERF_BIT 0x01
# define SA5_OUTDB_CLEAR_PERF_BIT 0x01
# define SA5_OUTDB_CLEAR 0xA0
# define SA5_OUTDB_CLEAR_PERF_BIT 0x01
# define SA5_OUTDB_STATUS 0x9C
2005-04-17 02:20:36 +04:00
# define CISS_ERROR_BIT 0x02
# define CCISS_INTR_ON 1
# define CCISS_INTR_OFF 0
2010-07-19 22:45:15 +04:00
/* CCISS_BOARD_READY_WAIT_SECS is how long to wait for a board
* to become ready , in seconds , before giving up on it .
* CCISS_BOARD_READY_POLL_INTERVAL_MSECS * is how long to wait
* between polling the board to see if it is ready , in
* milliseconds . CCISS_BOARD_READY_ITERATIONS is derived
* the above .
*/
# define CCISS_BOARD_READY_WAIT_SECS (120)
2011-05-03 23:53:31 +04:00
# define CCISS_BOARD_NOT_READY_WAIT_SECS (100)
2010-07-19 22:45:15 +04:00
# define CCISS_BOARD_READY_POLL_INTERVAL_MSECS (100)
# define CCISS_BOARD_READY_ITERATIONS \
( ( CCISS_BOARD_READY_WAIT_SECS * 1000 ) / \
CCISS_BOARD_READY_POLL_INTERVAL_MSECS )
2010-10-22 23:21:07 +04:00
# define CCISS_BOARD_NOT_READY_ITERATIONS \
( ( CCISS_BOARD_NOT_READY_WAIT_SECS * 1000 ) / \
CCISS_BOARD_READY_POLL_INTERVAL_MSECS )
2010-07-19 22:46:17 +04:00
# define CCISS_POST_RESET_PAUSE_MSECS (3000)
2011-05-03 23:53:41 +04:00
# define CCISS_POST_RESET_NOOP_INTERVAL_MSECS (4000)
2010-07-19 22:46:17 +04:00
# define CCISS_POST_RESET_NOOP_RETRIES (12)
2011-05-03 23:53:41 +04:00
# define CCISS_POST_RESET_NOOP_TIMEOUT_MSECS (10000)
2010-07-19 22:45:15 +04:00
2005-04-17 02:20:36 +04:00
/*
Send the command to the hardware
*/
static void SA5_submit_command ( ctlr_info_t * h , CommandList_struct * c )
{
# ifdef CCISS_DEBUG
2010-06-02 23:58:06 +04:00
printk ( KERN_WARNING " cciss%d: Sending %08x - down to controller \n " ,
h - > ctlr , c - > busaddr ) ;
# endif /* CCISS_DEBUG */
2005-04-17 02:20:36 +04:00
writel ( c - > busaddr , h - > vaddr + SA5_REQUEST_PORT_OFFSET ) ;
2011-07-09 11:04:12 +04:00
readl ( h - > vaddr + SA5_SCRATCHPAD_OFFSET ) ;
2005-04-17 02:20:36 +04:00
h - > commands_outstanding + + ;
if ( h - > commands_outstanding > h - > max_outstanding )
h - > max_outstanding = h - > commands_outstanding ;
}
/*
* This card is the opposite of the other cards .
* 0 turns interrupts on . . .
* 0x08 turns them off . . .
*/
static void SA5_intr_mask ( ctlr_info_t * h , unsigned long val )
{
if ( val )
{ /* Turn interrupts on */
h - > interrupts_enabled = 1 ;
writel ( 0 , h - > vaddr + SA5_REPLY_INTR_MASK_OFFSET ) ;
2011-05-03 23:52:54 +04:00
( void ) readl ( h - > vaddr + SA5_REPLY_INTR_MASK_OFFSET ) ;
2005-04-17 02:20:36 +04:00
} else /* Turn them off */
{
h - > interrupts_enabled = 0 ;
writel ( SA5_INTR_OFF ,
h - > vaddr + SA5_REPLY_INTR_MASK_OFFSET ) ;
2011-05-03 23:52:54 +04:00
( void ) readl ( h - > vaddr + SA5_REPLY_INTR_MASK_OFFSET ) ;
2005-04-17 02:20:36 +04:00
}
}
/*
* This card is the opposite of the other cards .
* 0 turns interrupts on . . .
* 0x04 turns them off . . .
*/
static void SA5B_intr_mask ( ctlr_info_t * h , unsigned long val )
{
if ( val )
{ /* Turn interrupts on */
h - > interrupts_enabled = 1 ;
writel ( 0 , h - > vaddr + SA5_REPLY_INTR_MASK_OFFSET ) ;
2011-05-03 23:52:54 +04:00
( void ) readl ( h - > vaddr + SA5_REPLY_INTR_MASK_OFFSET ) ;
2005-04-17 02:20:36 +04:00
} else /* Turn them off */
{
h - > interrupts_enabled = 0 ;
writel ( SA5B_INTR_OFF ,
h - > vaddr + SA5_REPLY_INTR_MASK_OFFSET ) ;
2011-05-03 23:52:54 +04:00
( void ) readl ( h - > vaddr + SA5_REPLY_INTR_MASK_OFFSET ) ;
2005-04-17 02:20:36 +04:00
}
}
2010-06-02 23:58:06 +04:00
/* Performant mode intr_mask */
static void SA5_performant_intr_mask ( ctlr_info_t * h , unsigned long val )
{
if ( val ) { /* turn on interrupts */
h - > interrupts_enabled = 1 ;
writel ( 0 , h - > vaddr + SA5_REPLY_INTR_MASK_OFFSET ) ;
2011-05-03 23:52:54 +04:00
( void ) readl ( h - > vaddr + SA5_REPLY_INTR_MASK_OFFSET ) ;
2010-06-02 23:58:06 +04:00
} else {
h - > interrupts_enabled = 0 ;
writel ( SA5_PERF_INTR_OFF ,
h - > vaddr + SA5_REPLY_INTR_MASK_OFFSET ) ;
2011-05-03 23:52:54 +04:00
( void ) readl ( h - > vaddr + SA5_REPLY_INTR_MASK_OFFSET ) ;
2010-06-02 23:58:06 +04:00
}
}
2005-04-17 02:20:36 +04:00
/*
* Returns true if fifo is full .
*
*/
static unsigned long SA5_fifo_full ( ctlr_info_t * h )
{
if ( h - > commands_outstanding > = h - > max_commands )
return ( 1 ) ;
else
return ( 0 ) ;
}
/*
* returns value read from hardware .
* returns FIFO_EMPTY if there is nothing to read
*/
static unsigned long SA5_completed ( ctlr_info_t * h )
{
unsigned long register_value
= readl ( h - > vaddr + SA5_REPLY_PORT_OFFSET ) ;
if ( register_value ! = FIFO_EMPTY )
{
h - > commands_outstanding - - ;
# ifdef CCISS_DEBUG
printk ( " cciss: Read %lx back from board \n " , register_value ) ;
# endif /* CCISS_DEBUG */
}
# ifdef CCISS_DEBUG
else
{
printk ( " cciss: FIFO Empty read \n " ) ;
}
# endif
return ( register_value ) ;
}
2010-06-02 23:58:06 +04:00
/* Performant mode command completed */
static unsigned long SA5_performant_completed ( ctlr_info_t * h )
{
unsigned long register_value = FIFO_EMPTY ;
/* flush the controller write of the reply queue by reading
* outbound doorbell status register .
*/
register_value = readl ( h - > vaddr + SA5_OUTDB_STATUS ) ;
/* msi auto clears the interrupt pending bit. */
if ( ! ( h - > msi_vector | | h - > msix_vector ) ) {
writel ( SA5_OUTDB_CLEAR_PERF_BIT , h - > vaddr + SA5_OUTDB_CLEAR ) ;
/* Do a read in order to flush the write to the controller
* ( as per spec . )
*/
register_value = readl ( h - > vaddr + SA5_OUTDB_STATUS ) ;
}
if ( ( * ( h - > reply_pool_head ) & 1 ) = = ( h - > reply_pool_wraparound ) ) {
register_value = * ( h - > reply_pool_head ) ;
( h - > reply_pool_head ) + + ;
h - > commands_outstanding - - ;
} else {
register_value = FIFO_EMPTY ;
}
/* Check for wraparound */
if ( h - > reply_pool_head = = ( h - > reply_pool + h - > max_commands ) ) {
h - > reply_pool_head = h - > reply_pool ;
h - > reply_pool_wraparound ^ = 1 ;
}
return register_value ;
}
2005-04-17 02:20:36 +04:00
/*
* Returns true if an interrupt is pending . .
*/
2010-06-02 23:58:04 +04:00
static bool SA5_intr_pending ( ctlr_info_t * h )
2005-04-17 02:20:36 +04:00
{
unsigned long register_value =
readl ( h - > vaddr + SA5_INTR_STATUS ) ;
# ifdef CCISS_DEBUG
printk ( " cciss: intr_pending %lx \n " , register_value ) ;
# endif /* CCISS_DEBUG */
if ( register_value & SA5_INTR_PENDING )
return 1 ;
return 0 ;
}
/*
* Returns true if an interrupt is pending . .
*/
2010-06-02 23:58:04 +04:00
static bool SA5B_intr_pending ( ctlr_info_t * h )
2005-04-17 02:20:36 +04:00
{
unsigned long register_value =
readl ( h - > vaddr + SA5_INTR_STATUS ) ;
# ifdef CCISS_DEBUG
printk ( " cciss: intr_pending %lx \n " , register_value ) ;
# endif /* CCISS_DEBUG */
if ( register_value & SA5B_INTR_PENDING )
return 1 ;
return 0 ;
}
2010-06-02 23:58:06 +04:00
static bool SA5_performant_intr_pending ( ctlr_info_t * h )
{
unsigned long register_value = readl ( h - > vaddr + SA5_INTR_STATUS ) ;
if ( ! register_value )
return false ;
if ( h - > msi_vector | | h - > msix_vector )
return true ;
/* Read outbound doorbell to flush */
register_value = readl ( h - > vaddr + SA5_OUTDB_STATUS ) ;
return register_value & SA5_OUTDB_STATUS_PERF_BIT ;
}
2005-04-17 02:20:36 +04:00
static struct access_method SA5_access = {
SA5_submit_command ,
SA5_intr_mask ,
SA5_fifo_full ,
SA5_intr_pending ,
SA5_completed ,
} ;
static struct access_method SA5B_access = {
SA5_submit_command ,
SA5B_intr_mask ,
SA5_fifo_full ,
SA5B_intr_pending ,
SA5_completed ,
} ;
2010-06-02 23:58:06 +04:00
static struct access_method SA5_performant_access = {
SA5_submit_command ,
SA5_performant_intr_mask ,
SA5_fifo_full ,
SA5_performant_intr_pending ,
SA5_performant_completed ,
} ;
2005-04-17 02:20:36 +04:00
struct board_type {
__u32 board_id ;
char * product_name ;
struct access_method * access ;
2006-12-07 07:35:01 +03:00
int nr_cmds ; /* Max cmds this kind of ctlr can handle. */
2005-04-17 02:20:36 +04:00
} ;
# endif /* CCISS_H */