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 .
*
2011-03-17 12:10:32 +03:00
* Copyright ( c ) 2000 - 2010 Adaptec , Inc .
* 2010 PMC - Sierra , Inc . ( aacraid @ pmc - sierra . 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 :
* comminit . c
*
* Abstract : This supports the initialization of the host adapter commuication interface .
* This is a platform dependent module for the pci cyclone board .
*
*/
# 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/completion.h>
# include <linux/mm.h>
2005-05-17 05:28:42 +04:00
# include <scsi/scsi_host.h>
2005-04-17 02:20:36 +04:00
# include "aacraid.h"
2005-08-04 02:38:51 +04:00
struct aac_common aac_config = {
. irq_mod = 1
} ;
2005-04-17 02:20:36 +04:00
static int aac_alloc_comm ( struct aac_dev * dev , void * * commaddr , unsigned long commsize , unsigned long commalign )
{
unsigned char * base ;
unsigned long size , align ;
2005-05-17 05:28:42 +04:00
const unsigned long fibsize = 4096 ;
const unsigned long printfbufsiz = 256 ;
2011-03-17 12:10:32 +03:00
unsigned long host_rrq_size = 0 ;
2005-04-17 02:20:36 +04:00
struct aac_init * init ;
dma_addr_t phys ;
2009-04-01 18:16:08 +04:00
unsigned long aac_max_hostphysmempages ;
2005-04-17 02:20:36 +04:00
2011-03-17 12:10:32 +03:00
if ( dev - > comm_interface = = AAC_COMM_MESSAGE_TYPE1 )
host_rrq_size = ( dev - > scsi_host_ptr - > can_queue
+ AAC_NUM_MGT_FIB ) * sizeof ( u32 ) ;
size = fibsize + sizeof ( struct aac_init ) + commsize +
commalign + printfbufsiz + host_rrq_size ;
2005-04-17 02:20:36 +04:00
base = pci_alloc_consistent ( dev - > pdev , size , & phys ) ;
if ( base = = NULL )
{
printk ( KERN_ERR " aacraid: unable to create mapping. \n " ) ;
return 0 ;
}
dev - > comm_addr = ( void * ) base ;
dev - > comm_phys = phys ;
dev - > comm_size = size ;
2011-03-17 12:10:32 +03:00
if ( dev - > comm_interface = = AAC_COMM_MESSAGE_TYPE1 ) {
dev - > host_rrq = ( u32 * ) ( base + fibsize ) ;
dev - > host_rrq_pa = phys + fibsize ;
memset ( dev - > host_rrq , 0 , host_rrq_size ) ;
}
dev - > init = ( struct aac_init * ) ( base + fibsize + host_rrq_size ) ;
dev - > init_pa = phys + fibsize + host_rrq_size ;
2005-04-17 02:20:36 +04:00
init = dev - > init ;
init - > InitStructRevision = cpu_to_le32 ( ADAPTER_INIT_STRUCT_REVISION ) ;
2005-05-17 05:28:42 +04:00
if ( dev - > max_fib_size ! = sizeof ( struct hw_fib ) )
init - > InitStructRevision = cpu_to_le32 ( ADAPTER_INIT_STRUCT_REVISION_4 ) ;
2005-04-17 02:20:36 +04:00
init - > MiniPortRevision = cpu_to_le32 ( Sa_MINIPORT_REVISION ) ;
init - > fsrev = cpu_to_le32 ( dev - > fsrev ) ;
/*
* Adapter Fibs are the first thing allocated so that they
* start page aligned
*/
dev - > aif_base_va = ( struct hw_fib * ) base ;
init - > AdapterFibsVirtualAddress = 0 ;
init - > AdapterFibsPhysicalAddress = cpu_to_le32 ( ( u32 ) phys ) ;
init - > AdapterFibsSize = cpu_to_le32 ( fibsize ) ;
init - > AdapterFibAlign = cpu_to_le32 ( sizeof ( struct hw_fib ) ) ;
2009-04-01 18:16:08 +04:00
/*
* number of 4 k pages of host physical memory . The aacraid fw needs
* this number to be less than 4 gb worth of pages . New firmware doesn ' t
* have any issues with the mapping system , but older Firmware did , and
* had * troubles * dealing with the math overloading past 32 bits , thus
* we must limit this field .
*/
aac_max_hostphysmempages = dma_get_required_mask ( & dev - > pdev - > dev ) > > 12 ;
if ( aac_max_hostphysmempages < AAC_MAX_HOSTPHYSMEMPAGES )
init - > HostPhysMemPages = cpu_to_le32 ( aac_max_hostphysmempages ) ;
else
init - > HostPhysMemPages = cpu_to_le32 ( AAC_MAX_HOSTPHYSMEMPAGES ) ;
2005-04-17 02:20:36 +04:00
2005-05-17 05:28:42 +04:00
init - > InitFlags = 0 ;
2007-01-24 01:59:20 +03:00
if ( dev - > comm_interface = = AAC_COMM_MESSAGE ) {
2011-03-17 12:10:32 +03:00
init - > InitFlags | = cpu_to_le32 ( INITFLAGS_NEW_COMM_SUPPORTED ) ;
2005-10-24 21:52:22 +04:00
dprintk ( ( KERN_WARNING " aacraid: New Comm Interface enabled \n " ) ) ;
2011-03-17 12:10:32 +03:00
} else if ( dev - > comm_interface = = AAC_COMM_MESSAGE_TYPE1 ) {
init - > InitStructRevision = cpu_to_le32 ( ADAPTER_INIT_STRUCT_REVISION_6 ) ;
init - > InitFlags | = cpu_to_le32 ( INITFLAGS_NEW_COMM_TYPE1_SUPPORTED ) ;
dprintk ( ( KERN_WARNING
" aacraid: New Comm Interface type1 enabled \n " ) ) ;
2005-10-24 21:52:22 +04:00
}
2008-05-01 00:03:42 +04:00
init - > InitFlags | = cpu_to_le32 ( INITFLAGS_DRIVER_USES_UTC_TIME |
INITFLAGS_DRIVER_SUPPORTS_PM ) ;
2005-05-17 05:28:42 +04:00
init - > MaxIoCommands = cpu_to_le32 ( dev - > scsi_host_ptr - > can_queue + AAC_NUM_MGT_FIB ) ;
init - > MaxIoSize = cpu_to_le32 ( dev - > scsi_host_ptr - > max_sectors < < 9 ) ;
init - > MaxFibSize = cpu_to_le32 ( dev - > max_fib_size ) ;
2005-04-17 02:20:36 +04:00
2011-03-17 12:10:32 +03:00
init - > MaxNumAif = cpu_to_le32 ( dev - > max_num_aif ) ;
init - > HostRRQ_AddrHigh = ( u32 ) ( ( u64 ) dev - > host_rrq_pa > > 32 ) ;
init - > HostRRQ_AddrLow = ( u32 ) ( dev - > host_rrq_pa & 0xffffffff ) ;
2005-04-17 02:20:36 +04:00
/*
* Increment the base address by the amount already used
*/
2011-03-17 12:10:32 +03:00
base = base + fibsize + host_rrq_size + sizeof ( struct aac_init ) ;
phys = ( dma_addr_t ) ( ( ulong ) phys + fibsize + host_rrq_size +
sizeof ( struct aac_init ) ) ;
2005-04-17 02:20:36 +04:00
/*
* Align the beginning of Headers to commalign
*/
2007-10-29 08:11:28 +03:00
align = ( commalign - ( ( uintptr_t ) ( base ) & ( commalign - 1 ) ) ) ;
2005-04-17 02:20:36 +04:00
base = base + align ;
phys = phys + align ;
/*
* Fill in addresses of the Comm Area Headers and Queues
*/
* commaddr = base ;
init - > CommHeaderAddress = cpu_to_le32 ( ( u32 ) phys ) ;
/*
* Increment the base address by the size of the CommArea
*/
base = base + commsize ;
phys = phys + commsize ;
/*
* Place the Printf buffer area after the Fast I / O comm area .
*/
dev - > printfbuf = ( void * ) base ;
init - > printfbuf = cpu_to_le32 ( phys ) ;
init - > printfbufsiz = cpu_to_le32 ( printfbufsiz ) ;
memset ( base , 0 , printfbufsiz ) ;
return 1 ;
}
static void aac_queue_init ( struct aac_dev * dev , struct aac_queue * q , u32 * mem , int qsize )
{
q - > numpending = 0 ;
q - > dev = dev ;
init_waitqueue_head ( & q - > cmdready ) ;
INIT_LIST_HEAD ( & q - > cmdq ) ;
init_waitqueue_head ( & q - > qfull ) ;
spin_lock_init ( & q - > lockdata ) ;
q - > lock = & q - > lockdata ;
2005-04-27 17:05:51 +04:00
q - > headers . producer = ( __le32 * ) mem ;
q - > headers . consumer = ( __le32 * ) ( mem + 1 ) ;
2005-04-17 02:20:36 +04:00
* ( q - > headers . producer ) = cpu_to_le32 ( qsize ) ;
* ( q - > headers . consumer ) = cpu_to_le32 ( qsize ) ;
q - > entries = qsize ;
}
/**
* aac_send_shutdown - shutdown an adapter
* @ dev : Adapter to shutdown
*
* This routine will send a VM_CloseAll ( shutdown ) request to the adapter .
*/
int aac_send_shutdown ( struct aac_dev * dev )
{
struct fib * fibctx ;
struct aac_close * cmd ;
int status ;
2006-02-01 20:30:55 +03:00
fibctx = aac_fib_alloc ( dev ) ;
2005-05-17 05:28:42 +04:00
if ( ! fibctx )
return - ENOMEM ;
2006-02-01 20:30:55 +03:00
aac_fib_init ( fibctx ) ;
2005-04-17 02:20:36 +04:00
cmd = ( struct aac_close * ) fib_data ( fibctx ) ;
cmd - > command = cpu_to_le32 ( VM_CloseAll ) ;
cmd - > cid = cpu_to_le32 ( 0xffffffff ) ;
2006-02-01 20:30:55 +03:00
status = aac_fib_send ( ContainerCommand ,
2005-04-17 02:20:36 +04:00
fibctx ,
sizeof ( struct aac_close ) ,
FsaNormal ,
2005-09-20 23:56:50 +04:00
- 2 /* Timeout silently */ , 1 ,
2005-04-17 02:20:36 +04:00
NULL , NULL ) ;
2006-08-03 19:03:07 +04:00
if ( status > = 0 )
2006-02-01 20:30:55 +03:00
aac_fib_complete ( fibctx ) ;
2009-12-21 16:09:27 +03:00
/* FIB should be freed only after getting the response from the F/W */
if ( status ! = - ERESTARTSYS )
aac_fib_free ( fibctx ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
/**
* aac_comm_init - Initialise FSA data structures
* @ dev : Adapter to initialise
*
* Initializes the data structures that are required for the FSA commuication
* interface to operate .
* Returns
* 1 - if we were able to init the commuication interface .
* 0 - If there were errors initing . This is a fatal error .
*/
2005-04-26 06:45:58 +04:00
static int aac_comm_init ( struct aac_dev * dev )
2005-04-17 02:20:36 +04:00
{
unsigned long hdrsize = ( sizeof ( u32 ) * NUMBER_OF_COMM_QUEUES ) * 2 ;
unsigned long queuesize = sizeof ( struct aac_entry ) * TOTAL_QUEUE_ENTRIES ;
u32 * headers ;
struct aac_entry * queues ;
unsigned long size ;
struct aac_queue_block * comm = dev - > queues ;
/*
* Now allocate and initialize the zone structures used as our
* pool of FIB context records . The size of the zone is based
* on the system memory size . We also initialize the mutex used
* to protect the zone .
*/
spin_lock_init ( & dev - > fib_lock ) ;
/*
tree-wide: fix assorted typos all over the place
That is "success", "unknown", "through", "performance", "[re|un]mapping"
, "access", "default", "reasonable", "[con]currently", "temperature"
, "channel", "[un]used", "application", "example","hierarchy", "therefore"
, "[over|under]flow", "contiguous", "threshold", "enough" and others.
Signed-off-by: André Goddard Rosa <andre.goddard@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
2009-11-14 18:09:05 +03:00
* Allocate the physically contiguous space for the commuication
2005-04-17 02:20:36 +04:00
* queue headers .
*/
size = hdrsize + queuesize ;
if ( ! aac_alloc_comm ( dev , ( void * * ) & headers , size , QUEUE_ALIGNMENT ) )
return - ENOMEM ;
queues = ( struct aac_entry * ) ( ( ( ulong ) headers ) + hdrsize ) ;
/* Adapter to Host normal priority Command queue */
comm - > queue [ HostNormCmdQueue ] . base = queues ;
aac_queue_init ( dev , & comm - > queue [ HostNormCmdQueue ] , headers , HOST_NORM_CMD_ENTRIES ) ;
queues + = HOST_NORM_CMD_ENTRIES ;
headers + = 2 ;
/* Adapter to Host high priority command queue */
comm - > queue [ HostHighCmdQueue ] . base = queues ;
aac_queue_init ( dev , & comm - > queue [ HostHighCmdQueue ] , headers , HOST_HIGH_CMD_ENTRIES ) ;
queues + = HOST_HIGH_CMD_ENTRIES ;
headers + = 2 ;
/* Host to adapter normal priority command queue */
comm - > queue [ AdapNormCmdQueue ] . base = queues ;
aac_queue_init ( dev , & comm - > queue [ AdapNormCmdQueue ] , headers , ADAP_NORM_CMD_ENTRIES ) ;
queues + = ADAP_NORM_CMD_ENTRIES ;
headers + = 2 ;
/* host to adapter high priority command queue */
comm - > queue [ AdapHighCmdQueue ] . base = queues ;
aac_queue_init ( dev , & comm - > queue [ AdapHighCmdQueue ] , headers , ADAP_HIGH_CMD_ENTRIES ) ;
queues + = ADAP_HIGH_CMD_ENTRIES ;
headers + = 2 ;
/* adapter to host normal priority response queue */
comm - > queue [ HostNormRespQueue ] . base = queues ;
aac_queue_init ( dev , & comm - > queue [ HostNormRespQueue ] , headers , HOST_NORM_RESP_ENTRIES ) ;
queues + = HOST_NORM_RESP_ENTRIES ;
headers + = 2 ;
/* adapter to host high priority response queue */
comm - > queue [ HostHighRespQueue ] . base = queues ;
aac_queue_init ( dev , & comm - > queue [ HostHighRespQueue ] , headers , HOST_HIGH_RESP_ENTRIES ) ;
queues + = HOST_HIGH_RESP_ENTRIES ;
headers + = 2 ;
/* host to adapter normal priority response queue */
comm - > queue [ AdapNormRespQueue ] . base = queues ;
aac_queue_init ( dev , & comm - > queue [ AdapNormRespQueue ] , headers , ADAP_NORM_RESP_ENTRIES ) ;
queues + = ADAP_NORM_RESP_ENTRIES ;
headers + = 2 ;
/* host to adapter high priority response queue */
comm - > queue [ AdapHighRespQueue ] . base = queues ;
aac_queue_init ( dev , & comm - > queue [ AdapHighRespQueue ] , headers , ADAP_HIGH_RESP_ENTRIES ) ;
comm - > queue [ AdapNormCmdQueue ] . lock = comm - > queue [ HostNormRespQueue ] . lock ;
comm - > queue [ AdapHighCmdQueue ] . lock = comm - > queue [ HostHighRespQueue ] . lock ;
comm - > queue [ AdapNormRespQueue ] . lock = comm - > queue [ HostNormCmdQueue ] . lock ;
comm - > queue [ AdapHighRespQueue ] . lock = comm - > queue [ HostHighCmdQueue ] . lock ;
return 0 ;
}
struct aac_dev * aac_init_adapter ( struct aac_dev * dev )
{
2005-05-17 05:28:42 +04:00
u32 status [ 5 ] ;
struct Scsi_Host * host = dev - > scsi_host_ptr ;
/*
* Check the preferred comm settings , defaults from template .
*/
2009-12-21 16:09:27 +03:00
dev - > management_fib_count = 0 ;
spin_lock_init ( & dev - > manage_lock ) ;
2005-05-17 05:28:42 +04:00
dev - > max_fib_size = sizeof ( struct hw_fib ) ;
dev - > sg_tablesize = host - > sg_tablesize = ( dev - > max_fib_size
- sizeof ( struct aac_fibhdr )
2005-09-20 23:57:04 +04:00
- sizeof ( struct aac_write ) + sizeof ( struct sgentry ) )
/ sizeof ( struct sgentry ) ;
2007-01-24 01:59:20 +03:00
dev - > comm_interface = AAC_COMM_PRODUCER ;
2011-03-17 12:10:32 +03:00
dev - > raw_io_interface = dev - > raw_io_64 = 0 ;
2005-09-22 20:15:24 +04:00
if ( ( ! aac_adapter_sync_cmd ( dev , GET_ADAPTER_PROPERTIES ,
0 , 0 , 0 , 0 , 0 , 0 , status + 0 , status + 1 , status + 2 , NULL , NULL ) ) & &
( status [ 0 ] = = 0x00000001 ) ) {
2008-01-08 23:48:25 +03:00
if ( status [ 1 ] & le32_to_cpu ( AAC_OPT_NEW_COMM_64 ) )
2005-09-22 20:15:24 +04:00
dev - > raw_io_64 = 1 ;
2011-03-17 12:10:32 +03:00
if ( dev - > a_ops . adapter_comm ) {
if ( status [ 1 ] & le32_to_cpu ( AAC_OPT_NEW_COMM_TYPE1 ) ) {
dev - > comm_interface = AAC_COMM_MESSAGE_TYPE1 ;
dev - > raw_io_interface = 1 ;
} else if ( status [ 1 ] & le32_to_cpu ( AAC_OPT_NEW_COMM ) ) {
dev - > comm_interface = AAC_COMM_MESSAGE ;
dev - > raw_io_interface = 1 ;
}
}
2007-01-24 01:59:20 +03:00
if ( ( dev - > comm_interface = = AAC_COMM_MESSAGE ) & &
( status [ 2 ] > dev - > base_size ) ) {
2006-09-19 20:00:02 +04:00
aac_adapter_ioremap ( dev , 0 ) ;
2005-10-24 21:52:22 +04:00
dev - > base_size = status [ 2 ] ;
2006-09-19 20:00:02 +04:00
if ( aac_adapter_ioremap ( dev , status [ 2 ] ) ) {
2005-10-24 21:52:22 +04:00
/* remap failed, go back ... */
2007-01-24 01:59:20 +03:00
dev - > comm_interface = AAC_COMM_PRODUCER ;
2006-09-19 20:00:02 +04:00
if ( aac_adapter_ioremap ( dev , AAC_MIN_FOOTPRINT_SIZE ) ) {
2005-10-24 21:52:22 +04:00
printk ( KERN_WARNING
" aacraid: unable to map adapter. \n " ) ;
return NULL ;
}
}
}
2005-09-22 20:15:24 +04:00
}
2005-05-17 05:28:42 +04:00
if ( ( ! aac_adapter_sync_cmd ( dev , GET_COMM_PREFERRED_SETTINGS ,
0 , 0 , 0 , 0 , 0 , 0 ,
status + 0 , status + 1 , status + 2 , status + 3 , status + 4 ) )
& & ( status [ 0 ] = = 0x00000001 ) ) {
/*
* status [ 1 ] > > 16 maximum command size in KB
* status [ 1 ] & 0xFFFF maximum FIB size
* status [ 2 ] > > 16 maximum SG elements to driver
* status [ 2 ] & 0xFFFF maximum SG elements from driver
* status [ 3 ] & 0xFFFF maximum number FIBs outstanding
*/
host - > max_sectors = ( status [ 1 ] > > 16 ) < < 1 ;
2011-03-17 12:10:32 +03:00
/* Multiple of 32 for PMC */
dev - > max_fib_size = status [ 1 ] & 0xFFE0 ;
2005-05-17 05:28:42 +04:00
host - > sg_tablesize = status [ 2 ] > > 16 ;
dev - > sg_tablesize = status [ 2 ] & 0xFFFF ;
host - > can_queue = ( status [ 3 ] & 0xFFFF ) - AAC_NUM_MGT_FIB ;
2011-03-17 12:10:32 +03:00
dev - > max_num_aif = status [ 4 ] & 0xFFFF ;
2005-05-17 05:28:42 +04:00
/*
* NOTE :
* All these overrides are based on a fixed internal
* knowledge and understanding of existing adapters ,
* acbsize should be set with caution .
*/
if ( acbsize = = 512 ) {
host - > max_sectors = AAC_MAX_32BIT_SGBCOUNT ;
dev - > max_fib_size = 512 ;
dev - > sg_tablesize = host - > sg_tablesize
= ( 512 - sizeof ( struct aac_fibhdr )
2005-09-20 23:57:04 +04:00
- sizeof ( struct aac_write ) + sizeof ( struct sgentry ) )
/ sizeof ( struct sgentry ) ;
2005-05-17 05:28:42 +04:00
host - > can_queue = AAC_NUM_IO_FIB ;
} else if ( acbsize = = 2048 ) {
host - > max_sectors = 512 ;
dev - > max_fib_size = 2048 ;
host - > sg_tablesize = 65 ;
dev - > sg_tablesize = 81 ;
host - > can_queue = 512 - AAC_NUM_MGT_FIB ;
} else if ( acbsize = = 4096 ) {
host - > max_sectors = 1024 ;
dev - > max_fib_size = 4096 ;
host - > sg_tablesize = 129 ;
dev - > sg_tablesize = 166 ;
host - > can_queue = 256 - AAC_NUM_MGT_FIB ;
} else if ( acbsize = = 8192 ) {
host - > max_sectors = 2048 ;
dev - > max_fib_size = 8192 ;
host - > sg_tablesize = 257 ;
dev - > sg_tablesize = 337 ;
host - > can_queue = 128 - AAC_NUM_MGT_FIB ;
} else if ( acbsize > 0 ) {
printk ( " Illegal acbsize=%d ignored \n " , acbsize ) ;
}
}
{
if ( numacb > 0 ) {
if ( numacb < host - > can_queue )
host - > can_queue = numacb ;
else
printk ( " numacb=%d ignored \n " , numacb ) ;
}
}
2005-04-17 02:20:36 +04:00
/*
* Ok now init the communication subsystem
*/
2007-04-16 19:21:50 +04:00
dev - > queues = kzalloc ( sizeof ( struct aac_queue_block ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( dev - > queues = = NULL ) {
printk ( KERN_ERR " Error could not allocate comm region. \n " ) ;
return NULL ;
}
if ( aac_comm_init ( dev ) < 0 ) {
kfree ( dev - > queues ) ;
return NULL ;
}
/*
* Initialize the list of fibs
*/
2006-02-01 20:30:55 +03:00
if ( aac_fib_setup ( dev ) < 0 ) {
2005-04-17 02:20:36 +04:00
kfree ( dev - > queues ) ;
return NULL ;
}
INIT_LIST_HEAD ( & dev - > fib_list ) ;
return dev ;
}