2005-04-17 02:20:36 +04:00
/*
* Adaptec AAC series RAID controller driver
2008-10-27 18:16:36 +03:00
* ( c ) Copyright 2001 Red Hat Inc .
2005-04-17 02:20:36 +04:00
*
* based on the old aacraid driver that is . .
* Adaptec aacraid device driver for Linux .
*
2007-03-26 17:21:14 +04:00
* Copyright ( c ) 2000 - 2007 Adaptec , Inc . ( aacraid @ adaptec . com )
2005-04-17 02:20:36 +04:00
*
* 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 , 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 ; see the file COPYING . If not , write to
* the Free Software Foundation , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
* Module Name :
* rx . c
*
* Abstract : Hardware miniport for Drawbridge specific hardware functions .
*
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/types.h>
# include <linux/pci.h>
# include <linux/spinlock.h>
# include <linux/slab.h>
# include <linux/blkdev.h>
# include <linux/delay.h>
# include <linux/completion.h>
# include <linux/time.h>
# include <linux/interrupt.h>
# include <scsi/scsi_host.h>
# include "aacraid.h"
2007-01-24 01:59:20 +03:00
static irqreturn_t aac_rx_intr_producer ( int irq , void * dev_id )
2005-04-17 02:20:36 +04:00
{
struct aac_dev * dev = dev_id ;
2007-01-24 01:59:20 +03:00
unsigned long bellbits ;
u8 intstat = rx_readb ( dev , MUnit . OISR ) ;
2005-10-24 21:52:22 +04:00
2007-01-24 01:59:20 +03:00
/*
* Read mask and invert because drawbridge is reversed .
* This allows us to only service interrupts that have
* been enabled .
* Check to see if this is our interrupt . If it isn ' t just return
*/
2007-03-26 17:21:14 +04:00
if ( likely ( intstat & ~ ( dev - > OIMR ) ) ) {
2007-01-24 01:59:20 +03:00
bellbits = rx_readl ( dev , OutboundDoorbellReg ) ;
2007-03-26 17:21:14 +04:00
if ( unlikely ( bellbits & DoorBellPrintfReady ) ) {
2007-01-24 01:59:20 +03:00
aac_printf ( dev , readl ( & dev - > IndexRegs - > Mailbox [ 5 ] ) ) ;
rx_writel ( dev , MUnit . ODR , DoorBellPrintfReady ) ;
rx_writel ( dev , InboundDoorbellReg , DoorBellPrintfDone ) ;
2005-04-17 02:20:36 +04:00
}
2007-03-26 17:21:14 +04:00
else if ( unlikely ( bellbits & DoorBellAdapterNormCmdReady ) ) {
2007-01-24 01:59:20 +03:00
rx_writel ( dev , MUnit . ODR , DoorBellAdapterNormCmdReady ) ;
aac_command_normal ( & dev - > queues - > queue [ HostNormCmdQueue ] ) ;
}
2007-03-26 17:21:14 +04:00
else if ( likely ( bellbits & DoorBellAdapterNormRespReady ) ) {
2007-01-24 01:59:20 +03:00
rx_writel ( dev , MUnit . ODR , DoorBellAdapterNormRespReady ) ;
aac_response_normal ( & dev - > queues - > queue [ HostNormRespQueue ] ) ;
}
2007-03-26 17:21:14 +04:00
else if ( unlikely ( bellbits & DoorBellAdapterNormCmdNotFull ) ) {
2007-01-24 01:59:20 +03:00
rx_writel ( dev , MUnit . ODR , DoorBellAdapterNormCmdNotFull ) ;
2005-04-17 02:20:36 +04:00
}
2007-03-26 17:21:14 +04:00
else if ( unlikely ( bellbits & DoorBellAdapterNormRespNotFull ) ) {
2007-01-24 01:59:20 +03:00
rx_writel ( dev , MUnit . ODR , DoorBellAdapterNormCmdNotFull ) ;
rx_writel ( dev , MUnit . ODR , DoorBellAdapterNormRespNotFull ) ;
}
return IRQ_HANDLED ;
}
return IRQ_NONE ;
}
static irqreturn_t aac_rx_intr_message ( int irq , void * dev_id )
{
struct aac_dev * dev = dev_id ;
u32 Index = rx_readl ( dev , MUnit . OutboundQueue ) ;
2007-03-26 17:21:14 +04:00
if ( unlikely ( Index = = 0xFFFFFFFFL ) )
2007-01-24 01:59:20 +03:00
Index = rx_readl ( dev , MUnit . OutboundQueue ) ;
2007-03-26 17:21:14 +04:00
if ( likely ( Index ! = 0xFFFFFFFFL ) ) {
2007-01-24 01:59:20 +03:00
do {
2007-03-26 17:21:14 +04:00
if ( unlikely ( aac_intr_normal ( dev , Index ) ) ) {
2007-01-24 01:59:20 +03:00
rx_writel ( dev , MUnit . OutboundQueue , Index ) ;
rx_writel ( dev , MUnit . ODR , DoorBellAdapterNormRespReady ) ;
}
Index = rx_readl ( dev , MUnit . OutboundQueue ) ;
} while ( Index ! = 0xFFFFFFFFL ) ;
return IRQ_HANDLED ;
2005-04-17 02:20:36 +04:00
}
return IRQ_NONE ;
}
2005-08-04 02:39:01 +04:00
/**
* aac_rx_disable_interrupt - Disable interrupts
* @ dev : Adapter
*/
static void aac_rx_disable_interrupt ( struct aac_dev * dev )
{
rx_writeb ( dev , MUnit . OIMR , dev - > OIMR = 0xff ) ;
}
2007-01-24 01:59:20 +03:00
/**
* aac_rx_enable_interrupt_producer - Enable interrupts
* @ dev : Adapter
*/
static void aac_rx_enable_interrupt_producer ( struct aac_dev * dev )
{
rx_writeb ( dev , MUnit . OIMR , dev - > OIMR = 0xfb ) ;
}
/**
* aac_rx_enable_interrupt_message - Enable interrupts
* @ dev : Adapter
*/
static void aac_rx_enable_interrupt_message ( struct aac_dev * dev )
{
rx_writeb ( dev , MUnit . OIMR , dev - > OIMR = 0xf7 ) ;
}
2005-04-17 02:20:36 +04:00
/**
* rx_sync_cmd - send a command and wait
* @ dev : Adapter
* @ command : Command to execute
* @ p1 : first parameter
* @ ret : adapter status
*
* This routine will send a synchronous command to the adapter and wait
* for its completion .
*/
2005-05-17 05:28:42 +04:00
static int rx_sync_cmd ( struct aac_dev * dev , u32 command ,
u32 p1 , u32 p2 , u32 p3 , u32 p4 , u32 p5 , u32 p6 ,
u32 * status , u32 * r1 , u32 * r2 , u32 * r3 , u32 * r4 )
2005-04-17 02:20:36 +04:00
{
unsigned long start ;
int ok ;
/*
* Write the command into Mailbox 0
*/
2006-09-19 20:00:02 +04:00
writel ( command , & dev - > IndexRegs - > Mailbox [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
/*
2005-05-17 05:28:42 +04:00
* Write the parameters into Mailboxes 1 - 6
2005-04-17 02:20:36 +04:00
*/
2006-09-19 20:00:02 +04:00
writel ( p1 , & dev - > IndexRegs - > Mailbox [ 1 ] ) ;
writel ( p2 , & dev - > IndexRegs - > Mailbox [ 2 ] ) ;
writel ( p3 , & dev - > IndexRegs - > Mailbox [ 3 ] ) ;
writel ( p4 , & dev - > IndexRegs - > Mailbox [ 4 ] ) ;
2005-04-17 02:20:36 +04:00
/*
* Clear the synch command doorbell to start on a clean slate .
*/
rx_writel ( dev , OutboundDoorbellReg , OUTBOUNDDOORBELL_0 ) ;
/*
* Disable doorbell interrupts
*/
2005-05-17 05:28:42 +04:00
rx_writeb ( dev , MUnit . OIMR , dev - > OIMR = 0xff ) ;
2005-04-17 02:20:36 +04:00
/*
* Force the completion of the mask register write before issuing
* the interrupt .
*/
rx_readb ( dev , MUnit . OIMR ) ;
/*
* Signal that there is a new synch command
*/
rx_writel ( dev , InboundDoorbellReg , INBOUNDDOORBELL_0 ) ;
ok = 0 ;
start = jiffies ;
/*
* Wait up to 30 seconds
*/
while ( time_before ( jiffies , start + 30 * HZ ) )
{
udelay ( 5 ) ; /* Delay 5 microseconds to let Mon960 get info. */
/*
* Mon960 will set doorbell0 bit when it has completed the command .
*/
if ( rx_readl ( dev , OutboundDoorbellReg ) & OUTBOUNDDOORBELL_0 ) {
/*
* Clear the doorbell .
*/
rx_writel ( dev , OutboundDoorbellReg , OUTBOUNDDOORBELL_0 ) ;
ok = 1 ;
break ;
}
/*
* Yield the processor in case we are slow
*/
2006-03-27 21:44:23 +04:00
msleep ( 1 ) ;
2005-04-17 02:20:36 +04:00
}
2007-03-26 17:21:14 +04:00
if ( unlikely ( ok ! = 1 ) ) {
2005-04-17 02:20:36 +04:00
/*
* Restore interrupt mask even though we timed out
*/
2007-01-24 01:59:20 +03:00
aac_adapter_enable_int ( dev ) ;
2005-04-17 02:20:36 +04:00
return - ETIMEDOUT ;
}
/*
* Pull the synch status from Mailbox 0.
*/
if ( status )
2006-09-19 20:00:02 +04:00
* status = readl ( & dev - > IndexRegs - > Mailbox [ 0 ] ) ;
2005-05-17 05:28:42 +04:00
if ( r1 )
2006-09-19 20:00:02 +04:00
* r1 = readl ( & dev - > IndexRegs - > Mailbox [ 1 ] ) ;
2005-05-17 05:28:42 +04:00
if ( r2 )
2006-09-19 20:00:02 +04:00
* r2 = readl ( & dev - > IndexRegs - > Mailbox [ 2 ] ) ;
2005-05-17 05:28:42 +04:00
if ( r3 )
2006-09-19 20:00:02 +04:00
* r3 = readl ( & dev - > IndexRegs - > Mailbox [ 3 ] ) ;
2005-05-17 05:28:42 +04:00
if ( r4 )
2006-09-19 20:00:02 +04:00
* r4 = readl ( & dev - > IndexRegs - > Mailbox [ 4 ] ) ;
2005-04-17 02:20:36 +04:00
/*
* Clear the synch command doorbell .
*/
rx_writel ( dev , OutboundDoorbellReg , OUTBOUNDDOORBELL_0 ) ;
/*
* Restore interrupt mask
*/
2007-01-24 01:59:20 +03:00
aac_adapter_enable_int ( dev ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/**
* aac_rx_interrupt_adapter - interrupt adapter
* @ dev : Adapter
*
* Send an interrupt to the i960 and breakpoint it .
*/
static void aac_rx_interrupt_adapter ( struct aac_dev * dev )
{
2005-05-17 05:28:42 +04:00
rx_sync_cmd ( dev , BREAKPOINT_REQUEST , 0 , 0 , 0 , 0 , 0 , 0 , NULL , NULL , NULL , NULL , NULL ) ;
2005-04-17 02:20:36 +04:00
}
/**
* aac_rx_notify_adapter - send an event to the adapter
* @ dev : Adapter
* @ event : Event to send
*
* Notify the i960 that something it probably cares about has
* happened .
*/
static void aac_rx_notify_adapter ( struct aac_dev * dev , u32 event )
{
switch ( event ) {
case AdapNormCmdQue :
rx_writel ( dev , MUnit . IDR , INBOUNDDOORBELL_1 ) ;
break ;
case HostNormRespNotFull :
rx_writel ( dev , MUnit . IDR , INBOUNDDOORBELL_4 ) ;
break ;
case AdapNormRespQue :
rx_writel ( dev , MUnit . IDR , INBOUNDDOORBELL_2 ) ;
break ;
case HostNormCmdNotFull :
rx_writel ( dev , MUnit . IDR , INBOUNDDOORBELL_3 ) ;
break ;
case HostShutdown :
break ;
case FastIo :
rx_writel ( dev , MUnit . IDR , INBOUNDDOORBELL_6 ) ;
break ;
case AdapPrintfDone :
rx_writel ( dev , MUnit . IDR , INBOUNDDOORBELL_5 ) ;
break ;
default :
BUG ( ) ;
break ;
}
}
/**
* aac_rx_start_adapter - activate adapter
* @ dev : Adapter
*
* Start up processing on an i960 based AAC adapter
*/
2007-03-27 09:59:35 +04:00
static void aac_rx_start_adapter ( struct aac_dev * dev )
2005-04-17 02:20:36 +04:00
{
struct aac_init * init ;
init = dev - > init ;
init - > HostElapsedSeconds = cpu_to_le32 ( get_seconds ( ) ) ;
// We can only use a 32 bit address here
2005-05-17 05:28:42 +04:00
rx_sync_cmd ( dev , INIT_STRUCT_BASE_ADDRESS , ( u32 ) ( ulong ) dev - > init_pa ,
0 , 0 , 0 , 0 , 0 , NULL , NULL , NULL , NULL , NULL ) ;
2005-04-17 02:20:36 +04:00
}
/**
* aac_rx_check_health
* @ dev : device to check if healthy
*
* Will attempt to determine if the specified adapter is alive and
* capable of handling requests , returning 0 if alive .
*/
static int aac_rx_check_health ( struct aac_dev * dev )
{
u32 status = rx_readl ( dev , MUnit . OMRx [ 0 ] ) ;
/*
* Check to see if the board failed any self tests .
*/
2007-03-26 17:21:14 +04:00
if ( unlikely ( status & SELF_TEST_FAILED ) )
2005-04-17 02:20:36 +04:00
return - 1 ;
/*
* Check to see if the board panic ' d .
*/
2007-03-26 17:21:14 +04:00
if ( unlikely ( status & KERNEL_PANIC ) ) {
2005-04-17 02:20:36 +04:00
char * buffer ;
struct POSTSTATUS {
2005-04-27 17:05:51 +04:00
__le32 Post_Command ;
__le32 Post_Address ;
2005-04-17 02:20:36 +04:00
} * post ;
dma_addr_t paddr , baddr ;
int ret ;
2007-03-26 17:21:14 +04:00
if ( likely ( ( status & 0xFF000000L ) = = 0xBC000000L ) )
2005-04-17 02:20:36 +04:00
return ( status > > 16 ) & 0xFF ;
buffer = pci_alloc_consistent ( dev - > pdev , 512 , & baddr ) ;
ret = - 2 ;
2007-03-26 17:21:14 +04:00
if ( unlikely ( buffer = = NULL ) )
2005-04-17 02:20:36 +04:00
return ret ;
post = pci_alloc_consistent ( dev - > pdev ,
sizeof ( struct POSTSTATUS ) , & paddr ) ;
2007-03-26 17:21:14 +04:00
if ( unlikely ( post = = NULL ) ) {
2005-04-17 02:20:36 +04:00
pci_free_consistent ( dev - > pdev , 512 , buffer , baddr ) ;
return ret ;
}
memset ( buffer , 0 , 512 ) ;
post - > Post_Command = cpu_to_le32 ( COMMAND_POST_RESULTS ) ;
post - > Post_Address = cpu_to_le32 ( baddr ) ;
rx_writel ( dev , MUnit . IMRx [ 0 ] , paddr ) ;
2005-05-17 05:28:42 +04:00
rx_sync_cmd ( dev , COMMAND_POST_RESULTS , baddr , 0 , 0 , 0 , 0 , 0 ,
NULL , NULL , NULL , NULL , NULL ) ;
2005-04-17 02:20:36 +04:00
pci_free_consistent ( dev - > pdev , sizeof ( struct POSTSTATUS ) ,
post , paddr ) ;
2007-03-26 17:21:14 +04:00
if ( likely ( ( buffer [ 0 ] = = ' 0 ' ) & & ( ( buffer [ 1 ] = = ' x ' ) | | ( buffer [ 1 ] = = ' X ' ) ) ) ) {
2005-04-17 02:20:36 +04:00
ret = ( buffer [ 2 ] < = ' 9 ' ) ? ( buffer [ 2 ] - ' 0 ' ) : ( buffer [ 2 ] - ' A ' + 10 ) ;
ret < < = 4 ;
ret + = ( buffer [ 3 ] < = ' 9 ' ) ? ( buffer [ 3 ] - ' 0 ' ) : ( buffer [ 3 ] - ' A ' + 10 ) ;
}
pci_free_consistent ( dev - > pdev , 512 , buffer , baddr ) ;
return ret ;
}
/*
* Wait for the adapter to be up and running .
*/
2007-03-26 17:21:14 +04:00
if ( unlikely ( ! ( status & KERNEL_UP_AND_RUNNING ) ) )
2005-04-17 02:20:36 +04:00
return - 3 ;
/*
* Everything is OK
*/
return 0 ;
}
2005-10-24 21:52:22 +04:00
/**
2007-01-24 01:59:20 +03:00
* aac_rx_deliver_producer
2005-10-24 21:52:22 +04:00
* @ fib : fib to issue
*
* Will send a fib , returning 0 if successful .
*/
2007-05-15 17:14:21 +04:00
int aac_rx_deliver_producer ( struct fib * fib )
2005-10-24 21:52:22 +04:00
{
struct aac_dev * dev = fib - > dev ;
2007-01-24 01:59:20 +03:00
struct aac_queue * q = & dev - > queues - > queue [ AdapNormCmdQueue ] ;
unsigned long qflags ;
2005-10-24 21:52:22 +04:00
u32 Index ;
2007-01-24 01:59:20 +03:00
unsigned long nointr = 0 ;
2005-10-24 21:52:22 +04:00
2007-01-24 01:59:20 +03:00
spin_lock_irqsave ( q - > lock , qflags ) ;
2007-03-15 20:26:22 +03:00
aac_queue_get ( dev , & Index , AdapNormCmdQueue , fib - > hw_fib_va , 1 , fib , & nointr ) ;
2007-01-24 01:59:20 +03:00
q - > numpending + + ;
* ( q - > headers . producer ) = cpu_to_le32 ( Index + 1 ) ;
spin_unlock_irqrestore ( q - > lock , qflags ) ;
if ( ! ( nointr & aac_config . irq_mod ) )
aac_adapter_notify ( dev , AdapNormCmdQueue ) ;
return 0 ;
}
/**
* aac_rx_deliver_message
* @ fib : fib to issue
*
* Will send a fib , returning 0 if successful .
*/
static int aac_rx_deliver_message ( struct fib * fib )
{
struct aac_dev * dev = fib - > dev ;
struct aac_queue * q = & dev - > queues - > queue [ AdapNormCmdQueue ] ;
unsigned long qflags ;
u32 Index ;
u64 addr ;
volatile void __iomem * device ;
unsigned long count = 10000000L ; /* 50 seconds */
spin_lock_irqsave ( q - > lock , qflags ) ;
q - > numpending + + ;
spin_unlock_irqrestore ( q - > lock , qflags ) ;
for ( ; ; ) {
2005-10-24 21:52:22 +04:00
Index = rx_readl ( dev , MUnit . InboundQueue ) ;
2007-03-26 17:21:14 +04:00
if ( unlikely ( Index = = 0xFFFFFFFFL ) )
2007-01-24 01:59:20 +03:00
Index = rx_readl ( dev , MUnit . InboundQueue ) ;
2007-03-26 17:21:14 +04:00
if ( likely ( Index ! = 0xFFFFFFFFL ) )
2007-01-24 01:59:20 +03:00
break ;
if ( - - count = = 0 ) {
spin_lock_irqsave ( q - > lock , qflags ) ;
q - > numpending - - ;
spin_unlock_irqrestore ( q - > lock , qflags ) ;
return - ETIMEDOUT ;
}
udelay ( 5 ) ;
}
2006-09-19 20:00:02 +04:00
device = dev - > base + Index ;
2007-01-24 01:59:20 +03:00
addr = fib - > hw_fib_pa ;
2005-10-24 21:52:22 +04:00
writel ( ( u32 ) ( addr & 0xffffffff ) , device ) ;
device + = sizeof ( u32 ) ;
writel ( ( u32 ) ( addr > > 32 ) , device ) ;
device + = sizeof ( u32 ) ;
2007-03-15 20:26:22 +03:00
writel ( le16_to_cpu ( fib - > hw_fib_va - > header . Size ) , device ) ;
2005-10-24 21:52:22 +04:00
rx_writel ( dev , MUnit . InboundQueue , Index ) ;
return 0 ;
}
2006-09-19 20:00:02 +04:00
/**
* aac_rx_ioremap
* @ size : mapping resize request
*
*/
static int aac_rx_ioremap ( struct aac_dev * dev , u32 size )
{
if ( ! size ) {
iounmap ( dev - > regs . rx ) ;
return 0 ;
}
dev - > base = dev - > regs . rx = ioremap ( dev - > scsi_host_ptr - > base , size ) ;
if ( dev - > base = = NULL )
return - 1 ;
dev - > IndexRegs = & dev - > regs . rx - > IndexRegs ;
return 0 ;
}
2007-03-15 20:26:05 +03:00
static int aac_rx_restart_adapter ( struct aac_dev * dev , int bled )
2006-08-08 19:52:14 +04:00
{
u32 var ;
2007-06-12 17:33:54 +04:00
if ( ! ( dev - > supplement_adapter_info . SupportedOptions2 &
2008-01-08 23:48:25 +03:00
AAC_OPTION_MU_RESET ) | | ( bled > = 0 ) | | ( bled = = - 2 ) ) {
2007-06-12 17:33:54 +04:00
if ( bled )
printk ( KERN_ERR " %s%d: adapter kernel panic'd %x. \n " ,
dev - > name , dev - > id , bled ) ;
else {
bled = aac_adapter_sync_cmd ( dev , IOP_RESET_ALWAYS ,
0 , 0 , 0 , 0 , 0 , 0 , & var , NULL , NULL , NULL , NULL ) ;
2007-07-27 18:29:26 +04:00
if ( ! bled & & ( var ! = 0x00000001 ) & & ( var ! = 0x3803000F ) )
2007-06-12 17:33:54 +04:00
bled = - EINVAL ;
}
if ( bled & & ( bled ! = - ETIMEDOUT ) )
bled = aac_adapter_sync_cmd ( dev , IOP_RESET ,
0 , 0 , 0 , 0 , 0 , 0 , & var , NULL , NULL , NULL , NULL ) ;
2007-03-15 20:26:05 +03:00
2007-06-12 17:33:54 +04:00
if ( bled & & ( bled ! = - ETIMEDOUT ) )
return - EINVAL ;
}
2007-03-30 18:30:48 +04:00
if ( bled | | ( var = = 0x3803000F ) ) { /* USE_OTHER_METHOD */
2007-03-15 20:26:05 +03:00
rx_writel ( dev , MUnit . reserved2 , 3 ) ;
msleep ( 5000 ) ; /* Delay 5 seconds */
var = 0x00000001 ;
}
2006-08-08 19:52:14 +04:00
if ( var ! = 0x00000001 )
2007-03-15 20:26:05 +03:00
return - EINVAL ;
2006-08-08 19:52:14 +04:00
if ( rx_readl ( dev , MUnit . OMRx [ 0 ] ) & KERNEL_PANIC )
2007-03-15 20:26:05 +03:00
return - ENODEV ;
2007-05-22 17:32:29 +04:00
if ( startup_timeout < 300 )
startup_timeout = 300 ;
2006-08-08 19:52:14 +04:00
return 0 ;
}
2007-01-24 01:59:20 +03:00
/**
* aac_rx_select_comm - Select communications method
* @ dev : Adapter
* @ comm : communications method
*/
int aac_rx_select_comm ( struct aac_dev * dev , int comm )
{
switch ( comm ) {
case AAC_COMM_PRODUCER :
dev - > a_ops . adapter_enable_int = aac_rx_enable_interrupt_producer ;
dev - > a_ops . adapter_intr = aac_rx_intr_producer ;
dev - > a_ops . adapter_deliver = aac_rx_deliver_producer ;
break ;
case AAC_COMM_MESSAGE :
dev - > a_ops . adapter_enable_int = aac_rx_enable_interrupt_message ;
dev - > a_ops . adapter_intr = aac_rx_intr_message ;
dev - > a_ops . adapter_deliver = aac_rx_deliver_message ;
break ;
default :
return 1 ;
}
return 0 ;
}
2005-04-17 02:20:36 +04:00
/**
* aac_rx_init - initialize an i960 based AAC card
* @ dev : device to configure
*
* Allocate and set up resources for the i960 based AAC variants . The
* device_interface in the commregion will be allocated and linked
* to the comm region .
*/
2006-09-19 20:00:02 +04:00
int _aac_rx_init ( struct aac_dev * dev )
2005-04-17 02:20:36 +04:00
{
unsigned long start ;
unsigned long status ;
2007-03-30 18:30:48 +04:00
int restart = 0 ;
2007-03-26 17:21:14 +04:00
int instance = dev - > id ;
const char * name = dev - > name ;
2005-04-17 02:20:36 +04:00
2006-09-19 20:00:02 +04:00
if ( aac_adapter_ioremap ( dev , dev - > base_size ) ) {
printk ( KERN_WARNING " %s: unable to map adapter. \n " , name ) ;
goto error_iounmap ;
}
2007-03-30 18:30:48 +04:00
/* Failure to reset here is an option ... */
2007-04-30 21:22:24 +04:00
dev - > a_ops . adapter_sync_cmd = rx_sync_cmd ;
dev - > a_ops . adapter_enable_int = aac_rx_disable_interrupt ;
2007-03-30 18:30:48 +04:00
dev - > OIMR = status = rx_readb ( dev , MUnit . OIMR ) ;
2007-05-22 17:32:29 +04:00
if ( ( ( ( status & 0x0c ) ! = 0x0c ) | | aac_reset_devices | | reset_devices ) & &
2007-03-30 18:30:48 +04:00
! aac_rx_restart_adapter ( dev , 0 ) )
2007-10-30 22:50:49 +03:00
/* Make sure the Hardware FIFO is empty */
while ( ( + + restart < 512 ) & &
( rx_readl ( dev , MUnit . OutboundQueue ) ! = 0xFFFFFFFFL ) ) ;
2005-04-17 02:20:36 +04:00
/*
2005-10-24 21:52:22 +04:00
* Check to see if the board panic ' d while booting .
2005-04-17 02:20:36 +04:00
*/
2006-09-19 20:00:02 +04:00
status = rx_readl ( dev , MUnit . OMRx [ 0 ] ) ;
2007-03-15 20:26:05 +03:00
if ( status & KERNEL_PANIC ) {
2007-03-30 18:30:48 +04:00
if ( aac_rx_restart_adapter ( dev , aac_rx_check_health ( dev ) ) )
2007-03-15 20:26:05 +03:00
goto error_iounmap ;
2007-03-30 18:30:48 +04:00
+ + restart ;
2007-03-15 20:26:05 +03:00
}
2005-04-17 02:20:36 +04:00
/*
* Check to see if the board failed any self tests .
*/
2006-09-19 20:00:02 +04:00
status = rx_readl ( dev , MUnit . OMRx [ 0 ] ) ;
if ( status & SELF_TEST_FAILED ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " %s%d: adapter self-test failed. \n " , dev - > name , instance ) ;
goto error_iounmap ;
}
/*
* Check to see if the monitor panic ' d while booting .
*/
2006-09-19 20:00:02 +04:00
if ( status & MONITOR_PANIC ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " %s%d: adapter monitor panic. \n " , dev - > name , instance ) ;
goto error_iounmap ;
}
start = jiffies ;
/*
* Wait for the adapter to be up and running . Wait up to 3 minutes
*/
2006-09-19 20:00:02 +04:00
while ( ! ( ( status = rx_readl ( dev , MUnit . OMRx [ 0 ] ) ) & KERNEL_UP_AND_RUNNING ) )
2005-04-17 02:20:36 +04:00
{
2007-03-30 18:30:48 +04:00
if ( ( restart & &
( status & ( KERNEL_PANIC | SELF_TEST_FAILED | MONITOR_PANIC ) ) ) | |
time_after ( jiffies , start + HZ * startup_timeout ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " %s%d: adapter kernel failed to start, init status = %lx. \n " ,
dev - > name , instance , status ) ;
goto error_iounmap ;
}
2007-03-30 18:30:48 +04:00
if ( ! restart & &
( ( status & ( KERNEL_PANIC | SELF_TEST_FAILED | MONITOR_PANIC ) ) | |
time_after ( jiffies , start + HZ *
( ( startup_timeout > 60 )
? ( startup_timeout - 60 )
: ( startup_timeout / 2 ) ) ) ) ) {
if ( likely ( ! aac_rx_restart_adapter ( dev , aac_rx_check_health ( dev ) ) ) )
start = jiffies ;
+ + restart ;
}
2006-05-10 20:12:48 +04:00
msleep ( 1 ) ;
2005-04-17 02:20:36 +04:00
}
2007-06-12 17:33:54 +04:00
if ( restart & & aac_commit )
2007-05-22 17:32:29 +04:00
aac_commit = 1 ;
2005-04-17 02:20:36 +04:00
/*
2007-01-24 01:59:20 +03:00
* Fill in the common function dispatch table .
2005-04-17 02:20:36 +04:00
*/
dev - > a_ops . adapter_interrupt = aac_rx_interrupt_adapter ;
2005-08-04 02:39:01 +04:00
dev - > a_ops . adapter_disable_int = aac_rx_disable_interrupt ;
2005-04-17 02:20:36 +04:00
dev - > a_ops . adapter_notify = aac_rx_notify_adapter ;
dev - > a_ops . adapter_sync_cmd = rx_sync_cmd ;
dev - > a_ops . adapter_check_health = aac_rx_check_health ;
2007-03-15 20:26:05 +03:00
dev - > a_ops . adapter_restart = aac_rx_restart_adapter ;
2005-04-17 02:20:36 +04:00
2005-08-04 02:39:01 +04:00
/*
* First clear out all interrupts . Then enable the one ' s that we
* can handle .
*/
2007-01-24 01:59:20 +03:00
aac_adapter_comm ( dev , AAC_COMM_PRODUCER ) ;
aac_adapter_disable_int ( dev ) ;
2005-08-04 02:39:01 +04:00
rx_writel ( dev , MUnit . ODR , 0xffffffff ) ;
2007-01-24 01:59:20 +03:00
aac_adapter_enable_int ( dev ) ;
2005-08-04 02:39:01 +04:00
2005-04-17 02:20:36 +04:00
if ( aac_init_adapter ( dev ) = = NULL )
2007-01-24 01:59:20 +03:00
goto error_iounmap ;
aac_adapter_comm ( dev , dev - > comm_interface ) ;
2008-02-08 16:48:22 +03:00
dev - > msi = aac_msi & & ! pci_enable_msi ( dev - > pdev ) ;
if ( request_irq ( dev - > pdev - > irq , dev - > a_ops . adapter_intr ,
2007-01-24 01:59:20 +03:00
IRQF_SHARED | IRQF_DISABLED , " aacraid " , dev ) < 0 ) {
2008-02-08 16:48:22 +03:00
if ( dev - > msi )
pci_disable_msi ( dev - > pdev ) ;
2007-01-24 01:59:20 +03:00
printk ( KERN_ERR " %s%d: Interrupt unavailable. \n " ,
name , instance ) ;
goto error_iounmap ;
}
aac_adapter_enable_int ( dev ) ;
/*
* Tell the adapter that all is configured , and it can
* start accepting requests
*/
aac_rx_start_adapter ( dev ) ;
2005-10-24 21:52:22 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
error_iounmap :
return - 1 ;
}
2006-09-19 20:00:02 +04:00
int aac_rx_init ( struct aac_dev * dev )
{
/*
* Fill in the function dispatch table .
*/
dev - > a_ops . adapter_ioremap = aac_rx_ioremap ;
2007-01-24 01:59:20 +03:00
dev - > a_ops . adapter_comm = aac_rx_select_comm ;
2006-09-19 20:00:02 +04:00
2007-01-24 01:59:20 +03:00
return _aac_rx_init ( dev ) ;
2006-09-19 20:00:02 +04:00
}