2006-09-19 10:28:00 -07:00
/*
* QLogic iSCSI HBA Driver
2010-12-02 22:12:51 -08:00
* Copyright ( c ) 2003 - 2010 QLogic Corporation
2006-09-19 10:28:00 -07:00
*
* See LICENSE . qla4xxx for copyright and licensing details .
*/
2007-12-13 12:43:29 -06:00
# include <scsi/iscsi_if.h>
2006-09-19 10:28:00 -07:00
# include "ql4_def.h"
2007-05-23 17:55:40 -07:00
# include "ql4_glbl.h"
# include "ql4_dbg.h"
# include "ql4_inline.h"
2006-09-19 10:28:00 -07:00
static void ql4xxx_set_mac_number ( struct scsi_qla_host * ha )
{
uint32_t value ;
uint8_t func_number ;
unsigned long flags ;
/* Get the function number */
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
value = readw ( & ha - > reg - > ctrl_status ) ;
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
func_number = ( uint8_t ) ( ( value > > 4 ) & 0x30 ) ;
switch ( value & ISP_CONTROL_FN_MASK ) {
case ISP_CONTROL_FN0_SCSI :
ha - > mac_index = 1 ;
break ;
case ISP_CONTROL_FN1_SCSI :
ha - > mac_index = 3 ;
break ;
default :
DEBUG2 ( printk ( " scsi%ld: %s: Invalid function number, "
" ispControlStatus = 0x%x \n " , ha - > host_no ,
__func__ , value ) ) ;
break ;
}
DEBUG2 ( printk ( " scsi%ld: %s: mac_index %d. \n " , ha - > host_no , __func__ ,
ha - > mac_index ) ) ;
}
/**
* qla4xxx_free_ddb - deallocate ddb
* @ ha : pointer to host adapter structure .
* @ ddb_entry : pointer to device database entry
*
2011-07-25 13:48:53 -05:00
* This routine marks a DDB entry INVALID
2006-09-19 10:28:00 -07:00
* */
2010-07-28 15:53:44 +05:30
void qla4xxx_free_ddb ( struct scsi_qla_host * ha ,
struct ddb_entry * ddb_entry )
2006-09-19 10:28:00 -07:00
{
/* Remove device pointer from index mapping arrays */
ha - > fw_ddb_index_map [ ddb_entry - > fw_ddb_index ] =
( struct ddb_entry * ) INVALID_ENTRY ;
ha - > tot_ddbs - - ;
}
2010-07-28 15:53:44 +05:30
/**
* qla4xxx_init_response_q_entries ( ) - Initializes response queue entries .
* @ ha : HA context
*
* Beginning of request ring has initialization control block already built
* by nvram config routine .
* */
static void qla4xxx_init_response_q_entries ( struct scsi_qla_host * ha )
{
uint16_t cnt ;
struct response * pkt ;
pkt = ( struct response * ) ha - > response_ptr ;
for ( cnt = 0 ; cnt < RESPONSE_QUEUE_DEPTH ; cnt + + ) {
pkt - > signature = RESPONSE_PROCESSED ;
pkt + + ;
}
}
2006-09-19 10:28:00 -07:00
/**
* qla4xxx_init_rings - initialize hw queues
* @ ha : pointer to host adapter structure .
*
* This routine initializes the internal queues for the specified adapter .
* The QLA4010 requires us to restart the queues at index 0.
* The QLA4000 doesn ' t care , so just default to QLA4010 ' s requirement .
* */
int qla4xxx_init_rings ( struct scsi_qla_host * ha )
{
unsigned long flags = 0 ;
2012-02-13 18:30:49 +05:30
int i ;
2006-09-19 10:28:00 -07:00
/* Initialize request queue. */
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
ha - > request_out = 0 ;
ha - > request_in = 0 ;
ha - > request_ptr = & ha - > request_ring [ ha - > request_in ] ;
ha - > req_q_count = REQUEST_QUEUE_DEPTH ;
/* Initialize response queue. */
ha - > response_in = 0 ;
ha - > response_out = 0 ;
ha - > response_ptr = & ha - > response_ring [ ha - > response_out ] ;
2010-07-28 15:53:44 +05:30
if ( is_qla8022 ( ha ) ) {
writel ( 0 ,
( unsigned long __iomem * ) & ha - > qla4_8xxx_reg - > req_q_out ) ;
writel ( 0 ,
( unsigned long __iomem * ) & ha - > qla4_8xxx_reg - > rsp_q_in ) ;
writel ( 0 ,
( unsigned long __iomem * ) & ha - > qla4_8xxx_reg - > rsp_q_out ) ;
} else {
/*
* Initialize DMA Shadow registers . The firmware is really
* supposed to take care of this , but on some uniprocessor
* systems , the shadow registers aren ' t cleared - - causing
* the interrupt_handler to think there are responses to be
* processed when there aren ' t .
*/
ha - > shadow_regs - > req_q_out = __constant_cpu_to_le32 ( 0 ) ;
ha - > shadow_regs - > rsp_q_in = __constant_cpu_to_le32 ( 0 ) ;
wmb ( ) ;
2006-09-19 10:28:00 -07:00
2010-07-28 15:53:44 +05:30
writel ( 0 , & ha - > reg - > req_q_in ) ;
writel ( 0 , & ha - > reg - > rsp_q_out ) ;
readl ( & ha - > reg - > rsp_q_out ) ;
}
qla4xxx_init_response_q_entries ( ha ) ;
2006-09-19 10:28:00 -07:00
2012-02-13 18:30:49 +05:30
/* Initialize mabilbox active array */
for ( i = 0 ; i < MAX_MRB ; i + + )
ha - > active_mrb_array [ i ] = NULL ;
2006-09-19 10:28:00 -07:00
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
return QLA_SUCCESS ;
}
/**
2010-07-28 15:53:44 +05:30
* qla4xxx_get_sys_info - validate adapter MAC address ( es )
2006-09-19 10:28:00 -07:00
* @ ha : pointer to host adapter structure .
*
* */
2010-07-28 15:53:44 +05:30
int qla4xxx_get_sys_info ( struct scsi_qla_host * ha )
2006-09-19 10:28:00 -07:00
{
struct flash_sys_info * sys_info ;
dma_addr_t sys_info_dma ;
int status = QLA_ERROR ;
sys_info = dma_alloc_coherent ( & ha - > pdev - > dev , sizeof ( * sys_info ) ,
& sys_info_dma , GFP_KERNEL ) ;
if ( sys_info = = NULL ) {
DEBUG2 ( printk ( " scsi%ld: %s: Unable to allocate dma buffer. \n " ,
ha - > host_no , __func__ ) ) ;
2010-07-28 15:53:44 +05:30
goto exit_get_sys_info_no_free ;
2006-09-19 10:28:00 -07:00
}
memset ( sys_info , 0 , sizeof ( * sys_info ) ) ;
/* Get flash sys info */
if ( qla4xxx_get_flash ( ha , sys_info_dma , FLASH_OFFSET_SYS_INFO ,
sizeof ( * sys_info ) ) ! = QLA_SUCCESS ) {
DEBUG2 ( printk ( " scsi%ld: %s: get_flash FLASH_OFFSET_SYS_INFO "
" failed \n " , ha - > host_no , __func__ ) ) ;
2010-07-28 15:53:44 +05:30
goto exit_get_sys_info ;
2006-09-19 10:28:00 -07:00
}
/* Save M.A.C. address & serial_number */
memcpy ( ha - > my_mac , & sys_info - > physAddr [ 0 ] . address [ 0 ] ,
min ( sizeof ( ha - > my_mac ) ,
sizeof ( sys_info - > physAddr [ 0 ] . address ) ) ) ;
memcpy ( ha - > serial_number , & sys_info - > acSerialNumber ,
min ( sizeof ( ha - > serial_number ) ,
sizeof ( sys_info - > acSerialNumber ) ) ) ;
status = QLA_SUCCESS ;
2010-07-28 15:53:44 +05:30
exit_get_sys_info :
2006-09-19 10:28:00 -07:00
dma_free_coherent ( & ha - > pdev - > dev , sizeof ( * sys_info ) , sys_info ,
sys_info_dma ) ;
2010-07-28 15:53:44 +05:30
exit_get_sys_info_no_free :
2006-09-19 10:28:00 -07:00
return status ;
}
/**
* qla4xxx_init_local_data - initialize adapter specific local data
* @ ha : pointer to host adapter structure .
*
* */
static int qla4xxx_init_local_data ( struct scsi_qla_host * ha )
{
2010-06-11 12:17:00 +02:00
/* Initialize aen queue */
2006-09-19 10:28:00 -07:00
ha - > aen_q_count = MAX_AEN_ENTRIES ;
return qla4xxx_get_firmware_status ( ha ) ;
}
2010-04-28 11:37:07 +05:30
static uint8_t
qla4xxx_wait_for_ip_config ( struct scsi_qla_host * ha )
{
uint8_t ipv4_wait = 0 ;
uint8_t ipv6_wait = 0 ;
int8_t ip_address [ IPv6_ADDR_LEN ] = { 0 } ;
/* If both IPv4 & IPv6 are enabled, possibly only one
* IP address may be acquired , so check to see if we
* need to wait for another */
if ( is_ipv4_enabled ( ha ) & & is_ipv6_enabled ( ha ) ) {
if ( ( ( ha - > addl_fw_state & FW_ADDSTATE_DHCPv4_ENABLED ) ! = 0 ) & &
( ( ha - > addl_fw_state &
FW_ADDSTATE_DHCPv4_LEASE_ACQUIRED ) = = 0 ) ) {
ipv4_wait = 1 ;
}
2011-07-25 13:48:39 -05:00
if ( ( ( ha - > ip_config . ipv6_addl_options &
IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE ) ! = 0 ) & &
( ( ha - > ip_config . ipv6_link_local_state = =
IP_ADDRSTATE_ACQUIRING ) | |
( ha - > ip_config . ipv6_addr0_state = =
IP_ADDRSTATE_ACQUIRING ) | |
( ha - > ip_config . ipv6_addr1_state = =
IP_ADDRSTATE_ACQUIRING ) ) ) {
2010-04-28 11:37:07 +05:30
ipv6_wait = 1 ;
2011-07-25 13:48:39 -05:00
if ( ( ha - > ip_config . ipv6_link_local_state = =
IP_ADDRSTATE_PREFERRED ) | |
( ha - > ip_config . ipv6_addr0_state = =
IP_ADDRSTATE_PREFERRED ) | |
( ha - > ip_config . ipv6_addr1_state = =
IP_ADDRSTATE_PREFERRED ) ) {
2010-04-28 11:37:07 +05:30
DEBUG2 ( printk ( KERN_INFO " scsi%ld: %s: "
" Preferred IP configured. "
" Don't wait! \n " , ha - > host_no ,
__func__ ) ) ;
ipv6_wait = 0 ;
}
2011-07-25 13:48:39 -05:00
if ( memcmp ( & ha - > ip_config . ipv6_default_router_addr ,
ip_address , IPv6_ADDR_LEN ) = = 0 ) {
2010-04-28 11:37:07 +05:30
DEBUG2 ( printk ( KERN_INFO " scsi%ld: %s: "
" No Router configured. "
" Don't wait! \n " , ha - > host_no ,
__func__ ) ) ;
ipv6_wait = 0 ;
}
2011-07-25 13:48:39 -05:00
if ( ( ha - > ip_config . ipv6_default_router_state = =
IPV6_RTRSTATE_MANUAL ) & &
( ha - > ip_config . ipv6_link_local_state = =
IP_ADDRSTATE_TENTATIVE ) & &
( memcmp ( & ha - > ip_config . ipv6_link_local_addr ,
& ha - > ip_config . ipv6_default_router_addr , 4 ) = =
0 ) ) {
2010-04-28 11:37:07 +05:30
DEBUG2 ( printk ( " scsi%ld: %s: LinkLocal Router & "
" IP configured. Don't wait! \n " ,
ha - > host_no , __func__ ) ) ;
ipv6_wait = 0 ;
}
}
if ( ipv4_wait | | ipv6_wait ) {
DEBUG2 ( printk ( " scsi%ld: %s: Wait for additional "
" IP(s) \" " , ha - > host_no , __func__ ) ) ;
if ( ipv4_wait )
DEBUG2 ( printk ( " IPv4 " ) ) ;
2011-07-25 13:48:39 -05:00
if ( ha - > ip_config . ipv6_link_local_state = =
IP_ADDRSTATE_ACQUIRING )
2010-04-28 11:37:07 +05:30
DEBUG2 ( printk ( " IPv6LinkLocal " ) ) ;
2011-07-25 13:48:39 -05:00
if ( ha - > ip_config . ipv6_addr0_state = =
IP_ADDRSTATE_ACQUIRING )
2010-04-28 11:37:07 +05:30
DEBUG2 ( printk ( " IPv6Addr0 " ) ) ;
2011-07-25 13:48:39 -05:00
if ( ha - > ip_config . ipv6_addr1_state = =
IP_ADDRSTATE_ACQUIRING )
2010-04-28 11:37:07 +05:30
DEBUG2 ( printk ( " IPv6Addr1 " ) ) ;
DEBUG2 ( printk ( " \" \n " ) ) ;
}
}
return ipv4_wait | ipv6_wait ;
}
2006-09-19 10:28:00 -07:00
static int qla4xxx_fw_ready ( struct scsi_qla_host * ha )
{
uint32_t timeout_count ;
int ready = 0 ;
2010-07-10 14:51:02 +05:30
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Waiting for Firmware Ready.. \n " ) ) ;
2006-09-19 10:28:00 -07:00
for ( timeout_count = ADAPTER_INIT_TOV ; timeout_count > 0 ;
timeout_count - - ) {
if ( test_and_clear_bit ( DPC_GET_DHCP_IP_ADDR , & ha - > dpc_flags ) )
qla4xxx_get_dhcp_ip_address ( ha ) ;
/* Get firmware state. */
if ( qla4xxx_get_firmware_state ( ha ) ! = QLA_SUCCESS ) {
DEBUG2 ( printk ( " scsi%ld: %s: unable to get firmware "
" state \n " , ha - > host_no , __func__ ) ) ;
break ;
}
if ( ha - > firmware_state & FW_STATE_ERROR ) {
DEBUG2 ( printk ( " scsi%ld: %s: an unrecoverable error has "
" occurred \n " , ha - > host_no , __func__ ) ) ;
break ;
}
if ( ha - > firmware_state & FW_STATE_CONFIG_WAIT ) {
/*
* The firmware has not yet been issued an Initialize
* Firmware command , so issue it now .
*/
if ( qla4xxx_initialize_fw_cb ( ha ) = = QLA_ERROR )
break ;
/* Go back and test for ready state - no wait. */
continue ;
}
2010-04-28 11:37:07 +05:30
if ( ha - > firmware_state & FW_STATE_WAIT_AUTOCONNECT ) {
DEBUG2 ( printk ( KERN_INFO " scsi%ld: %s: fwstate: "
" AUTOCONNECT in progress \n " ,
ha - > host_no , __func__ ) ) ;
}
if ( ha - > firmware_state & FW_STATE_CONFIGURING_IP ) {
DEBUG2 ( printk ( KERN_INFO " scsi%ld: %s: fwstate: "
" CONFIGURING IP \n " ,
ha - > host_no , __func__ ) ) ;
/*
* Check for link state after 15 secs and if link is
* still DOWN then , cable is unplugged . Ignore " DHCP
* in Progress / CONFIGURING IP " bit to check if firmware
* is in ready state or not after 15 secs .
* This is applicable for both 2. x & 3. x firmware
*/
if ( timeout_count < = ( ADAPTER_INIT_TOV - 15 ) ) {
if ( ha - > addl_fw_state & FW_ADDSTATE_LINK_UP ) {
DEBUG2 ( printk ( KERN_INFO " scsi%ld: %s: "
" LINK UP (Cable plugged) \n " ,
ha - > host_no , __func__ ) ) ;
} else if ( ha - > firmware_state &
( FW_STATE_CONFIGURING_IP |
FW_STATE_READY ) ) {
DEBUG2 ( printk ( KERN_INFO " scsi%ld: %s: "
" LINK DOWN (Cable unplugged) \n " ,
ha - > host_no , __func__ ) ) ;
ha - > firmware_state = FW_STATE_READY ;
}
}
}
2006-09-19 10:28:00 -07:00
if ( ha - > firmware_state = = FW_STATE_READY ) {
2010-04-28 11:37:07 +05:30
/* If DHCP IP Addr is available, retrieve it now. */
if ( test_and_clear_bit ( DPC_GET_DHCP_IP_ADDR ,
& ha - > dpc_flags ) )
qla4xxx_get_dhcp_ip_address ( ha ) ;
if ( ! qla4xxx_wait_for_ip_config ( ha ) | |
timeout_count = = 1 ) {
2010-07-10 14:51:02 +05:30
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" Firmware Ready.. \n " ) ) ;
2010-04-28 11:37:07 +05:30
/* The firmware is ready to process SCSI
commands . */
2010-07-10 14:51:02 +05:30
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
2010-04-28 11:37:07 +05:30
" scsi%ld: %s: MEDIA TYPE "
" - %s \n " , ha - > host_no ,
__func__ , ( ha - > addl_fw_state &
FW_ADDSTATE_OPTICAL_MEDIA )
! = 0 ? " OPTICAL " : " COPPER " ) ) ;
2010-07-10 14:51:02 +05:30
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
2010-04-28 11:37:07 +05:30
" scsi%ld: %s: DHCPv4 STATE "
" Enabled %s \n " , ha - > host_no ,
__func__ , ( ha - > addl_fw_state &
FW_ADDSTATE_DHCPv4_ENABLED ) ! = 0 ?
" YES " : " NO " ) ) ;
2010-07-10 14:51:02 +05:30
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
2010-04-28 11:37:07 +05:30
" scsi%ld: %s: LINK %s \n " ,
ha - > host_no , __func__ ,
( ha - > addl_fw_state &
FW_ADDSTATE_LINK_UP ) ! = 0 ?
" UP " : " DOWN " ) ) ;
2010-07-10 14:51:02 +05:30
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
2010-04-28 11:37:07 +05:30
" scsi%ld: %s: iSNS Service "
" Started %s \n " ,
ha - > host_no , __func__ ,
( ha - > addl_fw_state &
FW_ADDSTATE_ISNS_SVC_ENABLED ) ! = 0 ?
" YES " : " NO " ) ) ;
ready = 1 ;
break ;
}
2006-09-19 10:28:00 -07:00
}
DEBUG2 ( printk ( " scsi%ld: %s: waiting on fw, state=%x:%x - "
" seconds expired= %d \n " , ha - > host_no , __func__ ,
ha - > firmware_state , ha - > addl_fw_state ,
timeout_count ) ) ;
2006-11-15 17:38:40 -08:00
if ( is_qla4032 ( ha ) & &
! ( ha - > addl_fw_state & FW_ADDSTATE_LINK_UP ) & &
( timeout_count < ADAPTER_INIT_TOV - 5 ) ) {
break ;
}
2006-09-19 10:28:00 -07:00
msleep ( 1000 ) ;
} /* end of for */
2010-04-28 11:37:07 +05:30
if ( timeout_count < = 0 )
2006-09-19 10:28:00 -07:00
DEBUG2 ( printk ( " scsi%ld: %s: FW Initialization timed out! \n " ,
ha - > host_no , __func__ ) ) ;
2010-04-28 11:37:07 +05:30
if ( ha - > firmware_state & FW_STATE_CONFIGURING_IP ) {
DEBUG2 ( printk ( " scsi%ld: %s: FW initialized, but is reporting "
" it's waiting to configure an IP address \n " ,
ha - > host_no , __func__ ) ) ;
2006-09-19 10:28:00 -07:00
ready = 1 ;
2010-04-28 11:37:07 +05:30
} else if ( ha - > firmware_state & FW_STATE_WAIT_AUTOCONNECT ) {
DEBUG2 ( printk ( " scsi%ld: %s: FW initialized, but "
" auto-discovery still in process \n " ,
ha - > host_no , __func__ ) ) ;
2010-07-10 14:49:19 +05:30
ready = 1 ;
2006-09-19 10:28:00 -07:00
}
return ready ;
}
/**
* qla4xxx_init_firmware - initializes the firmware .
* @ ha : pointer to host adapter structure .
*
* */
static int qla4xxx_init_firmware ( struct scsi_qla_host * ha )
{
int status = QLA_ERROR ;
2010-07-30 14:38:47 +05:30
if ( is_aer_supported ( ha ) & &
test_bit ( AF_PCI_CHANNEL_IO_PERM_FAILURE , & ha - > flags ) )
return status ;
2010-07-30 14:26:31 +05:30
/* For 82xx, stop firmware before initializing because if BIOS
* has previously initialized firmware , then driver ' s initialize
* firmware will fail . */
if ( is_qla8022 ( ha ) )
qla4_8xxx_stop_firmware ( ha ) ;
2010-07-10 14:51:02 +05:30
ql4_printk ( KERN_INFO , ha , " Initializing firmware.. \n " ) ;
2006-09-19 10:28:00 -07:00
if ( qla4xxx_initialize_fw_cb ( ha ) = = QLA_ERROR ) {
DEBUG2 ( printk ( " scsi%ld: %s: Failed to initialize firmware "
" control block \n " , ha - > host_no , __func__ ) ) ;
return status ;
}
if ( ! qla4xxx_fw_ready ( ha ) )
return status ;
return qla4xxx_get_firmware_status ( ha ) ;
}
2011-08-01 03:26:17 -07:00
static void qla4xxx_set_model_info ( struct scsi_qla_host * ha )
{
uint16_t board_id_string [ 8 ] ;
int i ;
int size = sizeof ( ha - > nvram - > isp4022 . boardIdStr ) ;
int offset = offsetof ( struct eeprom_data , isp4022 . boardIdStr ) / 2 ;
for ( i = 0 ; i < ( size / 2 ) ; i + + ) {
board_id_string [ i ] = rd_nvram_word ( ha , offset ) ;
offset + = 1 ;
}
memcpy ( ha - > model_name , board_id_string , size ) ;
}
2006-09-19 10:28:00 -07:00
static int qla4xxx_config_nvram ( struct scsi_qla_host * ha )
{
unsigned long flags ;
union external_hw_config_reg extHwConfig ;
DEBUG2 ( printk ( " scsi%ld: %s: Get EEProm parameters \n " , ha - > host_no ,
__func__ ) ) ;
if ( ql4xxx_lock_flash ( ha ) ! = QLA_SUCCESS )
2010-02-10 16:51:48 -06:00
return QLA_ERROR ;
2006-09-19 10:28:00 -07:00
if ( ql4xxx_lock_nvram ( ha ) ! = QLA_SUCCESS ) {
ql4xxx_unlock_flash ( ha ) ;
2010-02-10 16:51:48 -06:00
return QLA_ERROR ;
2006-09-19 10:28:00 -07:00
}
/* Get EEPRom Parameters from NVRAM and validate */
2010-07-10 14:51:02 +05:30
ql4_printk ( KERN_INFO , ha , " Configuring NVRAM ... \n " ) ;
2006-09-19 10:28:00 -07:00
if ( qla4xxx_is_nvram_configuration_valid ( ha ) = = QLA_SUCCESS ) {
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
extHwConfig . Asuint32_t =
rd_nvram_word ( ha , eeprom_ext_hw_conf_offset ( ha ) ) ;
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
} else {
2010-07-10 14:51:02 +05:30
ql4_printk ( KERN_WARNING , ha ,
" scsi%ld: %s: EEProm checksum invalid. "
" Please update your EEPROM \n " , ha - > host_no ,
__func__ ) ;
2006-09-19 10:28:00 -07:00
2010-02-10 16:51:48 -06:00
/* Attempt to set defaults */
2006-09-19 10:28:00 -07:00
if ( is_qla4010 ( ha ) )
extHwConfig . Asuint32_t = 0x1912 ;
2006-11-15 17:38:40 -08:00
else if ( is_qla4022 ( ha ) | is_qla4032 ( ha ) )
2006-09-19 10:28:00 -07:00
extHwConfig . Asuint32_t = 0x0023 ;
2010-02-10 16:51:48 -06:00
else
return QLA_ERROR ;
2006-09-19 10:28:00 -07:00
}
2011-08-01 03:26:17 -07:00
if ( is_qla4022 ( ha ) | | is_qla4032 ( ha ) )
qla4xxx_set_model_info ( ha ) ;
else
strcpy ( ha - > model_name , " QLA4010 " ) ;
2006-09-19 10:28:00 -07:00
DEBUG ( printk ( " scsi%ld: %s: Setting extHwConfig to 0xFFFF%04x \n " ,
ha - > host_no , __func__ , extHwConfig . Asuint32_t ) ) ;
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
writel ( ( 0xFFFF < < 16 ) | extHwConfig . Asuint32_t , isp_ext_hw_conf ( ha ) ) ;
readl ( isp_ext_hw_conf ( ha ) ) ;
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
ql4xxx_unlock_nvram ( ha ) ;
ql4xxx_unlock_flash ( ha ) ;
2010-02-10 16:51:48 -06:00
return QLA_SUCCESS ;
2006-09-19 10:28:00 -07:00
}
2010-07-28 15:53:44 +05:30
/**
* qla4_8xxx_pci_config ( ) - Setup ISP82xx PCI configuration registers .
* @ ha : HA context
*/
void qla4_8xxx_pci_config ( struct scsi_qla_host * ha )
{
pci_set_master ( ha - > pdev ) ;
}
void qla4xxx_pci_config ( struct scsi_qla_host * ha )
2006-09-19 10:28:00 -07:00
{
2007-05-23 17:55:40 -07:00
uint16_t w ;
2007-06-08 17:37:16 -07:00
int status ;
2006-09-19 10:28:00 -07:00
2010-07-10 14:51:02 +05:30
ql4_printk ( KERN_INFO , ha , " Configuring PCI space... \n " ) ;
2006-09-19 10:28:00 -07:00
pci_set_master ( ha - > pdev ) ;
2007-06-08 17:37:16 -07:00
status = pci_set_mwi ( ha - > pdev ) ;
2006-09-19 10:28:00 -07:00
/*
* We want to respect framework ' s setting of PCI configuration space
* command register and also want to make sure that all bits of
* interest to us are properly set in command register .
*/
pci_read_config_word ( ha - > pdev , PCI_COMMAND , & w ) ;
2007-05-23 17:55:40 -07:00
w | = PCI_COMMAND_PARITY | PCI_COMMAND_SERR ;
2006-09-19 10:28:00 -07:00
w & = ~ PCI_COMMAND_INTX_DISABLE ;
pci_write_config_word ( ha - > pdev , PCI_COMMAND , w ) ;
}
static int qla4xxx_start_firmware_from_flash ( struct scsi_qla_host * ha )
{
int status = QLA_ERROR ;
2010-04-28 11:40:37 +05:30
unsigned long max_wait_time ;
2006-09-19 10:28:00 -07:00
unsigned long flags ;
uint32_t mbox_status ;
2010-07-10 14:51:02 +05:30
ql4_printk ( KERN_INFO , ha , " Starting firmware ... \n " ) ;
2006-09-19 10:28:00 -07:00
/*
* Start firmware from flash ROM
*
* WORKAROUND : Stuff a non - constant value that the firmware can
* use as a seed for a random number generator in MB7 prior to
* setting BOOT_ENABLE . Fixes problem where the TCP
* connections use the same TCP ports after each reboot ,
* causing some connections to not get re - established .
*/
DEBUG ( printk ( " scsi%d: %s: Start firmware from flash ROM \n " ,
ha - > host_no , __func__ ) ) ;
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
writel ( jiffies , & ha - > reg - > mailbox [ 7 ] ) ;
2006-11-15 17:38:40 -08:00
if ( is_qla4022 ( ha ) | is_qla4032 ( ha ) )
2006-09-19 10:28:00 -07:00
writel ( set_rmask ( NVR_WRITE_ENABLE ) ,
& ha - > reg - > u1 . isp4022 . nvram ) ;
2007-05-23 17:55:40 -07:00
writel ( 2 , & ha - > reg - > mailbox [ 6 ] ) ;
readl ( & ha - > reg - > mailbox [ 6 ] ) ;
2006-09-19 10:28:00 -07:00
writel ( set_rmask ( CSR_BOOT_ENABLE ) , & ha - > reg - > ctrl_status ) ;
readl ( & ha - > reg - > ctrl_status ) ;
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
/* Wait for firmware to come UP. */
2010-04-28 11:40:37 +05:30
DEBUG2 ( printk ( KERN_INFO " scsi%ld: %s: Wait up to %d seconds for "
" boot firmware to complete... \n " ,
ha - > host_no , __func__ , FIRMWARE_UP_TOV ) ) ;
max_wait_time = jiffies + ( FIRMWARE_UP_TOV * HZ ) ;
2006-09-19 10:28:00 -07:00
do {
uint32_t ctrl_status ;
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
ctrl_status = readw ( & ha - > reg - > ctrl_status ) ;
mbox_status = readw ( & ha - > reg - > mailbox [ 0 ] ) ;
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
if ( ctrl_status & set_rmask ( CSR_SCSI_PROCESSOR_INTR ) )
break ;
if ( mbox_status = = MBOX_STS_COMMAND_COMPLETE )
break ;
2010-04-28 11:40:37 +05:30
DEBUG2 ( printk ( KERN_INFO " scsi%ld: %s: Waiting for boot "
2010-10-06 22:47:48 -07:00
" firmware to complete... ctrl_sts=0x%x, remaining=%ld \n " ,
ha - > host_no , __func__ , ctrl_status , max_wait_time ) ) ;
2006-09-19 10:28:00 -07:00
2010-04-28 11:40:37 +05:30
msleep_interruptible ( 250 ) ;
} while ( ! time_after_eq ( jiffies , max_wait_time ) ) ;
2006-09-19 10:28:00 -07:00
if ( mbox_status = = MBOX_STS_COMMAND_COMPLETE ) {
2010-04-28 11:40:37 +05:30
DEBUG ( printk ( KERN_INFO " scsi%ld: %s: Firmware has started \n " ,
2006-09-19 10:28:00 -07:00
ha - > host_no , __func__ ) ) ;
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
writel ( set_rmask ( CSR_SCSI_PROCESSOR_INTR ) ,
& ha - > reg - > ctrl_status ) ;
readl ( & ha - > reg - > ctrl_status ) ;
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
status = QLA_SUCCESS ;
} else {
printk ( KERN_INFO " scsi%ld: %s: Boot firmware failed "
" - mbox status 0x%x \n " , ha - > host_no , __func__ ,
mbox_status ) ;
status = QLA_ERROR ;
}
return status ;
}
2007-05-23 17:55:40 -07:00
int ql4xxx_lock_drvr_wait ( struct scsi_qla_host * a )
2006-09-19 10:28:00 -07:00
{
2007-05-23 17:55:40 -07:00
# define QL4_LOCK_DRVR_WAIT 60
2007-01-22 12:26:11 -08:00
# define QL4_LOCK_DRVR_SLEEP 1
2006-09-19 10:28:00 -07:00
int drvr_wait = QL4_LOCK_DRVR_WAIT ;
while ( drvr_wait ) {
2007-05-23 17:55:40 -07:00
if ( ql4xxx_lock_drvr ( a ) = = 0 ) {
2007-01-22 12:26:11 -08:00
ssleep ( QL4_LOCK_DRVR_SLEEP ) ;
2006-09-19 10:28:00 -07:00
if ( drvr_wait ) {
DEBUG2 ( printk ( " scsi%ld: %s: Waiting for "
2007-05-23 17:55:40 -07:00
" Global Init Semaphore(%d)... \n " ,
a - > host_no ,
2007-01-22 12:26:11 -08:00
__func__ , drvr_wait ) ) ;
2006-09-19 10:28:00 -07:00
}
drvr_wait - = QL4_LOCK_DRVR_SLEEP ;
} else {
DEBUG2 ( printk ( " scsi%ld: %s: Global Init Semaphore "
2007-05-23 17:55:40 -07:00
" acquired \n " , a - > host_no , __func__ ) ) ;
2006-09-19 10:28:00 -07:00
return QLA_SUCCESS ;
}
}
return QLA_ERROR ;
}
/**
* qla4xxx_start_firmware - starts qla4xxx firmware
* @ ha : Pointer to host adapter structure .
*
2007-10-19 23:10:43 +02:00
* This routine performs the necessary steps to start the firmware for
2006-09-19 10:28:00 -07:00
* the QLA4010 adapter .
* */
2010-07-28 15:53:44 +05:30
int qla4xxx_start_firmware ( struct scsi_qla_host * ha )
2006-09-19 10:28:00 -07:00
{
unsigned long flags = 0 ;
uint32_t mbox_status ;
int status = QLA_ERROR ;
int soft_reset = 1 ;
int config_chip = 0 ;
2006-11-15 17:38:40 -08:00
if ( is_qla4022 ( ha ) | is_qla4032 ( ha ) )
2006-09-19 10:28:00 -07:00
ql4xxx_set_mac_number ( ha ) ;
if ( ql4xxx_lock_drvr_wait ( ha ) ! = QLA_SUCCESS )
return QLA_ERROR ;
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
DEBUG2 ( printk ( " scsi%ld: %s: port_ctrl = 0x%08X \n " , ha - > host_no ,
__func__ , readw ( isp_port_ctrl ( ha ) ) ) ) ;
DEBUG ( printk ( " scsi%ld: %s: port_status = 0x%08X \n " , ha - > host_no ,
__func__ , readw ( isp_port_status ( ha ) ) ) ) ;
/* Is Hardware already initialized? */
if ( ( readw ( isp_port_ctrl ( ha ) ) & 0x8000 ) ! = 0 ) {
DEBUG ( printk ( " scsi%ld: %s: Hardware has already been "
" initialized \n " , ha - > host_no , __func__ ) ) ;
/* Receive firmware boot acknowledgement */
mbox_status = readw ( & ha - > reg - > mailbox [ 0 ] ) ;
DEBUG2 ( printk ( " scsi%ld: %s: H/W Config complete - mbox[0]= "
" 0x%x \n " , ha - > host_no , __func__ , mbox_status ) ) ;
/* Is firmware already booted? */
if ( mbox_status = = 0 ) {
/* F/W not running, must be config by net driver */
config_chip = 1 ;
soft_reset = 0 ;
} else {
writel ( set_rmask ( CSR_SCSI_PROCESSOR_INTR ) ,
& ha - > reg - > ctrl_status ) ;
readl ( & ha - > reg - > ctrl_status ) ;
2012-01-11 02:44:18 -08:00
writel ( set_rmask ( CSR_SCSI_COMPLETION_INTR ) ,
& ha - > reg - > ctrl_status ) ;
readl ( & ha - > reg - > ctrl_status ) ;
2006-09-19 10:28:00 -07:00
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
if ( qla4xxx_get_firmware_state ( ha ) = = QLA_SUCCESS ) {
DEBUG2 ( printk ( " scsi%ld: %s: Get firmware "
" state -- state = 0x%x \n " ,
ha - > host_no ,
__func__ , ha - > firmware_state ) ) ;
/* F/W is running */
if ( ha - > firmware_state &
FW_STATE_CONFIG_WAIT ) {
DEBUG2 ( printk ( " scsi%ld: %s: Firmware "
" in known state -- "
" config and "
" boot, state = 0x%x \n " ,
ha - > host_no , __func__ ,
ha - > firmware_state ) ) ;
config_chip = 1 ;
soft_reset = 0 ;
}
} else {
DEBUG2 ( printk ( " scsi%ld: %s: Firmware in "
" unknown state -- resetting, "
" state = "
" 0x%x \n " , ha - > host_no , __func__ ,
ha - > firmware_state ) ) ;
}
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
}
} else {
DEBUG ( printk ( " scsi%ld: %s: H/W initialization hasn't been "
" started - resetting \n " , ha - > host_no , __func__ ) ) ;
}
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
DEBUG ( printk ( " scsi%ld: %s: Flags soft_rest=%d, config= %d \n " ,
ha - > host_no , __func__ , soft_reset , config_chip ) ) ;
if ( soft_reset ) {
DEBUG ( printk ( " scsi%ld: %s: Issue Soft Reset \n " , ha - > host_no ,
__func__ ) ) ;
2010-07-28 15:53:44 +05:30
status = qla4xxx_soft_reset ( ha ) ; /* NOTE: acquires drvr
* lock again , but ok */
2006-09-19 10:28:00 -07:00
if ( status = = QLA_ERROR ) {
DEBUG ( printk ( " scsi%d: %s: Soft Reset failed! \n " ,
ha - > host_no , __func__ ) ) ;
ql4xxx_unlock_drvr ( ha ) ;
return QLA_ERROR ;
}
config_chip = 1 ;
2008-02-03 17:28:22 +02:00
/* Reset clears the semaphore, so acquire again */
2006-09-19 10:28:00 -07:00
if ( ql4xxx_lock_drvr_wait ( ha ) ! = QLA_SUCCESS )
return QLA_ERROR ;
}
if ( config_chip ) {
if ( ( status = qla4xxx_config_nvram ( ha ) ) = = QLA_SUCCESS )
status = qla4xxx_start_firmware_from_flash ( ha ) ;
}
ql4xxx_unlock_drvr ( ha ) ;
if ( status = = QLA_SUCCESS ) {
if ( test_and_clear_bit ( AF_GET_CRASH_RECORD , & ha - > flags ) )
qla4xxx_get_crash_record ( ha ) ;
} else {
DEBUG ( printk ( " scsi%ld: %s: Firmware has NOT started \n " ,
ha - > host_no , __func__ ) ) ;
}
return status ;
}
2011-10-07 16:55:45 -07:00
/**
* qla4xxx_free_ddb_index - Free DDBs reserved by firmware
* @ ha : pointer to adapter structure
*
* Since firmware is not running in autoconnect mode the DDB indices should
* be freed so that when login happens from user space there are free DDB
* indices available .
* */
2011-12-01 21:38:41 -06:00
void qla4xxx_free_ddb_index ( struct scsi_qla_host * ha )
2011-10-07 16:55:45 -07:00
{
int max_ddbs ;
int ret ;
uint32_t idx = 0 , next_idx = 0 ;
uint32_t state = 0 , conn_err = 0 ;
2011-12-01 21:38:41 -06:00
max_ddbs = is_qla40XX ( ha ) ? MAX_DEV_DB_ENTRIES_40XX :
2011-10-07 16:55:45 -07:00
MAX_DEV_DB_ENTRIES ;
for ( idx = 0 ; idx < max_ddbs ; idx = next_idx ) {
ret = qla4xxx_get_fwddb_entry ( ha , idx , NULL , 0 , NULL ,
& next_idx , & state , & conn_err ,
NULL , NULL ) ;
[SCSI] qla4xxx: a small loop fix
When the qla4xxx_get_fwddb_entry returns QLA_ERROR
the nex_idx is not updated,
for (idx = 0; idx < max_ddbs; idx = next_idx) {
ret = qla4xxx_get_fwddb_entry(ha, idx, NULL, 0, NULL,
&next_idx, &state, &conn_err,
NULL, NULL);
if (ret == QLA_ERROR)
continue;
This means there is a risk that the 'idx < max_ddbs' condition will never
met and the loop will loop forever.
Fix this by explicitly increasing the next_idx in the error condition.
Maybe a break instead of continue is more appropriate, leaving the decision
on the qlogic maintainer.
Signed-off-by: Tomas Henzl <thenzl@redhat.com>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2011-12-01 21:38:42 -06:00
if ( ret = = QLA_ERROR ) {
next_idx + + ;
2011-10-07 16:55:45 -07:00
continue ;
[SCSI] qla4xxx: a small loop fix
When the qla4xxx_get_fwddb_entry returns QLA_ERROR
the nex_idx is not updated,
for (idx = 0; idx < max_ddbs; idx = next_idx) {
ret = qla4xxx_get_fwddb_entry(ha, idx, NULL, 0, NULL,
&next_idx, &state, &conn_err,
NULL, NULL);
if (ret == QLA_ERROR)
continue;
This means there is a risk that the 'idx < max_ddbs' condition will never
met and the loop will loop forever.
Fix this by explicitly increasing the next_idx in the error condition.
Maybe a break instead of continue is more appropriate, leaving the decision
on the qlogic maintainer.
Signed-off-by: Tomas Henzl <thenzl@redhat.com>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2011-12-01 21:38:42 -06:00
}
2011-10-07 16:55:45 -07:00
if ( state = = DDB_DS_NO_CONNECTION_ACTIVE | |
state = = DDB_DS_SESSION_FAILED ) {
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" Freeing DDB index = 0x%x \n " , idx ) ) ;
ret = qla4xxx_clear_ddb_entry ( ha , idx ) ;
if ( ret = = QLA_ERROR )
ql4_printk ( KERN_ERR , ha ,
" Unable to clear DDB index = "
" 0x%x \n " , idx ) ;
}
if ( next_idx = = 0 )
break ;
}
}
2006-09-19 10:28:00 -07:00
/**
* qla4xxx_initialize_adapter - initiailizes hba
* @ ha : Pointer to host adapter structure .
*
* This routine parforms all of the steps necessary to initialize the adapter .
*
* */
2011-12-01 21:38:41 -06:00
int qla4xxx_initialize_adapter ( struct scsi_qla_host * ha , int is_reset )
2006-09-19 10:28:00 -07:00
{
int status = QLA_ERROR ;
ha - > eeprom_cmd_data = 0 ;
2010-07-28 15:53:44 +05:30
ql4_printk ( KERN_INFO , ha , " Configuring PCI space... \n " ) ;
ha - > isp_ops - > pci_config ( ha ) ;
2006-09-19 10:28:00 -07:00
2010-07-28 15:53:44 +05:30
ha - > isp_ops - > disable_intrs ( ha ) ;
2006-09-19 10:28:00 -07:00
/* Initialize the Host adapter request/response queues and firmware */
2010-07-28 15:53:44 +05:30
if ( ha - > isp_ops - > start_firmware ( ha ) = = QLA_ERROR )
goto exit_init_hba ;
2011-05-17 23:17:11 -07:00
if ( qla4xxx_about_firmware ( ha ) = = QLA_ERROR )
2007-06-08 17:37:16 -07:00
goto exit_init_hba ;
2006-09-19 10:28:00 -07:00
2010-07-28 15:53:44 +05:30
if ( ha - > isp_ops - > get_sys_info ( ha ) = = QLA_ERROR )
2007-06-08 17:37:16 -07:00
goto exit_init_hba ;
2006-09-19 10:28:00 -07:00
if ( qla4xxx_init_local_data ( ha ) = = QLA_ERROR )
2007-06-08 17:37:16 -07:00
goto exit_init_hba ;
2006-09-19 10:28:00 -07:00
status = qla4xxx_init_firmware ( ha ) ;
if ( status = = QLA_ERROR )
2007-06-08 17:37:16 -07:00
goto exit_init_hba ;
2006-09-19 10:28:00 -07:00
2011-12-01 21:38:41 -06:00
if ( is_reset = = RESET_ADAPTER )
qla4xxx_build_ddb_list ( ha , is_reset ) ;
2011-10-07 16:55:45 -07:00
2007-05-23 17:55:40 -07:00
set_bit ( AF_ONLINE , & ha - > flags ) ;
2007-06-08 17:37:16 -07:00
exit_init_hba :
2010-10-06 22:49:08 -07:00
if ( is_qla8022 ( ha ) & & ( status = = QLA_ERROR ) ) {
/* Since interrupts are registered in start_firmware for
* 82 xx , release them here if initialize_adapter fails */
qla4xxx_free_irqs ( ha ) ;
}
2010-07-28 15:53:44 +05:30
DEBUG2 ( printk ( " scsi%ld: initialize adapter: %s \n " , ha - > host_no ,
2011-03-30 22:57:33 -03:00
status = = QLA_ERROR ? " FAILED " : " SUCCEEDED " ) ) ;
2006-09-19 10:28:00 -07:00
return status ;
}
2011-12-01 21:38:41 -06:00
int qla4xxx_ddb_change ( struct scsi_qla_host * ha , uint32_t fw_ddb_index ,
struct ddb_entry * ddb_entry , uint32_t state )
2006-09-19 10:28:00 -07:00
{
2011-07-25 13:48:53 -05:00
uint32_t old_fw_ddb_device_state ;
int status = QLA_ERROR ;
2006-09-19 10:28:00 -07:00
2011-07-25 13:48:53 -05:00
old_fw_ddb_device_state = ddb_entry - > fw_ddb_device_state ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" %s: DDB - old state = 0x%x, new state = 0x%x for "
" index [%d] \n " , __func__ ,
ddb_entry - > fw_ddb_device_state , state , fw_ddb_index ) ) ;
2006-09-19 10:28:00 -07:00
ddb_entry - > fw_ddb_device_state = state ;
2010-04-28 11:38:11 +05:30
2011-07-25 13:48:53 -05:00
switch ( old_fw_ddb_device_state ) {
case DDB_DS_LOGIN_IN_PROCESS :
switch ( state ) {
case DDB_DS_SESSION_ACTIVE :
case DDB_DS_DISCOVERY :
2011-12-01 21:38:41 -06:00
ddb_entry - > unblock_sess ( ddb_entry - > sess ) ;
2011-07-25 13:48:53 -05:00
qla4xxx_update_session_conn_param ( ha , ddb_entry ) ;
status = QLA_SUCCESS ;
break ;
case DDB_DS_SESSION_FAILED :
case DDB_DS_NO_CONNECTION_ACTIVE :
iscsi_conn_login_event ( ddb_entry - > conn ,
ISCSI_CONN_STATE_FREE ) ;
status = QLA_SUCCESS ;
break ;
}
break ;
case DDB_DS_SESSION_ACTIVE :
2011-10-07 16:55:46 -07:00
switch ( state ) {
case DDB_DS_SESSION_FAILED :
2006-09-19 10:28:00 -07:00
/*
2011-07-25 13:48:53 -05:00
* iscsi_session failure will cause userspace to
* stop the connection which in turn would block the
* iscsi_session and start relogin
2006-09-19 10:28:00 -07:00
*/
2011-07-25 13:48:53 -05:00
iscsi_session_failure ( ddb_entry - > sess - > dd_data ,
ISCSI_ERR_CONN_FAILED ) ;
status = QLA_SUCCESS ;
2011-10-07 16:55:46 -07:00
break ;
case DDB_DS_NO_CONNECTION_ACTIVE :
clear_bit ( fw_ddb_index , ha - > ddb_idx_map ) ;
status = QLA_SUCCESS ;
break ;
2006-09-19 10:28:00 -07:00
}
2011-07-25 13:48:53 -05:00
break ;
2011-10-07 16:55:47 -07:00
case DDB_DS_SESSION_FAILED :
switch ( state ) {
case DDB_DS_SESSION_ACTIVE :
case DDB_DS_DISCOVERY :
2011-12-01 21:38:41 -06:00
ddb_entry - > unblock_sess ( ddb_entry - > sess ) ;
2011-10-07 16:55:47 -07:00
qla4xxx_update_session_conn_param ( ha , ddb_entry ) ;
status = QLA_SUCCESS ;
break ;
case DDB_DS_SESSION_FAILED :
iscsi_session_failure ( ddb_entry - > sess - > dd_data ,
ISCSI_ERR_CONN_FAILED ) ;
status = QLA_SUCCESS ;
break ;
}
break ;
2011-07-25 13:48:53 -05:00
default :
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " %s: Unknown Event \n " ,
__func__ ) ) ;
break ;
2006-09-19 10:28:00 -07:00
}
2011-12-01 21:38:41 -06:00
return status ;
}
void qla4xxx_arm_relogin_timer ( struct ddb_entry * ddb_entry )
{
/*
* This triggers a relogin . After the relogin_timer
* expires , the relogin gets scheduled . We must wait a
* minimum amount of time since receiving an 0x8014 AEN
* with failed device_state or a logout response before
* we can issue another relogin .
*
* Firmware pads this timeout : ( time2wait + 1 ) .
* Driver retry to login should be longer than F / W .
* Otherwise F / W will fail
* set_ddb ( ) mbx cmd with 0x4005 since it still
* counting down its time2wait .
*/
atomic_set ( & ddb_entry - > relogin_timer , 0 ) ;
atomic_set ( & ddb_entry - > retry_relogin_timer ,
ddb_entry - > default_time2wait + 4 ) ;
}
int qla4xxx_flash_ddb_change ( struct scsi_qla_host * ha , uint32_t fw_ddb_index ,
struct ddb_entry * ddb_entry , uint32_t state )
{
uint32_t old_fw_ddb_device_state ;
int status = QLA_ERROR ;
old_fw_ddb_device_state = ddb_entry - > fw_ddb_device_state ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" %s: DDB - old state = 0x%x, new state = 0x%x for "
" index [%d] \n " , __func__ ,
ddb_entry - > fw_ddb_device_state , state , fw_ddb_index ) ) ;
ddb_entry - > fw_ddb_device_state = state ;
switch ( old_fw_ddb_device_state ) {
case DDB_DS_LOGIN_IN_PROCESS :
case DDB_DS_NO_CONNECTION_ACTIVE :
switch ( state ) {
case DDB_DS_SESSION_ACTIVE :
ddb_entry - > unblock_sess ( ddb_entry - > sess ) ;
qla4xxx_update_session_conn_fwddb_param ( ha , ddb_entry ) ;
status = QLA_SUCCESS ;
break ;
case DDB_DS_SESSION_FAILED :
iscsi_block_session ( ddb_entry - > sess ) ;
if ( ! test_bit ( DF_RELOGIN , & ddb_entry - > flags ) )
qla4xxx_arm_relogin_timer ( ddb_entry ) ;
status = QLA_SUCCESS ;
break ;
}
break ;
case DDB_DS_SESSION_ACTIVE :
switch ( state ) {
case DDB_DS_SESSION_FAILED :
iscsi_block_session ( ddb_entry - > sess ) ;
if ( ! test_bit ( DF_RELOGIN , & ddb_entry - > flags ) )
qla4xxx_arm_relogin_timer ( ddb_entry ) ;
status = QLA_SUCCESS ;
break ;
}
break ;
case DDB_DS_SESSION_FAILED :
switch ( state ) {
case DDB_DS_SESSION_ACTIVE :
ddb_entry - > unblock_sess ( ddb_entry - > sess ) ;
qla4xxx_update_session_conn_fwddb_param ( ha , ddb_entry ) ;
status = QLA_SUCCESS ;
break ;
case DDB_DS_SESSION_FAILED :
if ( ! test_bit ( DF_RELOGIN , & ddb_entry - > flags ) )
qla4xxx_arm_relogin_timer ( ddb_entry ) ;
status = QLA_SUCCESS ;
break ;
}
break ;
default :
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " %s: Unknown Event \n " ,
__func__ ) ) ;
break ;
}
return status ;
}
/**
* qla4xxx_process_ddb_changed - process ddb state change
* @ ha - Pointer to host adapter structure .
* @ fw_ddb_index - Firmware ' s device database index
* @ state - Device state
*
* This routine processes a Decive Database Changed AEN Event .
* */
int qla4xxx_process_ddb_changed ( struct scsi_qla_host * ha ,
uint32_t fw_ddb_index ,
uint32_t state , uint32_t conn_err )
{
struct ddb_entry * ddb_entry ;
int status = QLA_ERROR ;
/* check for out of range index */
if ( fw_ddb_index > = MAX_DDB_ENTRIES )
goto exit_ddb_event ;
/* Get the corresponging ddb entry */
ddb_entry = qla4xxx_lookup_ddb_by_fw_index ( ha , fw_ddb_index ) ;
/* Device does not currently exist in our database. */
if ( ddb_entry = = NULL ) {
ql4_printk ( KERN_ERR , ha , " %s: No ddb_entry at FW index [%d] \n " ,
__func__ , fw_ddb_index ) ;
if ( state = = DDB_DS_NO_CONNECTION_ACTIVE )
clear_bit ( fw_ddb_index , ha - > ddb_idx_map ) ;
goto exit_ddb_event ;
}
ddb_entry - > ddb_change ( ha , fw_ddb_index , ddb_entry , state ) ;
2011-07-25 13:48:53 -05:00
exit_ddb_event :
return status ;
2006-09-19 10:28:00 -07:00
}
2011-12-01 21:38:41 -06:00
/**
* qla4xxx_login_flash_ddb - Login to target ( DDB )
* @ cls_session : Pointer to the session to login
*
* This routine logins to the target .
* Issues setddb and conn open mbx
* */
void qla4xxx_login_flash_ddb ( struct iscsi_cls_session * cls_session )
{
struct iscsi_session * sess ;
struct ddb_entry * ddb_entry ;
struct scsi_qla_host * ha ;
struct dev_db_entry * fw_ddb_entry = NULL ;
dma_addr_t fw_ddb_dma ;
uint32_t mbx_sts = 0 ;
int ret ;
sess = cls_session - > dd_data ;
ddb_entry = sess - > dd_data ;
ha = ddb_entry - > ha ;
if ( ! test_bit ( AF_LINK_UP , & ha - > flags ) )
return ;
if ( ddb_entry - > ddb_type ! = FLASH_DDB ) {
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" Skipping login to non FLASH DB " ) ) ;
goto exit_login ;
}
fw_ddb_entry = dma_pool_alloc ( ha - > fw_ddb_dma_pool , GFP_KERNEL ,
& fw_ddb_dma ) ;
if ( fw_ddb_entry = = NULL ) {
DEBUG2 ( ql4_printk ( KERN_ERR , ha , " Out of memory \n " ) ) ;
goto exit_login ;
}
if ( ddb_entry - > fw_ddb_index = = INVALID_ENTRY ) {
ret = qla4xxx_get_ddb_index ( ha , & ddb_entry - > fw_ddb_index ) ;
if ( ret = = QLA_ERROR )
goto exit_login ;
ha - > fw_ddb_index_map [ ddb_entry - > fw_ddb_index ] = ddb_entry ;
ha - > tot_ddbs + + ;
}
memcpy ( fw_ddb_entry , & ddb_entry - > fw_ddb_entry ,
sizeof ( struct dev_db_entry ) ) ;
ddb_entry - > sess - > target_id = ddb_entry - > fw_ddb_index ;
ret = qla4xxx_set_ddb_entry ( ha , ddb_entry - > fw_ddb_index ,
fw_ddb_dma , & mbx_sts ) ;
if ( ret = = QLA_ERROR ) {
DEBUG2 ( ql4_printk ( KERN_ERR , ha , " Set DDB failed \n " ) ) ;
goto exit_login ;
}
ddb_entry - > fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS ;
ret = qla4xxx_conn_open ( ha , ddb_entry - > fw_ddb_index ) ;
if ( ret = = QLA_ERROR ) {
ql4_printk ( KERN_ERR , ha , " %s: Login failed: %s \n " , __func__ ,
sess - > targetname ) ;
goto exit_login ;
}
exit_login :
if ( fw_ddb_entry )
dma_pool_free ( ha - > fw_ddb_dma_pool , fw_ddb_entry , fw_ddb_dma ) ;
}