2013-02-05 14:15:02 +01:00
/*
* Filename : core . c
*
*
* Authors : Joshua Morris < josh . h . morris @ us . ibm . com >
* Philip Kelleher < pjk1939 @ linux . vnet . ibm . com >
*
* ( C ) Copyright 2013 IBM Corporation
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; either version 2 of the
* License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/module.h>
# include <linux/pci.h>
# include <linux/reboot.h>
# include <linux/slab.h>
# include <linux/bitops.h>
2013-03-16 08:22:25 +01:00
# include <linux/delay.h>
2013-06-18 14:52:21 -05:00
# include <linux/debugfs.h>
# include <linux/seq_file.h>
2013-02-05 14:15:02 +01:00
# include <linux/genhd.h>
# include <linux/idr.h>
# include "rsxx_priv.h"
# include "rsxx_cfg.h"
# define NO_LEGACY 0
2013-06-18 14:42:36 -05:00
# define SYNC_START_TIMEOUT (10 * 60) /* 10 minutes */
2013-02-05 14:15:02 +01:00
2013-06-18 14:43:58 -05:00
MODULE_DESCRIPTION ( " IBM Flash Adapter 900GB Full Height Device Driver " ) ;
2013-02-27 09:24:59 -06:00
MODULE_AUTHOR ( " Joshua Morris/Philip Kelleher, IBM " ) ;
2013-02-05 14:15:02 +01:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_VERSION ( DRIVER_VERSION ) ;
static unsigned int force_legacy = NO_LEGACY ;
module_param ( force_legacy , uint , 0444 ) ;
MODULE_PARM_DESC ( force_legacy , " Force the use of legacy type PCI interrupts " ) ;
2013-06-18 14:42:36 -05:00
static unsigned int sync_start = 1 ;
module_param ( sync_start , uint , 0444 ) ;
MODULE_PARM_DESC ( sync_start , " On by Default: Driver load will not complete "
" until the card startup has completed. " ) ;
2013-02-05 14:15:02 +01:00
static DEFINE_IDA ( rsxx_disk_ida ) ;
2013-06-18 14:52:21 -05:00
/* --------------------Debugfs Setup ------------------- */
static int rsxx_attr_pci_regs_show ( struct seq_file * m , void * p )
{
struct rsxx_cardinfo * card = m - > private ;
seq_printf ( m , " HWID 0x%08x \n " ,
ioread32 ( card - > regmap + HWID ) ) ;
seq_printf ( m , " SCRATCH 0x%08x \n " ,
ioread32 ( card - > regmap + SCRATCH ) ) ;
seq_printf ( m , " IER 0x%08x \n " ,
ioread32 ( card - > regmap + IER ) ) ;
seq_printf ( m , " IPR 0x%08x \n " ,
ioread32 ( card - > regmap + IPR ) ) ;
seq_printf ( m , " CREG_CMD 0x%08x \n " ,
ioread32 ( card - > regmap + CREG_CMD ) ) ;
seq_printf ( m , " CREG_ADD 0x%08x \n " ,
ioread32 ( card - > regmap + CREG_ADD ) ) ;
seq_printf ( m , " CREG_CNT 0x%08x \n " ,
ioread32 ( card - > regmap + CREG_CNT ) ) ;
seq_printf ( m , " CREG_STAT 0x%08x \n " ,
ioread32 ( card - > regmap + CREG_STAT ) ) ;
seq_printf ( m , " CREG_DATA0 0x%08x \n " ,
ioread32 ( card - > regmap + CREG_DATA0 ) ) ;
seq_printf ( m , " CREG_DATA1 0x%08x \n " ,
ioread32 ( card - > regmap + CREG_DATA1 ) ) ;
seq_printf ( m , " CREG_DATA2 0x%08x \n " ,
ioread32 ( card - > regmap + CREG_DATA2 ) ) ;
seq_printf ( m , " CREG_DATA3 0x%08x \n " ,
ioread32 ( card - > regmap + CREG_DATA3 ) ) ;
seq_printf ( m , " CREG_DATA4 0x%08x \n " ,
ioread32 ( card - > regmap + CREG_DATA4 ) ) ;
seq_printf ( m , " CREG_DATA5 0x%08x \n " ,
ioread32 ( card - > regmap + CREG_DATA5 ) ) ;
seq_printf ( m , " CREG_DATA6 0x%08x \n " ,
ioread32 ( card - > regmap + CREG_DATA6 ) ) ;
seq_printf ( m , " CREG_DATA7 0x%08x \n " ,
ioread32 ( card - > regmap + CREG_DATA7 ) ) ;
seq_printf ( m , " INTR_COAL 0x%08x \n " ,
ioread32 ( card - > regmap + INTR_COAL ) ) ;
seq_printf ( m , " HW_ERROR 0x%08x \n " ,
ioread32 ( card - > regmap + HW_ERROR ) ) ;
seq_printf ( m , " DEBUG0 0x%08x \n " ,
ioread32 ( card - > regmap + PCI_DEBUG0 ) ) ;
seq_printf ( m , " DEBUG1 0x%08x \n " ,
ioread32 ( card - > regmap + PCI_DEBUG1 ) ) ;
seq_printf ( m , " DEBUG2 0x%08x \n " ,
ioread32 ( card - > regmap + PCI_DEBUG2 ) ) ;
seq_printf ( m , " DEBUG3 0x%08x \n " ,
ioread32 ( card - > regmap + PCI_DEBUG3 ) ) ;
seq_printf ( m , " DEBUG4 0x%08x \n " ,
ioread32 ( card - > regmap + PCI_DEBUG4 ) ) ;
seq_printf ( m , " DEBUG5 0x%08x \n " ,
ioread32 ( card - > regmap + PCI_DEBUG5 ) ) ;
seq_printf ( m , " DEBUG6 0x%08x \n " ,
ioread32 ( card - > regmap + PCI_DEBUG6 ) ) ;
seq_printf ( m , " DEBUG7 0x%08x \n " ,
ioread32 ( card - > regmap + PCI_DEBUG7 ) ) ;
seq_printf ( m , " RECONFIG 0x%08x \n " ,
ioread32 ( card - > regmap + PCI_RECONFIG ) ) ;
return 0 ;
}
static int rsxx_attr_stats_show ( struct seq_file * m , void * p )
{
struct rsxx_cardinfo * card = m - > private ;
int i ;
for ( i = 0 ; i < card - > n_targets ; i + + ) {
seq_printf ( m , " Ctrl %d CRC Errors = %d \n " ,
i , card - > ctrl [ i ] . stats . crc_errors ) ;
seq_printf ( m , " Ctrl %d Hard Errors = %d \n " ,
i , card - > ctrl [ i ] . stats . hard_errors ) ;
seq_printf ( m , " Ctrl %d Soft Errors = %d \n " ,
i , card - > ctrl [ i ] . stats . soft_errors ) ;
seq_printf ( m , " Ctrl %d Writes Issued = %d \n " ,
i , card - > ctrl [ i ] . stats . writes_issued ) ;
seq_printf ( m , " Ctrl %d Writes Failed = %d \n " ,
i , card - > ctrl [ i ] . stats . writes_failed ) ;
seq_printf ( m , " Ctrl %d Reads Issued = %d \n " ,
i , card - > ctrl [ i ] . stats . reads_issued ) ;
seq_printf ( m , " Ctrl %d Reads Failed = %d \n " ,
i , card - > ctrl [ i ] . stats . reads_failed ) ;
seq_printf ( m , " Ctrl %d Reads Retried = %d \n " ,
i , card - > ctrl [ i ] . stats . reads_retried ) ;
seq_printf ( m , " Ctrl %d Discards Issued = %d \n " ,
i , card - > ctrl [ i ] . stats . discards_issued ) ;
seq_printf ( m , " Ctrl %d Discards Failed = %d \n " ,
i , card - > ctrl [ i ] . stats . discards_failed ) ;
seq_printf ( m , " Ctrl %d DMA SW Errors = %d \n " ,
i , card - > ctrl [ i ] . stats . dma_sw_err ) ;
seq_printf ( m , " Ctrl %d DMA HW Faults = %d \n " ,
i , card - > ctrl [ i ] . stats . dma_hw_fault ) ;
seq_printf ( m , " Ctrl %d DMAs Cancelled = %d \n " ,
i , card - > ctrl [ i ] . stats . dma_cancelled ) ;
seq_printf ( m , " Ctrl %d SW Queue Depth = %d \n " ,
i , card - > ctrl [ i ] . stats . sw_q_depth ) ;
seq_printf ( m , " Ctrl %d HW Queue Depth = %d \n " ,
i , atomic_read ( & card - > ctrl [ i ] . stats . hw_q_depth ) ) ;
}
return 0 ;
}
static int rsxx_attr_stats_open ( struct inode * inode , struct file * file )
{
return single_open ( file , rsxx_attr_stats_show , inode - > i_private ) ;
}
static int rsxx_attr_pci_regs_open ( struct inode * inode , struct file * file )
{
return single_open ( file , rsxx_attr_pci_regs_show , inode - > i_private ) ;
}
static ssize_t rsxx_cram_read ( struct file * fp , char __user * ubuf ,
size_t cnt , loff_t * ppos )
{
2014-08-19 14:42:04 -04:00
struct rsxx_cardinfo * card = file_inode ( fp ) - > i_private ;
2013-06-18 14:52:21 -05:00
char * buf ;
2014-08-19 14:42:04 -04:00
ssize_t st ;
2013-06-18 14:52:21 -05:00
2014-08-19 14:42:04 -04:00
buf = kzalloc ( cnt , GFP_KERNEL ) ;
2013-06-18 14:52:21 -05:00
if ( ! buf )
return - ENOMEM ;
2014-08-19 14:42:04 -04:00
st = rsxx_creg_read ( card , CREG_ADD_CRAM + ( u32 ) * ppos , cnt , buf , 1 ) ;
if ( ! st )
st = copy_to_user ( ubuf , buf , cnt ) ;
kfree ( buf ) ;
2013-06-18 14:52:21 -05:00
if ( st )
return st ;
2014-08-19 14:42:04 -04:00
* ppos + = cnt ;
2013-06-18 14:52:21 -05:00
return cnt ;
}
static ssize_t rsxx_cram_write ( struct file * fp , const char __user * ubuf ,
size_t cnt , loff_t * ppos )
{
2014-08-19 14:42:04 -04:00
struct rsxx_cardinfo * card = file_inode ( fp ) - > i_private ;
2013-06-18 14:52:21 -05:00
char * buf ;
2014-08-19 14:42:04 -04:00
ssize_t st ;
2013-06-18 14:52:21 -05:00
2016-01-02 14:58:07 -05:00
buf = memdup_user ( ubuf , cnt ) ;
if ( IS_ERR ( buf ) )
return PTR_ERR ( buf ) ;
2013-06-18 14:52:21 -05:00
2016-01-02 14:58:07 -05:00
st = rsxx_creg_write ( card , CREG_ADD_CRAM + ( u32 ) * ppos , cnt , buf , 1 ) ;
2014-08-19 14:42:04 -04:00
kfree ( buf ) ;
2013-06-18 14:52:21 -05:00
if ( st )
return st ;
2014-08-19 14:42:04 -04:00
* ppos + = cnt ;
2013-06-18 14:52:21 -05:00
return cnt ;
}
static const struct file_operations debugfs_cram_fops = {
. owner = THIS_MODULE ,
. read = rsxx_cram_read ,
. write = rsxx_cram_write ,
} ;
static const struct file_operations debugfs_stats_fops = {
. owner = THIS_MODULE ,
. open = rsxx_attr_stats_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
static const struct file_operations debugfs_pci_regs_fops = {
. owner = THIS_MODULE ,
. open = rsxx_attr_pci_regs_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
static void rsxx_debugfs_dev_new ( struct rsxx_cardinfo * card )
{
struct dentry * debugfs_stats ;
struct dentry * debugfs_pci_regs ;
struct dentry * debugfs_cram ;
card - > debugfs_dir = debugfs_create_dir ( card - > gendisk - > disk_name , NULL ) ;
if ( IS_ERR_OR_NULL ( card - > debugfs_dir ) )
goto failed_debugfs_dir ;
2018-05-24 13:38:59 -06:00
debugfs_stats = debugfs_create_file ( " stats " , 0444 ,
2013-06-18 14:52:21 -05:00
card - > debugfs_dir , card ,
& debugfs_stats_fops ) ;
if ( IS_ERR_OR_NULL ( debugfs_stats ) )
goto failed_debugfs_stats ;
2018-05-24 13:38:59 -06:00
debugfs_pci_regs = debugfs_create_file ( " pci_regs " , 0444 ,
2013-06-18 14:52:21 -05:00
card - > debugfs_dir , card ,
& debugfs_pci_regs_fops ) ;
if ( IS_ERR_OR_NULL ( debugfs_pci_regs ) )
goto failed_debugfs_pci_regs ;
2018-05-24 13:38:59 -06:00
debugfs_cram = debugfs_create_file ( " cram " , 0644 ,
2013-06-18 14:52:21 -05:00
card - > debugfs_dir , card ,
& debugfs_cram_fops ) ;
if ( IS_ERR_OR_NULL ( debugfs_cram ) )
goto failed_debugfs_cram ;
return ;
failed_debugfs_cram :
debugfs_remove ( debugfs_pci_regs ) ;
failed_debugfs_pci_regs :
debugfs_remove ( debugfs_stats ) ;
failed_debugfs_stats :
debugfs_remove ( card - > debugfs_dir ) ;
failed_debugfs_dir :
card - > debugfs_dir = NULL ;
}
2013-02-05 14:15:02 +01:00
/*----------------- Interrupt Control & Handling -------------------*/
2013-03-16 08:22:25 +01:00
static void rsxx_mask_interrupts ( struct rsxx_cardinfo * card )
{
card - > isr_mask = 0 ;
card - > ier_mask = 0 ;
}
2013-02-05 14:15:02 +01:00
static void __enable_intr ( unsigned int * mask , unsigned int intr )
{
* mask | = intr ;
}
static void __disable_intr ( unsigned int * mask , unsigned int intr )
{
* mask & = ~ intr ;
}
/*
* NOTE : Disabling the IER will disable the hardware interrupt .
* Disabling the ISR will disable the software handling of the ISR bit .
*
* Enable / Disable interrupt functions assume the card - > irq_lock
* is held by the caller .
*/
void rsxx_enable_ier ( struct rsxx_cardinfo * card , unsigned int intr )
{
2013-03-16 08:22:25 +01:00
if ( unlikely ( card - > halt ) | |
unlikely ( card - > eeh_state ) )
2013-02-05 14:15:02 +01:00
return ;
__enable_intr ( & card - > ier_mask , intr ) ;
iowrite32 ( card - > ier_mask , card - > regmap + IER ) ;
}
void rsxx_disable_ier ( struct rsxx_cardinfo * card , unsigned int intr )
{
2013-03-16 08:22:25 +01:00
if ( unlikely ( card - > eeh_state ) )
return ;
2013-02-05 14:15:02 +01:00
__disable_intr ( & card - > ier_mask , intr ) ;
iowrite32 ( card - > ier_mask , card - > regmap + IER ) ;
}
void rsxx_enable_ier_and_isr ( struct rsxx_cardinfo * card ,
unsigned int intr )
{
2013-03-16 08:22:25 +01:00
if ( unlikely ( card - > halt ) | |
unlikely ( card - > eeh_state ) )
2013-02-05 14:15:02 +01:00
return ;
__enable_intr ( & card - > isr_mask , intr ) ;
__enable_intr ( & card - > ier_mask , intr ) ;
iowrite32 ( card - > ier_mask , card - > regmap + IER ) ;
}
void rsxx_disable_ier_and_isr ( struct rsxx_cardinfo * card ,
unsigned int intr )
{
2013-03-16 08:22:25 +01:00
if ( unlikely ( card - > eeh_state ) )
return ;
2013-02-05 14:15:02 +01:00
__disable_intr ( & card - > isr_mask , intr ) ;
__disable_intr ( & card - > ier_mask , intr ) ;
iowrite32 ( card - > ier_mask , card - > regmap + IER ) ;
}
2013-02-18 21:35:59 +01:00
static irqreturn_t rsxx_isr ( int irq , void * pdata )
2013-02-05 14:15:02 +01:00
{
2013-02-18 21:35:59 +01:00
struct rsxx_cardinfo * card = pdata ;
2013-02-05 14:15:02 +01:00
unsigned int isr ;
int handled = 0 ;
int reread_isr ;
int i ;
spin_lock ( & card - > irq_lock ) ;
do {
reread_isr = 0 ;
2013-03-16 08:22:25 +01:00
if ( unlikely ( card - > eeh_state ) )
break ;
2013-02-05 14:15:02 +01:00
isr = ioread32 ( card - > regmap + ISR ) ;
if ( isr = = 0xffffffff ) {
/*
* A few systems seem to have an intermittent issue
* where PCI reads return all Fs , but retrying the read
* a little later will return as expected .
*/
dev_info ( CARD_TO_DEV ( card ) ,
" ISR = 0xFFFFFFFF, retrying later \n " ) ;
break ;
}
isr & = card - > isr_mask ;
if ( ! isr )
break ;
for ( i = 0 ; i < card - > n_targets ; i + + ) {
if ( isr & CR_INTR_DMA ( i ) ) {
if ( card - > ier_mask & CR_INTR_DMA ( i ) ) {
rsxx_disable_ier ( card , CR_INTR_DMA ( i ) ) ;
reread_isr = 1 ;
}
queue_work ( card - > ctrl [ i ] . done_wq ,
& card - > ctrl [ i ] . dma_done_work ) ;
handled + + ;
}
}
if ( isr & CR_INTR_CREG ) {
2013-06-18 14:34:54 -05:00
queue_work ( card - > creg_ctrl . creg_wq ,
& card - > creg_ctrl . done_work ) ;
2013-02-05 14:15:02 +01:00
handled + + ;
}
if ( isr & CR_INTR_EVENT ) {
2013-06-18 14:34:54 -05:00
queue_work ( card - > event_wq , & card - > event_work ) ;
2013-02-05 14:15:02 +01:00
rsxx_disable_ier_and_isr ( card , CR_INTR_EVENT ) ;
handled + + ;
}
} while ( reread_isr ) ;
spin_unlock ( & card - > irq_lock ) ;
return handled ? IRQ_HANDLED : IRQ_NONE ;
}
/*----------------- Card Event Handler -------------------*/
2013-02-25 12:27:46 -06:00
static const char * const rsxx_card_state_to_str ( unsigned int state )
2013-02-18 21:35:59 +01:00
{
2013-02-25 12:27:46 -06:00
static const char * const state_strings [ ] = {
2013-02-18 21:35:59 +01:00
" Unknown " , " Shutdown " , " Starting " , " Formatting " ,
" Uninitialized " , " Good " , " Shutting Down " ,
" Fault " , " Read Only Fault " , " dStroying "
} ;
return state_strings [ ffs ( state ) ] ;
}
2013-02-05 14:15:02 +01:00
static void card_state_change ( struct rsxx_cardinfo * card ,
unsigned int new_state )
{
int st ;
dev_info ( CARD_TO_DEV ( card ) ,
" card state change detected.(%s -> %s) \n " ,
rsxx_card_state_to_str ( card - > state ) ,
rsxx_card_state_to_str ( new_state ) ) ;
card - > state = new_state ;
/* Don't attach DMA interfaces if the card has an invalid config */
if ( ! card - > config_valid )
return ;
switch ( new_state ) {
case CARD_STATE_RD_ONLY_FAULT :
dev_crit ( CARD_TO_DEV ( card ) ,
" Hardware has entered read-only mode! \n " ) ;
/*
* Fall through so the DMA devices can be attached and
* the user can attempt to pull off their data .
*/
2019-01-23 00:33:09 -06:00
/* fall through */
2013-02-05 14:15:02 +01:00
case CARD_STATE_GOOD :
st = rsxx_get_card_size8 ( card , & card - > size8 ) ;
if ( st )
dev_err ( CARD_TO_DEV ( card ) ,
" Failed attaching DMA devices \n " ) ;
if ( card - > config_valid )
set_capacity ( card - > gendisk , card - > size8 > > 9 ) ;
break ;
case CARD_STATE_FAULT :
dev_crit ( CARD_TO_DEV ( card ) ,
" Hardware Fault reported! \n " ) ;
/* Fall through. */
/* Everything else, detach DMA interface if it's attached. */
case CARD_STATE_SHUTDOWN :
case CARD_STATE_STARTING :
case CARD_STATE_FORMATTING :
case CARD_STATE_UNINITIALIZED :
case CARD_STATE_SHUTTING_DOWN :
/*
* dStroy is a term coined by marketing to represent the low level
* secure erase .
*/
case CARD_STATE_DSTROYING :
set_capacity ( card - > gendisk , 0 ) ;
break ;
}
}
static void card_event_handler ( struct work_struct * work )
{
struct rsxx_cardinfo * card ;
unsigned int state ;
unsigned long flags ;
int st ;
card = container_of ( work , struct rsxx_cardinfo , event_work ) ;
if ( unlikely ( card - > halt ) )
return ;
/*
* Enable the interrupt now to avoid any weird race conditions where a
* state change might occur while rsxx_get_card_state ( ) is
* processing a returned creg cmd .
*/
spin_lock_irqsave ( & card - > irq_lock , flags ) ;
rsxx_enable_ier_and_isr ( card , CR_INTR_EVENT ) ;
spin_unlock_irqrestore ( & card - > irq_lock , flags ) ;
st = rsxx_get_card_state ( card , & state ) ;
if ( st ) {
dev_info ( CARD_TO_DEV ( card ) ,
" Failed reading state after event. \n " ) ;
return ;
}
if ( card - > state ! = state )
card_state_change ( card , state ) ;
if ( card - > creg_ctrl . creg_stats . stat & CREG_STAT_LOG_PENDING )
rsxx_read_hw_log ( card ) ;
}
/*----------------- Card Operations -------------------*/
static int card_shutdown ( struct rsxx_cardinfo * card )
{
unsigned int state ;
signed long start ;
const int timeout = msecs_to_jiffies ( 120000 ) ;
int st ;
/* We can't issue a shutdown if the card is in a transition state */
start = jiffies ;
do {
st = rsxx_get_card_state ( card , & state ) ;
if ( st )
return st ;
} while ( state = = CARD_STATE_STARTING & &
( jiffies - start < timeout ) ) ;
if ( state = = CARD_STATE_STARTING )
return - ETIMEDOUT ;
/* Only issue a shutdown if we need to */
if ( ( state ! = CARD_STATE_SHUTTING_DOWN ) & &
( state ! = CARD_STATE_SHUTDOWN ) ) {
st = rsxx_issue_card_cmd ( card , CARD_CMD_SHUTDOWN ) ;
if ( st )
return st ;
}
start = jiffies ;
do {
st = rsxx_get_card_state ( card , & state ) ;
if ( st )
return st ;
} while ( state ! = CARD_STATE_SHUTDOWN & &
( jiffies - start < timeout ) ) ;
if ( state ! = CARD_STATE_SHUTDOWN )
return - ETIMEDOUT ;
return 0 ;
}
2013-03-26 11:03:07 -05:00
static int rsxx_eeh_frozen ( struct pci_dev * dev )
2013-03-16 08:22:25 +01:00
{
struct rsxx_cardinfo * card = pci_get_drvdata ( dev ) ;
int i ;
2013-03-26 11:03:07 -05:00
int st ;
2013-03-16 08:22:25 +01:00
2013-06-18 14:43:58 -05:00
dev_warn ( & dev - > dev , " IBM Flash Adapter PCI: preparing for slot reset. \n " ) ;
2013-03-16 08:22:25 +01:00
card - > eeh_state = 1 ;
rsxx_mask_interrupts ( card ) ;
/*
* We need to guarantee that the write for eeh_state and masking
* interrupts does not become reordered . This will prevent a possible
* race condition with the EEH code .
*/
wmb ( ) ;
pci_disable_device ( dev ) ;
2013-03-26 11:03:07 -05:00
st = rsxx_eeh_save_issued_dmas ( card ) ;
if ( st )
return st ;
2013-03-16 08:22:25 +01:00
rsxx_eeh_save_issued_creg ( card ) ;
for ( i = 0 ; i < card - > n_targets ; i + + ) {
if ( card - > ctrl [ i ] . status . buf )
pci_free_consistent ( card - > dev , STATUS_BUFFER_SIZE8 ,
card - > ctrl [ i ] . status . buf ,
card - > ctrl [ i ] . status . dma_addr ) ;
if ( card - > ctrl [ i ] . cmd . buf )
pci_free_consistent ( card - > dev , COMMAND_BUFFER_SIZE8 ,
card - > ctrl [ i ] . cmd . buf ,
card - > ctrl [ i ] . cmd . dma_addr ) ;
}
2013-03-26 11:03:07 -05:00
return 0 ;
2013-03-16 08:22:25 +01:00
}
static void rsxx_eeh_failure ( struct pci_dev * dev )
{
struct rsxx_cardinfo * card = pci_get_drvdata ( dev ) ;
int i ;
2013-06-18 14:36:26 -05:00
int cnt = 0 ;
2013-03-16 08:22:25 +01:00
2013-06-18 14:43:58 -05:00
dev_err ( & dev - > dev , " IBM Flash Adapter PCI: disabling failed card. \n " ) ;
2013-03-16 08:22:25 +01:00
card - > eeh_state = 1 ;
2013-06-18 14:36:26 -05:00
card - > halt = 1 ;
2013-03-16 08:22:25 +01:00
2013-06-18 14:36:26 -05:00
for ( i = 0 ; i < card - > n_targets ; i + + ) {
spin_lock_bh ( & card - > ctrl [ i ] . queue_lock ) ;
cnt = rsxx_cleanup_dma_queue ( & card - > ctrl [ i ] ,
2013-09-04 13:59:02 -05:00
& card - > ctrl [ i ] . queue ,
COMPLETE_DMA ) ;
2013-06-18 14:36:26 -05:00
spin_unlock_bh ( & card - > ctrl [ i ] . queue_lock ) ;
cnt + = rsxx_dma_cancel ( & card - > ctrl [ i ] ) ;
2013-03-16 08:22:25 +01:00
2013-06-18 14:36:26 -05:00
if ( cnt )
dev_info ( CARD_TO_DEV ( card ) ,
" Freed %d queued DMAs on channel %d \n " ,
cnt , card - > ctrl [ i ] . id ) ;
}
2013-03-16 08:22:25 +01:00
}
static int rsxx_eeh_fifo_flush_poll ( struct rsxx_cardinfo * card )
{
unsigned int status ;
int iter = 0 ;
/* We need to wait for the hardware to reset */
while ( iter + + < 10 ) {
status = ioread32 ( card - > regmap + PCI_RECONFIG ) ;
if ( status & RSXX_FLUSH_BUSY ) {
ssleep ( 1 ) ;
continue ;
}
if ( status & RSXX_FLUSH_TIMEOUT )
dev_warn ( CARD_TO_DEV ( card ) , " HW: flash controller timeout \n " ) ;
return 0 ;
}
/* Hardware failed resetting itself. */
return - 1 ;
}
static pci_ers_result_t rsxx_error_detected ( struct pci_dev * dev ,
enum pci_channel_state error )
{
2013-03-26 11:03:07 -05:00
int st ;
2013-03-16 08:22:25 +01:00
if ( dev - > revision < RSXX_EEH_SUPPORT )
return PCI_ERS_RESULT_NONE ;
if ( error = = pci_channel_io_perm_failure ) {
rsxx_eeh_failure ( dev ) ;
return PCI_ERS_RESULT_DISCONNECT ;
}
2013-03-26 11:03:07 -05:00
st = rsxx_eeh_frozen ( dev ) ;
if ( st ) {
dev_err ( & dev - > dev , " Slot reset setup failed \n " ) ;
rsxx_eeh_failure ( dev ) ;
return PCI_ERS_RESULT_DISCONNECT ;
}
2013-03-16 08:22:25 +01:00
return PCI_ERS_RESULT_NEED_RESET ;
}
static pci_ers_result_t rsxx_slot_reset ( struct pci_dev * dev )
{
struct rsxx_cardinfo * card = pci_get_drvdata ( dev ) ;
unsigned long flags ;
int i ;
int st ;
dev_warn ( & dev - > dev ,
2013-06-18 14:43:58 -05:00
" IBM Flash Adapter PCI: recovering from slot reset. \n " ) ;
2013-03-16 08:22:25 +01:00
st = pci_enable_device ( dev ) ;
if ( st )
goto failed_hw_setup ;
pci_set_master ( dev ) ;
st = rsxx_eeh_fifo_flush_poll ( card ) ;
if ( st )
goto failed_hw_setup ;
rsxx_dma_queue_reset ( card ) ;
for ( i = 0 ; i < card - > n_targets ; i + + ) {
st = rsxx_hw_buffers_init ( dev , & card - > ctrl [ i ] ) ;
if ( st )
goto failed_hw_buffers_init ;
}
if ( card - > config_valid )
rsxx_dma_configure ( card ) ;
/* Clears the ISR register from spurious interrupts */
st = ioread32 ( card - > regmap + ISR ) ;
card - > eeh_state = 0 ;
spin_lock_irqsave ( & card - > irq_lock , flags ) ;
if ( card - > n_targets & RSXX_MAX_TARGETS )
rsxx_enable_ier_and_isr ( card , CR_INTR_ALL_G ) ;
else
rsxx_enable_ier_and_isr ( card , CR_INTR_ALL_C ) ;
spin_unlock_irqrestore ( & card - > irq_lock , flags ) ;
rsxx_kick_creg_queue ( card ) ;
for ( i = 0 ; i < card - > n_targets ; i + + ) {
spin_lock ( & card - > ctrl [ i ] . queue_lock ) ;
if ( list_empty ( & card - > ctrl [ i ] . queue ) ) {
spin_unlock ( & card - > ctrl [ i ] . queue_lock ) ;
continue ;
}
spin_unlock ( & card - > ctrl [ i ] . queue_lock ) ;
queue_work ( card - > ctrl [ i ] . issue_wq ,
& card - > ctrl [ i ] . issue_dma_work ) ;
}
2013-06-18 14:43:58 -05:00
dev_info ( & dev - > dev , " IBM Flash Adapter PCI: recovery complete. \n " ) ;
2013-03-16 08:22:25 +01:00
return PCI_ERS_RESULT_RECOVERED ;
failed_hw_buffers_init :
for ( i = 0 ; i < card - > n_targets ; i + + ) {
if ( card - > ctrl [ i ] . status . buf )
pci_free_consistent ( card - > dev ,
STATUS_BUFFER_SIZE8 ,
card - > ctrl [ i ] . status . buf ,
card - > ctrl [ i ] . status . dma_addr ) ;
if ( card - > ctrl [ i ] . cmd . buf )
pci_free_consistent ( card - > dev ,
COMMAND_BUFFER_SIZE8 ,
card - > ctrl [ i ] . cmd . buf ,
card - > ctrl [ i ] . cmd . dma_addr ) ;
}
failed_hw_setup :
rsxx_eeh_failure ( dev ) ;
return PCI_ERS_RESULT_DISCONNECT ;
}
2013-02-05 14:15:02 +01:00
/*----------------- Driver Initialization & Setup -------------------*/
/* Returns: 0 if the driver is compatible with the device
- 1 if the driver is NOT compatible with the device */
static int rsxx_compatibility_check ( struct rsxx_cardinfo * card )
{
unsigned char pci_rev ;
pci_read_config_byte ( card - > dev , PCI_REVISION_ID , & pci_rev ) ;
if ( pci_rev > RS70_PCI_REV_SUPPORTED )
return - 1 ;
return 0 ;
}
2013-02-06 14:03:13 +11:00
static int rsxx_pci_probe ( struct pci_dev * dev ,
2013-02-05 14:15:02 +01:00
const struct pci_device_id * id )
{
struct rsxx_cardinfo * card ;
int st ;
2013-06-18 14:42:36 -05:00
unsigned int sync_timeout ;
2013-02-05 14:15:02 +01:00
dev_info ( & dev - > dev , " PCI-Flash SSD discovered \n " ) ;
card = kzalloc ( sizeof ( * card ) , GFP_KERNEL ) ;
if ( ! card )
return - ENOMEM ;
card - > dev = dev ;
pci_set_drvdata ( dev , card ) ;
2018-06-11 15:46:46 -04:00
st = ida_alloc ( & rsxx_disk_ida , GFP_KERNEL ) ;
if ( st < 0 )
2013-02-05 14:15:02 +01:00
goto failed_ida_get ;
2018-06-11 15:46:46 -04:00
card - > disk_id = st ;
2013-02-05 14:15:02 +01:00
st = pci_enable_device ( dev ) ;
if ( st )
goto failed_enable ;
pci_set_master ( dev ) ;
2018-10-09 16:08:24 +02:00
dma_set_max_seg_size ( & dev - > dev , RSXX_HW_BLK_SIZE ) ;
2013-02-05 14:15:02 +01:00
2018-10-18 15:15:15 +02:00
st = dma_set_mask ( & dev - > dev , DMA_BIT_MASK ( 64 ) ) ;
2013-02-05 14:15:02 +01:00
if ( st ) {
dev_err ( CARD_TO_DEV ( card ) ,
" No usable DMA configuration,aborting \n " ) ;
goto failed_dma_mask ;
}
st = pci_request_regions ( dev , DRIVER_NAME ) ;
if ( st ) {
dev_err ( CARD_TO_DEV ( card ) ,
" Failed to request memory region \n " ) ;
goto failed_request_regions ;
}
if ( pci_resource_len ( dev , 0 ) = = 0 ) {
dev_err ( CARD_TO_DEV ( card ) , " BAR0 has length 0! \n " ) ;
st = - ENOMEM ;
goto failed_iomap ;
}
card - > regmap = pci_iomap ( dev , 0 , 0 ) ;
if ( ! card - > regmap ) {
dev_err ( CARD_TO_DEV ( card ) , " Failed to map BAR0 \n " ) ;
st = - ENOMEM ;
goto failed_iomap ;
}
spin_lock_init ( & card - > irq_lock ) ;
card - > halt = 0 ;
2013-03-16 08:22:25 +01:00
card - > eeh_state = 0 ;
2013-02-05 14:15:02 +01:00
2013-02-18 21:35:59 +01:00
spin_lock_irq ( & card - > irq_lock ) ;
2013-02-05 14:15:02 +01:00
rsxx_disable_ier_and_isr ( card , CR_INTR_ALL ) ;
2013-02-18 21:35:59 +01:00
spin_unlock_irq ( & card - > irq_lock ) ;
2013-02-05 14:15:02 +01:00
if ( ! force_legacy ) {
st = pci_enable_msi ( dev ) ;
if ( st )
dev_warn ( CARD_TO_DEV ( card ) ,
" Failed to enable MSI \n " ) ;
}
2014-10-01 14:07:39 -06:00
st = request_irq ( dev - > irq , rsxx_isr , IRQF_SHARED ,
2013-02-05 14:15:02 +01:00
DRIVER_NAME , card ) ;
if ( st ) {
dev_err ( CARD_TO_DEV ( card ) ,
" Failed requesting IRQ%d \n " , dev - > irq ) ;
goto failed_irq ;
}
/************* Setup Processor Command Interface *************/
2013-06-18 14:34:54 -05:00
st = rsxx_creg_setup ( card ) ;
if ( st ) {
dev_err ( CARD_TO_DEV ( card ) , " Failed to setup creg interface. \n " ) ;
goto failed_creg_setup ;
}
2013-02-05 14:15:02 +01:00
2013-02-18 21:35:59 +01:00
spin_lock_irq ( & card - > irq_lock ) ;
2013-02-05 14:15:02 +01:00
rsxx_enable_ier_and_isr ( card , CR_INTR_CREG ) ;
2013-02-18 21:35:59 +01:00
spin_unlock_irq ( & card - > irq_lock ) ;
2013-02-05 14:15:02 +01:00
st = rsxx_compatibility_check ( card ) ;
if ( st ) {
dev_warn ( CARD_TO_DEV ( card ) ,
" Incompatible driver detected. Please update the driver. \n " ) ;
st = - EINVAL ;
goto failed_compatiblity_check ;
}
/************* Load Card Config *************/
st = rsxx_load_config ( card ) ;
if ( st )
dev_err ( CARD_TO_DEV ( card ) ,
" Failed loading card config \n " ) ;
/************* Setup DMA Engine *************/
st = rsxx_get_num_targets ( card , & card - > n_targets ) ;
if ( st )
dev_info ( CARD_TO_DEV ( card ) ,
" Failed reading the number of DMA targets \n " ) ;
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 14:03:40 -07:00
card - > ctrl = kcalloc ( card - > n_targets , sizeof ( * card - > ctrl ) ,
GFP_KERNEL ) ;
2013-02-05 14:15:02 +01:00
if ( ! card - > ctrl ) {
st = - ENOMEM ;
goto failed_dma_setup ;
}
st = rsxx_dma_setup ( card ) ;
if ( st ) {
dev_info ( CARD_TO_DEV ( card ) ,
" Failed to setup DMA engine \n " ) ;
goto failed_dma_setup ;
}
/************* Setup Card Event Handler *************/
2013-06-18 14:34:54 -05:00
card - > event_wq = create_singlethread_workqueue ( DRIVER_NAME " _event " ) ;
if ( ! card - > event_wq ) {
dev_err ( CARD_TO_DEV ( card ) , " Failed card event setup. \n " ) ;
goto failed_event_handler ;
}
2013-02-05 14:15:02 +01:00
INIT_WORK ( & card - > event_work , card_event_handler ) ;
st = rsxx_setup_dev ( card ) ;
if ( st )
goto failed_create_dev ;
rsxx_get_card_state ( card , & card - > state ) ;
dev_info ( CARD_TO_DEV ( card ) ,
" card state: %s \n " ,
rsxx_card_state_to_str ( card - > state ) ) ;
/*
* Now that the DMA Engine and devices have been setup ,
* we can enable the event interrupt ( it kicks off actions in
* those layers so we couldn ' t enable it right away . )
*/
2013-02-18 21:35:59 +01:00
spin_lock_irq ( & card - > irq_lock ) ;
2013-02-05 14:15:02 +01:00
rsxx_enable_ier_and_isr ( card , CR_INTR_EVENT ) ;
2013-02-18 21:35:59 +01:00
spin_unlock_irq ( & card - > irq_lock ) ;
2013-02-05 14:15:02 +01:00
if ( card - > state = = CARD_STATE_SHUTDOWN ) {
st = rsxx_issue_card_cmd ( card , CARD_CMD_STARTUP ) ;
if ( st )
dev_crit ( CARD_TO_DEV ( card ) ,
" Failed issuing card startup \n " ) ;
2013-06-18 14:42:36 -05:00
if ( sync_start ) {
sync_timeout = SYNC_START_TIMEOUT ;
dev_info ( CARD_TO_DEV ( card ) ,
" Waiting for card to startup \n " ) ;
do {
ssleep ( 1 ) ;
sync_timeout - - ;
rsxx_get_card_state ( card , & card - > state ) ;
} while ( sync_timeout & &
( card - > state = = CARD_STATE_STARTING ) ) ;
if ( card - > state = = CARD_STATE_STARTING ) {
dev_warn ( CARD_TO_DEV ( card ) ,
" Card startup timed out \n " ) ;
card - > size8 = 0 ;
} else {
dev_info ( CARD_TO_DEV ( card ) ,
" card state: %s \n " ,
rsxx_card_state_to_str ( card - > state ) ) ;
st = rsxx_get_card_size8 ( card , & card - > size8 ) ;
if ( st )
card - > size8 = 0 ;
}
}
2013-02-05 14:15:02 +01:00
} else if ( card - > state = = CARD_STATE_GOOD | |
card - > state = = CARD_STATE_RD_ONLY_FAULT ) {
st = rsxx_get_card_size8 ( card , & card - > size8 ) ;
if ( st )
card - > size8 = 0 ;
}
rsxx_attach_dev ( card ) ;
2013-06-18 14:52:21 -05:00
/************* Setup Debugfs *************/
rsxx_debugfs_dev_new ( card ) ;
2013-02-05 14:15:02 +01:00
return 0 ;
failed_create_dev :
2013-06-18 14:34:54 -05:00
destroy_workqueue ( card - > event_wq ) ;
card - > event_wq = NULL ;
failed_event_handler :
2013-02-05 14:15:02 +01:00
rsxx_dma_destroy ( card ) ;
failed_dma_setup :
failed_compatiblity_check :
2013-06-18 14:34:54 -05:00
destroy_workqueue ( card - > creg_ctrl . creg_wq ) ;
card - > creg_ctrl . creg_wq = NULL ;
failed_creg_setup :
2013-02-18 21:35:59 +01:00
spin_lock_irq ( & card - > irq_lock ) ;
2013-02-05 14:15:02 +01:00
rsxx_disable_ier_and_isr ( card , CR_INTR_ALL ) ;
2013-02-18 21:35:59 +01:00
spin_unlock_irq ( & card - > irq_lock ) ;
2013-02-05 14:15:02 +01:00
free_irq ( dev - > irq , card ) ;
if ( ! force_legacy )
pci_disable_msi ( dev ) ;
failed_irq :
pci_iounmap ( dev , card - > regmap ) ;
failed_iomap :
pci_release_regions ( dev ) ;
failed_request_regions :
failed_dma_mask :
pci_disable_device ( dev ) ;
failed_enable :
2018-06-11 15:46:46 -04:00
ida_free ( & rsxx_disk_ida , card - > disk_id ) ;
2013-02-05 14:15:02 +01:00
failed_ida_get :
kfree ( card ) ;
return st ;
}
2013-02-06 14:03:13 +11:00
static void rsxx_pci_remove ( struct pci_dev * dev )
2013-02-05 14:15:02 +01:00
{
struct rsxx_cardinfo * card = pci_get_drvdata ( dev ) ;
unsigned long flags ;
int st ;
int i ;
if ( ! card )
return ;
dev_info ( CARD_TO_DEV ( card ) ,
" Removing PCI-Flash SSD. \n " ) ;
rsxx_detach_dev ( card ) ;
for ( i = 0 ; i < card - > n_targets ; i + + ) {
spin_lock_irqsave ( & card - > irq_lock , flags ) ;
rsxx_disable_ier_and_isr ( card , CR_INTR_DMA ( i ) ) ;
spin_unlock_irqrestore ( & card - > irq_lock , flags ) ;
}
st = card_shutdown ( card ) ;
if ( st )
dev_crit ( CARD_TO_DEV ( card ) , " Shutdown failed! \n " ) ;
/* Sync outstanding event handlers. */
spin_lock_irqsave ( & card - > irq_lock , flags ) ;
rsxx_disable_ier_and_isr ( card , CR_INTR_EVENT ) ;
spin_unlock_irqrestore ( & card - > irq_lock , flags ) ;
cancel_work_sync ( & card - > event_work ) ;
rsxx_destroy_dev ( card ) ;
rsxx_dma_destroy ( card ) ;
spin_lock_irqsave ( & card - > irq_lock , flags ) ;
rsxx_disable_ier_and_isr ( card , CR_INTR_ALL ) ;
spin_unlock_irqrestore ( & card - > irq_lock , flags ) ;
2013-02-25 13:09:40 -06:00
/* Prevent work_structs from re-queuing themselves. */
card - > halt = 1 ;
2013-06-18 14:52:21 -05:00
debugfs_remove_recursive ( card - > debugfs_dir ) ;
2013-02-05 14:15:02 +01:00
free_irq ( dev - > irq , card ) ;
if ( ! force_legacy )
pci_disable_msi ( dev ) ;
rsxx_creg_destroy ( card ) ;
pci_iounmap ( dev , card - > regmap ) ;
pci_disable_device ( dev ) ;
pci_release_regions ( dev ) ;
2018-06-11 15:46:46 -04:00
ida_free ( & rsxx_disk_ida , card - > disk_id ) ;
2013-02-05 14:15:02 +01:00
kfree ( card ) ;
}
static int rsxx_pci_suspend ( struct pci_dev * dev , pm_message_t state )
{
/* We don't support suspend at this time. */
return - ENOSYS ;
}
static void rsxx_pci_shutdown ( struct pci_dev * dev )
{
struct rsxx_cardinfo * card = pci_get_drvdata ( dev ) ;
unsigned long flags ;
int i ;
if ( ! card )
return ;
dev_info ( CARD_TO_DEV ( card ) , " Shutting down PCI-Flash SSD. \n " ) ;
rsxx_detach_dev ( card ) ;
for ( i = 0 ; i < card - > n_targets ; i + + ) {
spin_lock_irqsave ( & card - > irq_lock , flags ) ;
rsxx_disable_ier_and_isr ( card , CR_INTR_DMA ( i ) ) ;
spin_unlock_irqrestore ( & card - > irq_lock , flags ) ;
}
card_shutdown ( card ) ;
}
2013-03-16 08:22:25 +01:00
static const struct pci_error_handlers rsxx_err_handler = {
. error_detected = rsxx_error_detected ,
. slot_reset = rsxx_slot_reset ,
} ;
2014-08-08 15:56:03 +02:00
static const struct pci_device_id rsxx_pci_ids [ ] = {
2013-02-27 09:24:59 -06:00
{ PCI_DEVICE ( PCI_VENDOR_ID_IBM , PCI_DEVICE_ID_FS70_FLASH ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_IBM , PCI_DEVICE_ID_FS80_FLASH ) } ,
2013-02-05 14:15:02 +01:00
{ 0 , } ,
} ;
MODULE_DEVICE_TABLE ( pci , rsxx_pci_ids ) ;
static struct pci_driver rsxx_pci_driver = {
. name = DRIVER_NAME ,
. id_table = rsxx_pci_ids ,
. probe = rsxx_pci_probe ,
2013-02-06 14:03:13 +11:00
. remove = rsxx_pci_remove ,
2013-02-05 14:15:02 +01:00
. suspend = rsxx_pci_suspend ,
. shutdown = rsxx_pci_shutdown ,
2013-03-16 08:22:25 +01:00
. err_handler = & rsxx_err_handler ,
2013-02-05 14:15:02 +01:00
} ;
static int __init rsxx_core_init ( void )
{
int st ;
st = rsxx_dev_init ( ) ;
if ( st )
return st ;
st = rsxx_dma_init ( ) ;
if ( st )
goto dma_init_failed ;
st = rsxx_creg_init ( ) ;
if ( st )
goto creg_init_failed ;
return pci_register_driver ( & rsxx_pci_driver ) ;
creg_init_failed :
rsxx_dma_cleanup ( ) ;
dma_init_failed :
rsxx_dev_cleanup ( ) ;
return st ;
}
static void __exit rsxx_core_cleanup ( void )
{
pci_unregister_driver ( & rsxx_pci_driver ) ;
rsxx_creg_cleanup ( ) ;
rsxx_dma_cleanup ( ) ;
rsxx_dev_cleanup ( ) ;
}
module_init ( rsxx_core_init ) ;
module_exit ( rsxx_core_cleanup ) ;